elementUI+vue2+Sortable.js实现列拖拽(二级表头)

1.安装插件

(vuedraggable依赖 Sortable.js,下载后可以直接引入sortablejs进行使用)

npm i -S vuedraggable

2.引入

import Sortable from 'sortablejs'

3.使用

(1)表格只有一行表头的基础表格

<template>
  <div style="width:600px">
    <el-table :data="tableData" border row-key="id" align="left">
      <el-table-column v-for="(item, index) in col" :key="`col_${index}`" 
           :prop="dropCol[index].prop" :label="item.label">
      </el-table-column>
    </el-table>
  </div>
</template>
<script>
import Sortable from 'sortablejs'
export default {
  data() {
    return {
      col: [
        {
          label: '日期',
          prop: 'date'
        },
        {
          label: '姓名',
          prop: 'name'
        },
        {
          label: '地址',
          prop: 'address'
        }
        ],
      dropCol: // 和col一模一样
      tableData: [
        {
          id: '1',
          date: '2016-05-02',
          name: '王小虎1',
          address: '上海市普陀区金沙江路 100 弄'
        },
        {
          id: '2',
          date: '2016-05-04',
          name: '王小虎2',
          address: '上海市普陀区金沙江路 200 弄'
        },
        {
          id: '3',
          date: '2016-05-01',
          name: '王小虎3',
          address: '上海市普陀区金沙江路 300 弄'
        },
        {
          id: '4',
          date: '2016-05-03',
          name: '王小虎4',
          address: '上海市普陀区金沙江路 400 弄'
        }
      ]
    }
  },
  mounted() {
    this.columnDrop()
  },
  methods: {
    // 列拖拽
    columnDrop() {
      const wrapperTr = document.querySelector('.el-table__header-wrapper tr')
      this.sortable = Sortable.create(wrapperTr, {
        animation: 180,
        delay: 0,
        onEnd: evt => {
          const oldItem = this.dropCol[evt.oldIndex]
          this.dropCol.splice(evt.oldIndex, 1)
          this.dropCol.splice(evt.newIndex, 0, oldItem)
        }
      })
    }
  }
}
</script>

(2)如果有fixed属性,就直接加在dropCol和col里面,dropCol和col在data里是一样的,注意在页面里的fixed为true时是不会被拖动的。

(3)如果有sortable和width属性的话,同fixed一样加在dropCol和col里面,但是在html中使用时注意使用的是col中的sortable,因为sortable是跟着表头的字段一起被拖动的,而width应该适应字段,所以width取的是变换后的dropCol中的width。

(4)【多级表头情况】如下图,表头被分为两块,拖动第二层的表头的情况,需要注意一下几个点。

a.循环渲染会出现,第二层的表头未被渲染时就需要使用,就取不到第二层表头,在基础表格的代码中,需要修改取到的wrapper,同时在使用这个方法时要用nextTick包上就不会出现取不到想要节点的情况。

b.需要判断拖动的是哪部分的表头,二层表头肯定是只能在一级表头的对应区域中拖拽。

有两种写法,一种是两个分开拖拽的表头使用两个变量分别定义,然后循环时分别循环,第二种是写在一个变量里,循环时进行判断。这里使用的是第一种写法。

定义变量和循环渲染如下:

js部分,在列拖拽的方法里,定义的evtNum是第一部分有evtNum+1个字段,buTuo方法实现了禁止列拖拽,在判断拖动的字段是第一部分或者第二部分时,改变对应的dropCol。

完整代码如下:

<template>
  <div style="width:1000px;margin-left: 10px;">
    <el-table :data="tableData" border row-key="id" align="left">
      <el-table-column label="我是1">
        <el-table-column v-for="(item, index) in col" :key="`col_${index}`" :prop="dropCol[index].prop"
          :label="item.label" :fixed="item.fixed" :sortable="item.sortable" :width="dropCol[index].width">
        </el-table-column>
      </el-table-column>
      <el-table-column label="我是2">
        <el-table-column v-for="(item, index) in col2" :key="`col_${index}`" :prop="dropCol2[index].prop"
          :label="item.label" :fixed="item.fixed" :sortable="item.sortable" :width="dropCol2[index].width">
        </el-table-column>
      </el-table-column>
    </el-table>
  </div>
