You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

如何点击SortableJS子元素时避免选中父级sortable-item?

解决SortableJS + multiDrag的事件冒泡与选中问题

我之前也遇到过类似的坑,核心原因其实是你阻止的事件不对——SortableJS(包括multiDrag插件)触发选中/拖拽逻辑的时机是mousedown(移动端是touchstart)事件,而不是你现在处理的click事件。所以你在click上做的stopPropagation完全管不到multiDrag的选中逻辑,这才导致父元素依然会被选中。

下面给你两个靠谱的解决方案,以及针对你疑问的详细解答:

解决方案1:用Sortable官方的Filter配置(推荐)

Sortable本身提供了filter选项,专门用来指定哪些元素不会触发拖拽/选中行为,这是最优雅的解决方式,不需要手动处理事件冒泡:

在初始化Sortable的时候,添加filter配置:

// 假设你在Vue的mounted钩子中初始化Sortable
mounted() {
  this.sortableInstance = new Sortable(this.$el.querySelector('.sortable-container'), {
    multiDrag: true,
    selectedClass: 'selected', // 你的高亮类
    filter: '.toggle-arrow', // 指定要过滤的元素选择器
    // 可选:如果需要过滤后做些操作,可以加onFilter回调
    onFilter: (evt) => {
      // 这里可以什么都不做,我们只需要让Sortable忽略.toggle-arrow的事件
    },
    // 其他Sortable配置...
  })
}

这样设置后,点击.toggle-arrow时,Sortable会直接忽略这个元素的事件,既不会触发选中,也不会影响你自己的toggleTree方法执行。

解决方案2:阻止mousedown事件冒泡

如果你不想用filter,也可以直接阻止.toggle-arrowmousedown事件冒泡(这才是Sortable监听的核心事件):

修改你的Pug模板:

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

这里的@mousedown.stop.prevent会直接阻止事件冒泡到父元素,同时阻止默认行为,这样Sortable就检测不到这个mousedown事件,自然不会触发选中逻辑。

如果需要在mousedown时做额外处理,也可以绑定一个函数:

handleToggleMouseDown = function($event) {
  $event.stopPropagation()
  $event.preventDefault()
}

然后模板里写@mousedown="handleToggleMouseDown"


针对你疑问的解答

1. 点击sortable-item的子元素时,如何阻止事件传播?

关键点是找对Sortable监听的事件类型:Sortable的拖拽、选中逻辑都是基于mousedown/touchstart事件触发的,不是click。所以你需要阻止的是这些事件的冒泡,而不是click事件。

推荐用上面的方案1(Sortable filter),因为这是官方提供的标准化解决方案,不需要自己处理事件流的细节;如果必须手动处理,就针对mousedown/touchstart做阻止冒泡。

2. multiDrag插件的选择机制是怎样的?为何select事件在drop事件处理程序中触发?

  • multiDrag的选择机制
    multiDrag主要通过监听mousedown事件实现选中逻辑:

    • 点击未选中的sortable-item(非过滤元素):添加选中类;
    • 按住Ctrl/Command点击:切换元素的选中状态;
    • 拖拽时可以通过框选(按住鼠标拖动)或拖拽已选中元素,批量选中多个元素;
    • 选中状态会同步保存到插件的selected数组中。
  • select事件在drop时触发的原因
    当你拖拽选中的元素完成drop后,multiDrag需要确认元素的选中状态——比如拖拽后元素位置变化,插件需要确保选中集合仍然准确,或者当你拖拽多个元素时,drop后要同步更新选中的DOM元素引用。因此插件会在drop事件的处理流程中触发select事件,用来同步或确认最新的选中状态。

内容的提问来源于stack exchange,提问作者AJB

火山引擎 最新活动