Vue3 使用 vuedraggable 时拖拽层级不生效的解决方法?

image.png 想要把AA1-BB3这条数据拖拽到第二层级,执行了事件onMove,没有执行dragEnd,如果AA1-BB3这条数据有同级,进行拖拽没有问题,这是什么原因?

image.png 想把AA3拖拽到AA2下面,做AA2的下一层级,也没有生效,如果AA2存在一个子集,则是可以的,这是什么原因?

vue3,vuedraggable

下面是代码是在递归组件里面:

<div style="display: flex;align-items: center;justify-content: center;">
            <Draggable v-if="item.expanded && item.children && item.children.length" :list="item.children"
                :key="item.id" :group="{ name: 'items', pull: true , put: true }" @end="dragEnd" :move="onMove" item-key="id"
                :class="item.children && item.children.length ? 'childItem childItemSon' : 'childItem'"
                ghost-class="ghost" chosen-class="chosen" animation="300" forceFallback="true">
                <template #item="{ element }">
                    <RecursiveItemHX :item="element" :index="index" :lightsItem="lightsItem" @editItem="editItem"
                        @deleteItem="deleteItem" @addBrotherItem="addBrotherItem" @addChildItem="addChildItem"
                        @testIntem="testIntem" @seeNodeDetail="seeNodeDetail" @expandCollapse="expandCollapse"
                        :parentChildrenLength="item.children.length" @addChildNestedItem="addChildNestedItem"
                        @updateTree="updateTree" />
                </template>
            </Draggable>
        </div>

执行事件:

const dragEnd = (event) => {
    console.log("结束dragEnd:", event);
    const { oldIndex, newIndex } = event;
    console.log("拖拽开始时的 oldIndex:", oldIndex, "newIndex:", newIndex);

    if (oldIndex !== undefined && newIndex !== undefined) {
        const movedItem = props.item.children[oldIndex];
        console.log("移动的项数据:", movedItem);
        const data = setParentIdToChildren(props.lightsItem);

        // 更新树形结构
        // emit('updateTree', oldIndex, newIndex, itemCopy);
        updateTree(oldIndex, newIndex, data)

    } else {
        console.warn("拖拽结束时,索引未定义,无法更新树形结构!");
    }
    console.log("结束dragEnd:", event);
};

// 不同级数据拖拽,parentId值取上一级的id
const setParentIdToChildren = (items, parentId = null) => {
    items.forEach(item => {
        item.parentId = parentId;
        if (item.children && item.children.length > 0) {
            setParentIdToChildren(item.children, item.id);
        }
    });

    return items;
};
// 更新外部数据
const updateTree = (oldIndex, newIndex, updatedItems) => {
    console.log("updateTree", oldIndex, newIndex, updatedItems);
    emit('updateTree', oldIndex, newIndex, updatedItems);
};

const onMove = (event) => {
    console.log("起始位置:", event.from);
    console.log("目标位置:", event.to);
    // if (event.from === event.to) {
    return true; // 允许在同一容器中拖动
    // } else {
    //     console.warn('只能在同级节点之间移动');
    //     // 可以弹出错误提示,或返回 false 来阻止移动
    //     return false;
    // }
};
阅读 3.5k
2 个回答
<template>
  <div style="display: flex; align-items: center; justify-content: center;">
    <Draggable 
      v-if="item.expanded && item.children && item.children.length" 
      :list="item.children"
      :key="item.id" 
      :group="{ name: 'items' }"
      @end="dragEnd" 
      @add="onAdd"
      @update="onUpdate"
      @move="onMove" 
      item-key="id"
      :class="item.children && item.children.length ? 'childItem childItemSon' : 'childItem'"
      ghost-class="ghost" 
      chosen-class="chosen" 
      animation="300"
      :force-fallback="true">
      <template #item="{ element }">
        <RecursiveItemHX 
          :item="element" 
          :index="index"
          :lightsItem="lightsItem"
          @editItem="editItem"
          @deleteItem="deleteItem"
          @addBrotherItem="addBrotherItem"
          @addChildItem="addChildItem"
          @testIntem="testIntem"
          @seeNodeDetail="seeNodeDetail"
          @expandCollapse="expandCollapse"
          :parentChildrenLength="item.children.length"
          @addChildNestedItem="addChildNestedItem"
          @updateTree="updateTree" />
      </template>
    </Draggable>
  </div>
</template>

<script setup>
const dragEnd = (evt) => {
  const { from, to, oldIndex, newIndex, item } = evt;
  
  const fromContainer = from.__draggable_component__.list;
  const toContainer = to.__draggable_component__.list;
  
  if (fromContainer === toContainer) {
    // 同层级拖拽
    console.log("同层级拖拽");
    updateTree(oldIndex, newIndex, props.lightsItem);
  } else {
    // 跨层级拖拽
    console.log("跨层级拖拽");
    const draggedItem = fromContainer[oldIndex];
    
    // 更新父级ID
    draggedItem.parentId = to.closest('[data-id]')?.dataset.id || null;
    
    // 从源容器删除
    fromContainer.splice(oldIndex, 1);
    
    // 添加到目标容器
    toContainer.splice(newIndex, 0, draggedItem);
    
    // 更新整个树结构
    const updatedTree = setParentIdToChildren(props.lightsItem);
    emit('updateTree', oldIndex, newIndex, updatedTree);
  }
};

const onMove = (evt) => {
  const { draggedContext, relatedContext } = evt;
  
  if (!relatedContext.element.children) {
    relatedContext.element.children = [];
  }
  
  return true; 
};

const onAdd = (evt) => {
  console.log('Added element', evt);
};

const onUpdate = (evt) => {
  console.log('Updated position', evt);
};

// 更新父级ID的函数
const setParentIdToChildren = (items, parentId = null) => {
  return items.map(item => {
    const newItem = { ...item, parentId };
    if (newItem.children && newItem.children.length > 0) {
      newItem.children = setParentIdToChildren(newItem.children, newItem.id);
    }
    return newItem;
  });
};

// 其他代码不变...
</script>

<style scoped>
.ghost {
  opacity: 0.5;
  background: #c8ebfb;
}

.chosen {
  background: #eee;
}

.childItem {
  margin-left: 20px;
}

.childItemSon {
  border-left: 1px dashed #ccc;
}
</style>
新手上路,请多包涵
    <div style="display: flex;align-items: center;justify-content: center;">
        <Draggable :list="item.children" :key="item.id" :group="{ name: 'items', pull: true, put: true }"
            @end="dragEnd" :move="onMove" item-key="id" v-if="item.expanded"
            :class="['childItem', item.children && item.children.length ? 'childItemSon' : 'noChildItem']"
            ghost-class="ghost" chosen-class="chosen" animation="300" forceFallback="true" :handle="'.item-name'">
            <template v-slot:item="{ element }">
                <RecursiveItemHX :item="element" :index="index" :lightsItem="lightsItem" @editItem="editItem"
                    @deleteItem="deleteItem" @addBrotherItem="addBrotherItem" @addChildItem="addChildItem"
                    @testIntem="testIntem" @seeNodeDetail="seeNodeDetail" @expandCollapse="expandCollapse"
                    :parentChildrenLength="item.children.length" @addChildNestedItem="addChildNestedItem"
                    @updateTree="updateTree" @copyItem="copyItem" @pasteItem="pasteItem" />
            </template>
            <template v-slot:empty>
                <div></div>
            </template>
        </Draggable>
    </div>

在没有子集的后面加个空白的区域,占位,就解决了

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