vue+element+Sortablejs 树形表格拖拽

2,202 阅读1分钟

最近因为项目需求,专门研究了树形表格行拖拽。总结一下。效果图如下:

image.png 拖拽后

image.png 1,npm安装Sortablejs
可以参考中文文档www.itxst.com/sortablejs/… 在对应页面引入:import Sortable from 'sortablejs' 2,需求后台返回的树形结构数据。首先要根据后台返回的sort字段排序。 3,不能跨级拖拽,只能同级拖拽。 4,因为不能跨级拖拽,我们需要先把后台的数据每一级通过递归加上level。然后再平铺数据,根据他的level与parentId来进行判断是否同级,同级方可拖拽。 表格要必须添加:key="tableKey" row-key="id" ,key是用来刷新dom用的。 废话不说,直接上代码。

<el-table stripe v-loading="loading" :data="classificationList" style="width: 100%"
          :tree-props="{children: 'children', hasChildren: 'hasChildren'}"
          ref="sortableTable"
          :key="tableKey"
          row-key="id" @row-click="rowClick"
>
  <el-table-column type="index" width="50"  label="序号"></el-table-column>
  <el-table-column prop="name" show-overflow-tooltip  label="分类名称"></el-table-column>
  <el-table-column prop="code" show-overflow-tooltip  label="分类编码"></el-table-column>
  <el-table-column prop="operating"  label="操作" width="220">
    <template slot-scope="scope">
      <el-button  type="text" @click="getDetailCategory(scope.row)">详情</el-button>
      <el-button type="text" @click="getEditCategory(scope.row)">编辑</el-button>
      <el-button type="text" @click="getDeleteC(scope.row.id)">删除</el-button>
    </template>
  </el-table-column>
</el-table>

这是表格内容。 下面是全部逻辑代码,大家看完就懂啦

import Sortable from 'sortablejs'


