IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> JavaScript知识库 -> vue3 + element plus实现树状表格的拖拽排序 -> 正文阅读

[JavaScript知识库]vue3 + element plus实现树状表格的拖拽排序

描述:使用vue3 + element plus实现树状表格的拖拽排序功能
请添加图片描述
index.vue

<el-table
  ref="tableRef"
  :data="tableData"
  row-key="id"
  style="width: 100%"
  :tree-props="tableTreeProps"
>
  <el-table-column prop="date" label="Date" width="180" />
  <el-table-column prop="name" label="Name" width="180" />
  <el-table-column
    fixed="right"
    label="操作"
    width="204"
    className="operationCloumn">
    <template v-slot="scope">
      <span @click="deleteClick(scope.row)">编辑</span>
      <span @click="deleteClick(scope.row)">{{scope.row.enable ? '停用' :'启用'}}</span>
      <span @click="deleteClick(scope.row)">删除</span>
      <i class="moveIcon iconfont icon-yidong-16px"></i>
    </template>
  </el-table-column>
</el-table>

使用:传入表格tbody的dom元素和对应的表格数据

import { useTableDragSort } from '@/hooks/common'
onMounted(() => {
  const tableBodyDom = document.querySelector('.el-table .el-table__body-wrapper .el-scrollbar__wrap tbody') as HTMLElement
  useTableDragSort(tableBodyDom, tableData.value)
})
watch(tableData.value, () => {
  console.log('数据改变')
})

common.ts
封装拖拽的实现方法

// 表格拖拽排序
const lightLine = document.createElement('div')
lightLine.style.cssText += ';height: 1px; position: absolute; top: 0; left: 0; right: 0; background-color: skyblue; z-index: 999; display: none'
export async function useTableDragSort (tableBodyDom: HTMLElement, tableData: any[]) {
  setTimeout(() => {
    const trList = tableBodyDom.querySelectorAll<HTMLTableRowElement>('tr')
    const trHeight = trList[0].clientHeight
    const dragEnterTextList = tableBodyDom.querySelectorAll<HTMLElement>('tr .dragEnterText')
    const moveIconDoms = tableBodyDom.querySelectorAll<HTMLElement>('.moveIcon')
    tableBodyDom.appendChild(lightLine)

    // 一维数据
    const flatData = getChildrenItem(tableData, [])
    // console.log(flatData)

    // 当前拖拽对象
    let currentDragDom: HTMLTableRowElement
    let currentDragIndex: number
    for (let i = 0; i < trList.length; i++) {
      moveIconDoms[i].onmousedown = () => {
        trList[i].setAttribute('draggable', 'true')
        currentDragDom = trList[i]
        currentDragIndex = i
      }
      moveIconDoms[i].onmouseup = () => {
        trList[i].removeAttribute('draggable')
      }
      // 进入tr,展示高亮线
      trList[i].ondragenter = (e: DragEvent) => {
        if (notDragSonNode(flatData[currentDragIndex], flatData[i])) {
          lightLine.style.cssText += ';display: none'
          return
        }
        const dragEnterText = trList[i].querySelector('.dragEnterText') as HTMLElement
        const parentDom = dragEnterText.offsetParent as HTMLElement
        const left = dragEnterText.offsetLeft + parentDom.offsetLeft
        const top = Math.max(Math.abs(Math.round(e.offsetY / trHeight)) * trHeight + trList[i].offsetTop - 1, 0)
        lightLine.style.cssText += `;left: ${left}px; top: ${top}px; display: block`
      }
      trList[i].ondragover = (e: Event) => {
        e.preventDefault()
      }
      trList[i].ondrop = (e: DragEvent) => {
        currentDragDom.removeAttribute('draggable')
        if (notDragSonNode(flatData[currentDragIndex], flatData[i])) return
        const positionValue = Math.abs(Math.round(e.offsetY / trHeight)) // 0:在前面插入;1:在后面插入
        changeData(tableData, flatData[currentDragIndex], flatData[i], positionValue)
      }
      trList[i].ondragend = () => {
        lightLine.style.cssText += ';display: none'
      }
      // 进入文本,数据嵌套
      dragEnterTextList[i].ondrop = (e: Event) => {
        if (currentDragIndex === i) return
        e.stopPropagation()
        console.log('text:', dragEnterTextList[i], i)
      }
    }
  }, 0)
  // 获取所有子项处理为一维数组
  function getChildrenItem (arr: any[], res: any[]) {
    if (!arr) return res
    arr.forEach(checkItem => {
      res.push({
        ...checkItem
      })
      getChildrenItem(checkItem.children, res)
    })
    return res
  }
  // 判断父节点是否拖入子节点中
  function notDragSonNode (dragData: any, enterData: any) {
    if (dragData.id === enterData.id) return true
    if (!dragData.children) return false
    let children = JSON.parse(JSON.stringify(dragData.children))
    while (children.length > 0) {
      let cur = children.pop()
      if (cur.id === enterData.id) {
        return true
      } else if (cur.children){
        children.push(...cur.children)
      }
    }
    return false
  }
  // 处理拖拽排序前后的数据
  function changeData (parentData: any[], dragData: any, enterData: any, positionValue: number) {
    const stack = [parentData]
    let addOk = false
    let removeOk = false
    while (stack.length > 0) {
      const cur = stack.pop() || []
      const ids = cur.map((item: any) => item.id)
      let dragIndex = ids.indexOf(dragData.id)
      let enterIndex = ids.indexOf(enterData.id)
      // 同级情况
      if (dragIndex >= 0 && enterIndex >= 0) {
        if ((dragIndex - enterIndex === -1 && positionValue === 0)) return
        if ((dragIndex - enterIndex === 1 && positionValue === 1)) return
      }
      if (dragIndex >= 0 && !removeOk) {
        cur.splice(dragIndex, 1)
        removeOk = true
      }
      if (enterIndex >= 0 && !addOk) {
        addOk = true
        if (positionValue === 0) {
          cur.splice(enterIndex, 0, dragData)
          // console.log('在前面', enterIndex)
        } else {
          cur.splice(enterIndex + 1, 0, dragData)
          // console.log('在后面', enterIndex)
        }
        useTableDragSort(tableBodyDom, tableData)
      }
      if (!addOk || !removeOk) {
        cur.forEach((item:any) => stack.push(item.children))
      }
    }
  }
}

css
这里由于在表格中多添加了蓝色线条,所以body要添加position: relation的定位属性

tbody {
    position: relative;
}
  JavaScript知识库 最新文章
ES6的相关知识点
react 函数式组件 & react其他一些总结
Vue基础超详细
前端JS也可以连点成线(Vue中运用 AntVG6)
Vue事件处理的基本使用
Vue后台项目的记录 (一)
前后端分离vue跨域,devServer配置proxy代理
TypeScript
初识vuex
vue项目安装包指令收集
上一篇文章      下一篇文章      查看所有文章
加:2022-04-09 18:14:27  更:2022-04-09 18:14:35 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/24 2:47:14-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码