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>