单击其中一个子元素时如何防止选择 SortableJS 项目?

How to prevent selection of a SortableJS item when clicking on one of its child elements?

问题

我正在使用 SortableJS 构建一个可拖动的树组件。这意味着我的每个 sortable-item 都有一个 toggle-arrow 作为打开和关闭 sub-tree(如果有的话)的子元素。

我正在尝试使用 stopPropagation() 来防止在单击 toggle-arrow 时选择父 sortable-item,但它不起作用。

关闭后是这样的:

打开时看起来像这样:

您在打开状态(第二张图片)中看到的蓝色突出显示是我在使用 multiDrag 插件时为 selectedClass 选项选择的样式。

这说明当我单击 toggle-arrow 时,它会导致选择父 sortable-item

我不希望发生这种情况。

代码

我的 SortableJS 树组件中的项目代码如下所示(使用 Vue.js 和 Pug 语法):

div.sortable-item
    div.content
        div.toggle-arrow(@click.stop="toggleTree($event)")
        div.icon
        div.title
    div.sub-tree

然后我在 toggle-arrow 元素上得到了 @click 绑定的处理程序:

toggleTree = function($event) {
    $event.stopPropagation()
    /// Code for handling the sub-tree toggling goes here.
    /// The sub-tree toggling itself works just fine.
}

您可以看到我将 @click.stop 声明为事件绑定,这应该会阻止 click 事件从 toggle-arrow 子元素冒泡,但它不起作用.

我什至试图在处理程序中使用 $event.stopPropagation。但是,事件似乎继续冒泡,因此父 sortable-item 元素最终处于选中状态。

我也曾尝试将 @click.native.stop 声明为事件绑定,但它只是阻止了我的 toggleTree 方法的触发。我假设 SortableJS 中某处有另一个事件处理程序干扰了 @click.native.stop 绑定。

问题

  1. 如何在单击我的 sortable-item 的子元素时停止传播事件?

  2. multiDrag 插件如何处理选择?我仔细研究了代码,看到了 sortable-itemthe select event is fired within the handler of the drop event,但我对此感到困惑。为什么 drop 事件处理程序用于切换 sortable-item 的选择?

在此先感谢您提供的任何信息。

错误事件

查看SortableJS的源码,好像你要停止冒泡的事件不是click事件,而是mouseup事件。



"Stuck"拖动项目问题

如该答案的评论中所示,停止对 mouseup 事件的传播会导致无意中开始拖动,并且 sortable-item 变为指向指针的 "stuck" .

似乎 "drag initiation" 是由 pointerdownmousedowntouchstart 事件触发的,具体取决于设备。

可以安全地假设 pointerdown 事件是触发 according to caniuse.com 的事件。



解决方案

所以解决这个问题的实际方法是使用 @pointerdown.stop 事件绑定来触发您的 toggleTree 方法,而不触发 sortable-item 的选择或无意的拖动启动。

div.sortable-item
    div.content
        div.toggle-arrow(@pointerdown.stop="toggleTree($event)")
        div.icon
        div.title
    div.sub-tree

改变

div.toggle-arrow(@click.stop="toggleTree($event)")

div.toggle-arrow(@click.native.stop="toggleTree($event)")

如果您在 toggleTree 中所做的只是 stopPropagation,您可以将其更改为:

div.toggle-arrow(@click.native.stop)

Docs.

简而言之,您当前正在停止传播来自子组件的任何发出的点击(a.k.a。自定义 Vue 事件,实际上不需要停止传播,因为它默认情况下不冒泡) .您要做的是在本机 click 事件上调用 event.stopPropagation()
另一种方法是使用:

div.toggle-arrow(@click.native="toggleTree($event)")

...并在 toggleTree 中调用 .stopPropagation()。这正是 .stop 修饰符的作用。