项目背景: 需要实现树形组件中的内容可以拖拽到功能区的六个功能位,使用tree自带的拖拽draggable功能会产生问题,故而使用HTML5原生拖拽事件来控制实现。

1.首先渲染树形数据

<el-tree
  ref="treeRef"
  style="max-width: 600px"
  class="filter-tree"
  :accordion="false"
  :show-checkbox="false"
  :data="data"
  :props="defaultProps"
  :filter-node-method="filterNode"
  node-key="id"
>
  <template #default="{ node, data }">
    <div v-if="data.children" class="custom-tree-node">
      <span>{{ node.label }}</span>
    </div>
    <div v-else draggable="true" @dragstart="handleDragStart(data, $event)" class="custom-tree-node flex relative w-full">
      <div>{{ node.label }}</div>
    </div>
  </template>
</el-tree>

开启拖拽 draggable="true",这里使用v-if方法限制只给二级菜单添加了拖拽事件,一级菜单不能拖拽

01. 绑定@dragstart="handleDragStart(data, $event)"事件,给退拽元素打上标签和参数

// 拖拽开始事件
const handleDragStart = (node: Node, ev: any) => {
  ev.dataTransfer?.setData('text/plain', node.id.toString()); // 将被拖拽项的 id 存入 dataTransfer 对象中
  ev.dataTransfer?.setData('text/type', "tree"); // 将被拖拽项的 type 存入 dataTransfer 对象中
  ev.dataTransfer?.setData('text/label', node.label.toString()); // 将被拖拽项的 label 存入 dataTransfer 对象中
};

2.渲染拖拽放置的功能区

<div class="flex w-full h-full" @dragover.prevent="dragoverInfo" @drop="handleDrop">
  <div class="w-full flex h-full justify-between flex-wrap">
    <div v-for="item in moveBoxList" :key="item.id" :data-id="item.id" class="moveBox w-32.6% h-28.4vh mb-6px mt-6px relative">
      <template v-if="item.url">
        <div class="w-full h-40px absolute z-9 top-0 left-0 bg-#293A5880 flex justify-between items-center">
          <div class="infoTitle ALMM text-(16px #333333)">{{ item.name }}</div>
          <div class="text-(14px #ffffff) flex justify-center items-center mr-12px">
            <div class="flex justify-center items-center cursor-pointer mr-16px">
              <img src="/@/assets/images/playbackIcon.png" alt="">
              <span class="ml-8px">回放</span>
            </div>
            <div class="flex justify-center items-center cursor-pointer">
              <img src="/@/assets/images/amplifyIcon.png" alt="">
              <span class="ml-8px">放大</span>
            </div>
          </div>
        </div>
        <div class="w-full h-full flex bg-#E1E1E1 justify-center items-center" v-loading="item.isLoading">
          <img class="w-120px h-130px" src="/@/assets/images/noData.png" alt="">
        </div>
      </template>
      <template v-else>
        <div class="w-full h-full flex bg-#E1E1E1 justify-center items-center">
          <img class="w-120px h-130px" src="/@/assets/images/noData.png" alt="">
        </div>
      </template>
    </div>
  </div>
</div>

给功能区添加@dragover.prevent="dragoverInfo" 和 @drop="handleDrop"事件,

01. dragoverInfo事件允许拖拽放置

// 拖拽
const dragoverInfo = (event) => {
  event.preventDefault(); // 允许放置
}

02. handleDrop事件监听拖拽放置结束

// 拖拽进入结束
const handleDrop = (event) => {
  event.preventDefault();
  const type = event.dataTransfer?.getData('text/type'); // 获取被拖拽项的 id
 if (type === "tree") {
   const id = event.dataTransfer?.getData('text/plain'); // 获取被拖拽项的 id
   const label = event.dataTransfer?.getData('text/label'); // 获取被拖拽项的 id
   // 找到被拖拽到的 moveBox 容器
   const targetElement = event.target as HTMLElement;
   const moveBoxElement = targetElement.closest('.moveBox');
   if (moveBoxElement) {
     const moveBoxId = parseInt(moveBoxElement.getAttribute('data-id') || '0');
     console.log('拖入的 moveBox 是:', moveBoxId);
    // 这里可以找到当前拖拽的元素放置在哪一个功能区的位置,然后执行对应的业务逻辑

   }
 }
}

小结: 

1. 通过给树形组件自定义节点绑定允许拖拽事件和配置,通过绑定的拖拽事件给拖拽元素打上标记并且携带参数

2. 在功能区绑定@dragover.prevent事件允许拖拽元素放置

3. 在功能区绑定@drop事件监听拖拽结束,通过业务逻辑找到拖拽到第几个功能区,并且拿取参数执行需要做的业务逻辑

Logo

中国智能体开发者社区,聚焦智能体与大模型开发,提供前沿资讯、实用工具链、开源项目及行业案例。通过技术沙龙、开发者大赛等活动,促进经验交流与协作,助力开发者快速构建创新智能应用。

更多推荐