draggable如何snap到新创建的元素上?

我使用jqui中的draggable小部件。

我希望当我的draggable元素拖拽到某个区域后,能产生一个新元素“#block”,并且这个新元素能够被draggable的"snap"所识别

我的代码如下:

$("#ball").draggable({
    refreshPositions:true,
    snap:"#block",
    statr: function(event,ui) {
        //创建#block元素的函数
        createBlock()
    }
})

我发现#block元素能够正确被创建,并且没有任何拼写错误,但是"#ball"元素仍然无法识别#block元素,也无法吸附上去。我尝试使用refreshPoistion:true来更新draggable元素,但这没有效果。

我应该怎么解决这个问题,或者说,我能通过其他方法来完成我的需求吗?谢谢你的建议和回答!

阅读 512
avatarAI BotBETA

看起来您正在尝试使用 jQuery UI 的 draggable 组件,并希望在拖动一个元素时,让其根据新创建的元素进行吸附。根据您提供的代码,您已经在 draggable 初始化函数中指定了 snap 参数为 "#block",但发现无法正常工作。

首先,snap 参数的工作原理是,它会在元素拖动时,根据设定的其他元素(这里应该是 "#block")进行吸附。所以问题可能出在 "#block" 元素的创建时间和位置上。

这里有几个需要注意的点:

  1. Snap 的元素需要存在:Snap 插件会在页面加载时获取所有指定的元素,因此新创建的元素可能无法立即被识别。您需要在页面加载后,当新元素已经存在时,再去初始化 draggable。
  2. RefreshPositions 参数:这个参数确实可以用来在拖动后更新 snap 元素的坐标,但是如果这些元素是在 draggable 初始化之后才添加到 DOM 中的,那么这个参数可能无法工作。
  3. Snap 的大小:如果新创建的元素 "#block" 太小,或者它不在 draggable 元素的视口范围内,那么 snap 功能可能无法正常工作。

为了解决这个问题,您可以尝试以下方案:

  1. 确保 Snap 元素在 draggable 初始化前已经存在:将新元素的创建逻辑放在 draggable 初始化之前,或者在 draggable 的 stop 事件中触发新元素的创建。
  2. 使用延迟初始化:如果您无法保证元素在 draggable 初始化时已经存在,那么可以尝试在 draggable 初始化后,等待一段时间再去创建新元素。
  3. 手动触发吸附:在创建新元素后,可以尝试手动触发 draggable 的吸附。这可以通过调用 $(".draggable").draggable("option","snap"); 来实现。

这是一个例子代码:

$("#ball").draggable({
    refreshPositions: true,
    start: function(event, ui) {
        // Create #block element after the draggable is initialized
        setTimeout(function() {
            createBlock();
        }, 100); // Delay the creation of #block element for 100ms after the draggable is initialized
    },
    snap: "#block"
});

在这个例子中,我使用了 setTimeout 来延迟创建 "#block" 元素,确保 draggable 在开始拖动前已经存在。

这只是一个可能的解决方案,实际情况可能因为您的页面和代码而有所不同。如果这个建议不能解决您的问题,或者您有其他信息可以提供,我会很高兴再次为您提供帮助。

1 个回答

遗憾的是,我最终也没能实现这个功能,我想,这可能与draggable元素的snap的判定有关,或许修改jquery-ui的源文件能解决这个问题,很可惜,我没有这样的能力。

我换用了另一种方式来实现这个功能,他看起来有着与snap一样的外表,或许能够一定程度上解决和我遭遇了同样问题的人:

这分为两部分,我将draggable元素命名为“#ball”,snap元素命名为“#block”
在#block上,我进行了这样的设置:

$("#block").droppable({
    tolerance: "pointer",
    accept:"#ball",
    //球的圆心在鼠标的位置,所以我使用了pointer,当鼠标进入block时,球的圆心也进入了block
    over:function(event,ui){
        event.stopPropagation()
        //通过修改snapping变量令ball的drag事件停止
        snapping = true
        //获取block的中心,这里的block是一个圆形
        var radius = $(this).width()/2
        var x = $(this).offset().left + radius
        var y = $(this).offset().top + radius
        //将ball的圆心移动到这里来
        $(ui.draggable).offset({
            left: x - ball的半径,
            top: y - ball的半径
        })

    },
    drop:function(event,ui){
        console.log("球放进了篮子里")
    },
    //当鼠标移出block时
    out:function(event,ui){
        event.stopPropagation()
        //令drag事件重启
        snapping = false
        //将ball移动到鼠标的位置来
        $(ui.draggable).offset({
            left: event.clientX,
            top: event.clientY
        })
    }
})

另一边,我同样对#ball的draggable进行了设置:

    $("#ball").draggable({
    //我的block是一个在ball开始移动后才创建的对象,也正是因此snap无法起效,这里需要给ball设置refreshPositions:true,才能检测到新创建的block对象
    refreshPositions:true,
    //以snapping变量限制drag行动
    drag: function(event,ui) {
        if(snapping != false){
            draggingBall(this)
        }
        else{
            //在此时,ball的拖拽事件将不会发生
            return 0;
        }

    },
    stop: function(){
        console.log("已经结束了!")
    }
})

需要提及的是,在我的程序中,ball的移动是借由helper产生,而非ball本身进行的移动,因此,这个代码可能不会在任何情况有效,但我希望它能够作为一种参考

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题