仅支持同级拖拽
<template>
<div class="draggable" style="padding: 20px">
<el-table ref="sortableTable" row-key="id" :data="tableData" :key="tableKey" style="width: 100%">
<el-table-column prop="展开" width="40"></el-table-column>
<el-table-column prop="添加二级" width="60">
<template slot-scope="scope">
<span style="cursor:pointer;color:#100DB1 " @click="addItem(scope['row'])"
v-if="scope['row']['level']===1">{{'+ 二级'}}</span>
</template>
</el-table-column>
<el-table-column prop="拖拽" width="40">
<template slot-scope="scope">
<i class="el-icon-setting draggableIcon"></i>
</template>
</el-table-column>
<el-table-column prop="name">
</el-table-column>
</el-table>
</div>
</template>
<script>
import Sortable from 'sortablejs';
export default {
mounted() {
this.rowDrop()
},
data() {
return {
tableKey: 0,
activeRows: [],
tableData: [
{
id: 1,
level: 1,
name: '李一',
gender: '男',
age: 30,
job: "会计",
children: [{
id: 31,
level: 2,
name: '李一1',
gender: '2016-05-01',
age: '王小虎',
job: '上海市普陀区金沙江路 1519 弄',
}, {
id: 32,
name: '李一2',
level: 2,
gender: '2016-05-01',
age: '王小虎',
job: '上海市普陀区金沙江路 1519 弄'
}]
},
{
level: 1,
id: 2,
name: '王二',
gender: '未知',
age: 18,
job: "无业游民"
},
{
id: 3,
name: '张三',
gender: '男',
age: 50,
job: "老板",
level: 1,
children: [{
id: 321,
level: 2,
name: '张三1',
gender: '2016-05-01',
age: '王小虎',
job: '上海市普陀区金沙江路 1519 弄'
}, {
id: 322,
level: 2,
name: '张三2',
gender: '2016-05-01',
age: '王小虎',
job: '上海市普陀区金沙江路 1519 弄'
}]
},
],
tableConfig: {
tableItems: [
{
label: '姓名',
prop: 'name',
},
{
label: '性别',
prop: 'gender',
},
{
label: '年龄',
prop: 'age',
},
{
label: '工作',
prop: 'job',
},
]
}
}
},
methods: {
getUuiD(randomLength) {
return Number(Math.random().toString().substr(2, randomLength) + Date.now()).toString(36)
},
// 添加二级
addItem(r) {
let data = {
id: this.getUuiD(),
name: '李一11111111',
gender: '2016-05-01',
age: '王小虎',
job: '上海市普陀区金沙江路 1519 弄',
}
let idx = this.tableData.findIndex(e => e.id === r.id)
if (idx > -1) {
let item = this.tableData[idx]
if (item.hasOwnProperty('children')) {
item.children.push(data)
} else {
item['children'] = [{ ...data }]
}
}
this.tableData = [...this.tableData]
},
// 行拖拽
rowDrop() {
// 获取表格节点
// this.tableSortDestroy()
this.$nextTick(() => {
const el = this.$refs.sortableTable.$el.querySelector('.el-table__body-wrapper tbody')
if (!el) { return }
const _this = this
// 插件调用函数
Sortable.create(el, {
animation: 300,
handle: '.draggableIcon',
onMove({ dragged, related }) {
// _this.$set(_this, 'tableData', _this.arrayTreeSetLevel(_this.tableData)) // 树形结构数据添加level
_this.$set(_this, 'activeRows', _this.treeToTile(_this.tableData)) // 把树形的结构转为列表再进行拖拽
const oldRow = _this.activeRows[dragged.rowIndex]
const newRow = _this.activeRows[related.rowIndex]
if (oldRow.level !== newRow.level && oldRow.id !== newRow.id) { //不能跨级拖拽
console.log('oldRow.level !== newRow.level')
return false
}
},
onEnd({ oldIndex, newIndex }) {
const oldRow = _this.activeRows[oldIndex] // 移动的那个元素
const newRow = _this.activeRows[newIndex] // 新的元素
console.log('onEnd判断--->', oldIndex, newIndex, oldRow.level, newRow.level, oldRow.id, newRow.id)
if (oldIndex !== newIndex && oldRow.level === newRow.level && oldRow.id !== newRow.id) {
console.log(oldRow)
console.log(newRow)
const modelProperty = _this.activeRows[oldIndex]
console.log('modelProperty', modelProperty)
const changeIndex = newIndex - oldIndex
const index = _this.activeRows.indexOf(modelProperty)
console.log('index', index)
if (index < 0) {
console.log('index < 0')
return
}
_this.activeRows.splice(index, 1)
_this.activeRows.splice(index + changeIndex, 0, modelProperty)
console.log('activeRows', _this.activeRows)
_this.sortMenuData()
}
}
})
})
},
sortMenuData() {
let res = []
this.activeRows.forEach(r => {
if (r.level === 1) {
let itemIdx = this.tableData.findIndex(t => t.id === r.id)
if (itemIdx > -1) {
res.push({ ...this.tableData[itemIdx] })
}
}
})
this.tableData = res
console.log(this.tableData)
this.tableKey = Math.random() //狠狠的刷新dom
this.rowDrop() // 再把拖拽的功能塞入
},
treeToTile(treeData, childKey = 'children') { // 将树数据转化为平铺数据
const arr = []
const expanded = data => {
if (data && data.length > 0) {
data.filter(d => d).forEach(e => {
arr.push(e)
expanded(e[childKey] || [])
})
}
}
expanded(treeData)
console.log('treeToTile', arr)
return arr
},
}
}
</script>
<style scoped lang="scss">
/deep/.el-table__row--level-1 {
background: #F5F5FC;
}
</style>
支持跨级拖拽
<template>
<div class="draggable" style="padding: 20px">
<el-table ref="sortableTable" row-key="id" :data="tableData" :key="tableKey" style="width: 100%">
<el-table-column prop="展开" width="40"></el-table-column>
<el-table-column prop="添加二级" width="60">
<template slot-scope="scope">
<span style="cursor:pointer;color:#100DB1 " @click="addItem(scope['row'])"
v-if="scope['row']['level']===1">{{'+ 二级'}}</span>
</template>
</el-table-column>
<el-table-column prop="拖拽" width="40">
<template slot-scope="scope">
<i class="el-icon-setting draggableIcon"></i>
</template>
</el-table-column>
<el-table-column prop="name">
</el-table-column>
</el-table>
</div>
</template>
<script>
import Sortable from 'sortablejs';
export default {
mounted() {
this.rowDrop()
},
data() {
return {
tableKey: 0,
activeRows: [],
tableData: [
{
id: 1,
level: 1,
name: '李一',
gender: '男',
age: 30,
job: "会计",
children: [{
id: 31,
level: 2,
name: '李一1',
gender: '2016-05-01',
age: '王小虎',
job: '上海市普陀区金沙江路 1519 弄',
}, {
id: 32,
name: '李一2',
level: 2,
gender: '2016-05-01',
age: '王小虎',
job: '上海市普陀区金沙江路 1519 弄'
}]
},
{
level: 1,
id: 2,
name: '王二',
gender: '未知',
age: 18,
job: "无业游民"
},
{
id: 3,
name: '张三',
gender: '男',
age: 50,
job: "老板",
level: 1,
children: [{
id: 321,
level: 2,
name: '张三1',
gender: '2016-05-01',
age: '王小虎',
job: '上海市普陀区金沙江路 1519 弄'
}, {
id: 322,
level: 2,
name: '张三2',
gender: '2016-05-01',
age: '王小虎',
job: '上海市普陀区金沙江路 1519 弄'
}]
},
],
tableConfig: {
tableItems: [
{
label: '姓名',
prop: 'name',
},
{
label: '性别',
prop: 'gender',
},
{
label: '年龄',
prop: 'age',
},
{
label: '工作',
prop: 'job',
},
]
}
}
},
methods: {
getUuiD(randomLength) {
return Number(Math.random().toString().substr(2, randomLength) + Date.now()).toString(36)
},
// 添加二级
addItem(r) {
let data = {
id: this.getUuiD(),
name: '李一11111111',
gender: '2016-05-01',
age: '王小虎',
job: '上海市普陀区金沙江路 1519 弄',
}
let idx = this.tableData.findIndex(e => e.id === r.id)
if (idx > -1) {
let item = this.tableData[idx]
if (item.hasOwnProperty('children')) {
item.children.push(data)
} else {
item['children'] = [{ ...data }]
}
}
this.tableData = [...this.tableData]
},
// 行拖拽
rowDrop() {
// 获取表格节点
// this.tableSortDestroy()
this.$nextTick(() => {
const el = this.$refs.sortableTable.$el.querySelector('.el-table__body-wrapper tbody')
if (!el) { return }
const _this = this
// 插件调用函数
Sortable.create(el, {
animation: 300,
handle: '.draggableIcon',
onMove({ dragged, related }) {
_this.$set(_this, 'activeRows', _this.treeToTile(_this.tableData)) // 把树形的结构转为列表再进行拖拽
},
onEnd({ oldIndex, newIndex }) {
const oldRow = _this.activeRows[oldIndex] // 移动的那个元素
const newRow = _this.activeRows[newIndex] // 新的元素
if (oldIndex !== newIndex && oldRow.id !== newRow.id) {
const modelProperty = _this.activeRows[oldIndex]
const changeIndex = newIndex - oldIndex
const index = _this.activeRows.indexOf(modelProperty)
if (oldRow.level === newRow.level && oldRow.level === 1) {
// 一级之间的拖拽
if (index < 0) {
console.log('index < 0')
return
}
_this.activeRows.splice(index, 1)
_this.activeRows.splice(index + changeIndex, 0, modelProperty)
_this.sortMenuData('1-1')
} else if (oldRow.level === newRow.level && oldRow.level === 2) {
// 二级之间的拖拽
// _this.activeRows.splice(index, 1)
let res = [];
_this.tableData.forEach(t => {
if (t.hasOwnProperty('children')) {
// 在原来的一级下删除二级
let oldChildIndex = t.children.findIndex(c => c.id === oldRow.id)
if (oldChildIndex > -1) {
t.children.splice(oldChildIndex, 1)
}
// 在新的一级下添加二级
let newChildIndex = t.children.findIndex(c => c.id === newRow.id)
if (newChildIndex > -1) {
t.children = [...t.children.slice(0, newChildIndex), oldRow, ...t.children.slice(newChildIndex)]
}
}
res.push(t)
_this.tableData = res
})
_this.tableKey = Math.random()
_this.rowDrop()
} else if (oldRow.level === 2 && newRow.level === 1) {
// 二级移动到一级
// console.log('2-1', oldRow, newRow)
let res = [];
_this.tableData.forEach(t => {
if (t.hasOwnProperty('children')) {
// 在原来的一级下删除二级
let oldChildIndex = t.children.findIndex(c => c.id === oldRow.id)
if (oldChildIndex > -1) {
t.children.splice(oldChildIndex, 1)
}
}
// 将提升为一级的二级放到相应位置
let item = { ...oldRow, level: 1 }
if (t.id === newRow.id) {
res.push(t, item)
} else {
res.push(t)
}
_this.tableData = res
})
_this.tableKey = Math.random()
_this.rowDrop()
} else if (oldRow.level === 1 && newRow.level === 2) {
// 一级移动到二级
console.log('1-2', oldRow, newRow)
let res = [];
let item = [{ ...oldRow, level: 2 }]
if (oldRow.hasOwnProperty('children')) {
item = [...item, ...oldRow.children]
delete item[0].children
}
_this.tableData.forEach(t => {
// 将降为二级的目标以及他的children放到相应的位置
if (t.hasOwnProperty('children')) {
let newChildIndex = t.children.findIndex(c => c.id === newRow.id)
if (newChildIndex > -1) {
t.children = [...t.children.slice(0, newChildIndex), ...item, ...t.children.slice(newChildIndex)]
}
}
if (t.id !== oldRow.id) {
res.push(t)
}
})
_this.tableData = res
_this.tableKey = Math.random()
_this.rowDrop()
}
}
}
})
})
},
sortMenuData(type) {
if (type === '1-1') {
let res = []
this.activeRows.forEach(r => {
if (r.level === 1) {
let itemIdx = this.tableData.findIndex(t => t.id === r.id)
if (itemIdx > -1) {
res.push({ ...this.tableData[itemIdx] })
}
}
})
this.tableData = res
}
this.tableKey = Math.random() //狠狠的刷新dom
this.rowDrop() // 再把拖拽的功能塞入
},
treeToTile(treeData, childKey = 'children') { // 将树数据转化为平铺数据
const arr = []
const expanded = data => {
if (data && data.length > 0) {
data.filter(d => d).forEach(e => {
arr.push(e)
expanded(e[childKey] || [])
})
}
}
expanded(treeData)
// console.log('treeToTile', arr)
return arr
},
}
}
</script>
<style scoped lang="scss">
/deep/.el-table__row--level-1 {
background: #F5F5FC;
}
</style>