export default {
  name: "detail",
  components:{
    addCommodity,
    detailCommodity,
    editCommodity
  },
  data() {
    return {
      isAddShopCategory: false,
      isDetails: false,
      isEdit: false,
      activeName: 'first',
      details:{},
      classificationList:[],
      commodityList:[],
      ids:{id:'',parentId:'',shopCategoryId:'',},
      loading:false,
      ownerNameList:[],
      payeeUuidList:[],
      invoiceDrawerUuidList:[],
      tableData:[],
      pageInfo:{},
      total:0,
      pageNum:1,
      pageSize:10,
      sortable: null,  // sortable对象
      activeRows: new Array(0),  // 排序时用来跟后端进行数据交互
      tableKey: ''  // 这个蛮重要的,让dom刷新

    }
  },
  created() {
    this.ids.id = this.$route.query.id
    if(this.ids.id){
      this.getDetail(this.ids.id);
      this.getCategoryTree(this.ids.id)
    }
    this.getOwnerName()
    this.getPayeeList()
    this.getInvoiceDrawer()
    //this.getGoodsList()
  },
  methods: {
    getCategoryTree(id){
      shopCategoryTree({id:id}).then(res => {
        let arr = this.sortMenu(res.data)
        this.classificationList = arr
        //初始化数据
        this.initData()
      })
    },
    //根据后台的sort递归字段排序
    sortMenu(arr) {
      arr.forEach((item) => {
        if(item.children && item.children.length) {
          this.sortMenu(item.children);
        }
      })
      arr.sort((a,b) => {
        return a.sort - b.sort;
      })
      return arr;
    },
    async initData () {
      if (this.sortable && this.sortable.el) {
        this.sortable.destroy()
      }
      // 这里是把树结构的数据再按照从上到下的顺序转化成平级数据
       this.arrayFlagLevel(this.classificationList,1)
      // 这里是把树结构的数据再按照从上到下的顺序转化成平级数据
      this.$set(this, 'activeRows', this.treeToTile(this.classificationList))
      // 这里是给tableKey一个随机数,Math.random也可以的,只要跟上一次的值不一样,能让dom刷新就可以
      this.tableKey = new Date().getTime()
      this.$nextTick(() => {
        this.setSort()
      })
    },
    setSort () {
      const el = document.querySelectorAll('table.el-table__body > tbody')[0]
      if (!el) {
        return
      }
      let that = this
      this.sortable = Sortable.create(el, {
        ghostClass: 'sortable-ghost',
        setData: function (dataTransfer) {
          dataTransfer.setData('Text', '')
        },
        // 拖拽移动的时候
        onMove: function ({ dragged, related }) {
          //树数据中不管是哪一层,都一定要有level字段
          /*
            evt.dragged; // 被拖拽的对象
            evt.related; // 被替换的对象
           */
          const oldRow = that.activeRows[dragged.rowIndex]
          const newRow = that.activeRows[related.rowIndex]
          if (oldRow.level !== newRow.level || oldRow.parentId !== newRow.parentId) {
            return false
          }
        },
        onEnd: async ({ oldIndex, newIndex }) => {
          const oldRow = that.activeRows[oldIndex]
          const newRow = that.activeRows[newIndex]
          if (oldIndex !== newIndex && oldRow.level === newRow.level && oldRow.parentId === newRow.parentId) {
            const oldRow = that.activeRows[oldIndex]
            const newRow = that.activeRows[newIndex]
            let oldRowSuffixData = that.activeRows.slice(oldIndex)
            let newRowSuffixData = that.activeRows.slice(newIndex)
            oldRowSuffixData = oldRowSuffixData.filter((d, i) => i < that.getLeastIndex(oldRowSuffixData.findIndex((_d, _i) => _d.level === oldRow.level && _i !== 0)))
            newRowSuffixData = newRowSuffixData.filter((d, i) => i < that.getLeastIndex(newRowSuffixData.findIndex((_d, _i) => _d.level === newRow.level && _i !== 0)))
            const targetRows = that.activeRows.splice(oldIndex, oldRowSuffixData.length)
            if (oldIndex > newIndex) {
              that.activeRows.splice(newIndex, 0, ...targetRows)
            } else if (oldIndex < newIndex) {
              that.activeRows.splice(newIndex + newRowSuffixData.length - oldRowSuffixData.length, 0, ...targetRows)
            }
            let newChildrenId=[]
            let childrenId =[]
            that.activeRows.map(item =>{
              if(oldRow.parentId && newRow.parentId){
                if(oldRow.parentId==item.id && newRow.parentId==item.id){
                  item.children.forEach(item2=>{
                    childrenId.push(item2.id)
                  })
                }
                let sortId = that.activeRows.map(d => d.id)
                newChildrenId = sortId.filter(function(n) {
                  return childrenId.indexOf(n) != -1
                });
              }else if(!oldRow.parentId && !newRow.parentId){
                if(oldRow.level ==1 && newRow.level==1){
                    if(oldRow.level ==item.level) {
                      newChildrenId.push(item.id)
                    }
                 }
               }
            })
            await that.sort(newChildrenId)
            this.tableKey = new Date().getTime()
            that.initData();
          }
        },
      })
    },
    //排序接口
    sort(arr){
      shopCategorySort({sortedCategoryId:arr}).then(res => {
        this.$message({
          type: 'success',
          message: res.msg
        })
        this.getCategoryTree(this.ids.id)
      })
    },
    getLeastIndex (index) {
      return index >= 1 ? index : 1
    },
    // 将树数据转化为平铺数据
   treeToTile(classificationList, childKey = 'children') {
    let arr = []
    let expanded = data => {
      if (data && data.length > 0) {
        data.filter(d => d).forEach(e => {
          arr.push(e)
          expanded(e[childKey] || [])
        })
      }
    }
    expanded(classificationList)
    return arr
   },
    //递归给每一级增加一个level
    arrayFlagLevel(array, level) {
      if (!array || !array.length) return;
      array.forEach(item => {
        item.level = level;
        if (item.children && item.children.length) {
          this.arrayFlagLevel(item.children, level + 1);
        }
      })
    },

好啦,完成,做一个爱学习爱研究的美少女啦