</template>
<script>
import Sortable from 'sortablejs'
export default {
  data() {
    return {
      col: [
        { label: 'id', prop: 'id', fixed: false, sortable: true, width: 200 },
        { label: '日期', prop: 'date', fixed: false, sortable: true, width: 200 },
        { label: '姓名', prop: 'name', fixed: false, sortable: false, width: 100 },
        { label: '地址', prop: 'address', fixed: false, sortable: false, width: 200 }
      ],
      dropCol: [
        {
          label: 'id',
          prop: 'id',
          fixed: false,
          sortable: true,
          width: 200,
        },
        {
          label: '日期',
          prop: 'date',
          fixed: false,
          sortable: true,
          width: 200,
        },
        {
          label: '姓名',
          prop: 'name',
          fixed: false,
          sortable: false,
          width: 100,
        },
        {
          label: '地址',
          prop: 'address',
          fixed: false,
          sortable: false,
          width: 200,
        }
      ],
      col2: [
        { label: 'id', prop: 'id', fixed: false, sortable: true, width: 200 },
        { label: '日期', prop: 'date', fixed: false, sortable: true, width: 200 },
        { label: '姓名', prop: 'name', fixed: false, sortable: false, width: 100 },
        { label: '地址', prop: 'address', fixed: false, sortable: false, width: 200 }
      ],
      dropCol2: [
        {
          label: 'id',
          prop: 'id',
          fixed: false,
          sortable: true,
          width: 200,
        },
        {
          label: '日期',
          prop: 'date',
          fixed: false,
          sortable: true,
          width: 200,
        },
        {
          label: '姓名',
          prop: 'name',
          fixed: false,
          sortable: false,
          width: 100,
        },
        {
          label: '地址',
          prop: 'address',
          fixed: false,
          sortable: false,
          width: 200,
        }
      ],
      tableData: [
        {
          id: '1',
          date: '2016-05-02',
          name: '王小虎1',
          address: '上海市普陀区金沙江路 100 弄',
          id2: '1',
          date2: '2016-05-10',
          name2: '王小虎1444',
          address2: '上海市普陀区金沙江路 1020 弄'
        },
        {
          id: '2',
          date: '2016-05-04',
          name: '王小虎2',
          address: '上海市普陀区金沙江路 200 弄',
          id2: '2',
          date2: '2016-05-12',
          name2: '王小虎14224',
          address2: '上海市普陀区金沙江路 1220 弄'
        },
        {
          id: '3',
          date: '2016-05-01',
          name: '王小虎3',
          address: '上海市普陀区金沙江路 300 弄',
          id2: '3',
          date2: '2016-05-13',
          name2: '王小虎1333',
          address2: '上海市普陀区金沙江路 3320 弄'
        },
        {
          id: '4',
          date: '2016-05-03',
          name: '王小虎4',
          address: '上海市普陀区金沙江路 400 弄',
          id2: '4',
          date2: '2016-05-16',
          name2: '王小虎1666',
          address2: '上海市普陀区金沙江路 10266 弄'
        }
      ]
    }
  },
  mounted() {
    this.$nextTick(() => {
      this.columnDrop()
    })
  },
  methods: {
    //列拖拽
    columnDrop() {
      const wrapperTr = document.querySelector('.has-gutter tr:nth-child(2)')
      this.sortable = Sortable.create(wrapperTr, {
        animation: 180,
        delay: 0,
        onEnd: evt => {
          const evtNum = 3  // 判断第一部分的表头只能在3以内拖动 剩下的第二部分在3以后拖动
          const buTuo = () => {
            let newNode = wrapperTr.childNodes[evt.newIndex].cloneNode(true)
            wrapperTr.removeChild(wrapperTr.childNodes[evt.newIndex])
            wrapperTr.insertBefore(newNode, wrapperTr.childNodes[evt.oldIndex])
          }
          if (evt.oldIndex <= evtNum) {
            if (evt.newIndex <= evtNum) { // 第一部分表头的拖拽
              const oldItem = this.dropCol[evt.oldIndex]
              this.dropCol.splice(evt.oldIndex, 1)
              this.dropCol.splice(evt.newIndex, 0, oldItem)
            } else {
              buTuo()  // 不允许拖拽
            }
          } else {
            if (evt.newIndex > evtNum) { // 第二部分表头的拖拽
              const oldItem = this.dropCol2[evt.oldIndex - evtNum - 1]
              this.dropCol2.splice(evt.oldIndex - evtNum - 1, 1)
              this.dropCol2.splice(evt.newIndex - evtNum - 1, 0, oldItem)
            } else {
              buTuo()  // 不允许拖拽
            }
          }
        }
      })
    }
  }
}
</script>

  • 4
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值