vue elementUi+sortable.js實現(xiàn)嵌套表格拖拽問題
vue elementUi+sortable.js嵌套表格拖拽
首先說下項目需求,一個多層嵌套的表格,行可以進行拖拽排序,但不能跨主級去拖拽,下拉可以異步獲取數(shù)據(jù),考慮了很久,還是用最熟悉的vue+element來做,但是element沒有拖拽排序的功能,所以在此基礎上加入sortable.js去實現(xiàn)拖拽功能。
后臺返回的排序規(guī)則是 每個數(shù)據(jù)都帶有3個屬性 id next prev
用這3個屬性實時的去更新排序
- id表示這一條數(shù)據(jù)的id
- next表示下一條數(shù)據(jù)的id
- prev表示上一條數(shù)據(jù)的id
html部分

data部分
flattArray:[], originalData:[], tableData: [], arr:[], maps:new Map()
我這里定義了四個數(shù)組和一個map
flattArray是平鋪的數(shù)據(jù) originalData數(shù)組也是平鋪的數(shù)據(jù)(以防數(shù)據(jù)出錯,沒有啥實際用途) tableData是表格渲染的數(shù)據(jù) arr是點擊下拉異步請求的數(shù)據(jù)
maps是tableData改變后去重新渲染數(shù)據(jù)用的
methods部分
首先我定義了一個方法去深拷貝,這樣改變一個數(shù)據(jù)的時候,其他數(shù)據(jù)不會改變
//深拷貝
getNewObject(val) {
let resObj = JSON.stringify(val);
return JSON.parse(resObj);
},加載頁面從接口 獲取 tableData數(shù)據(jù) 并深拷貝 tableData
getDetails(id){
axios.get(url).then(res =>{
if(res.data.code === 0){
this.tableData = res.data.data
this.tableData.map( item =>{
item.hasChildren = true
delete item.children
})
this.flattArray = this.getNewObject(this.tableData)
this.originalData = this.getNewObject(this.tableData)
}else{
this.$message.error('網(wǎng)絡錯誤');
}
}).catch(function (error) {
this.$message.error('網(wǎng)絡錯誤');
});
},這里表格就已經(jīng)渲染出來了 ,因為下拉的數(shù)據(jù)要異步去獲取,所以在element提供的下拉事件里面去請求數(shù)據(jù),這里去獲取子級的數(shù)據(jù),并給maps賦值,利用遞歸,把數(shù)據(jù)平鋪、組裝。
//點擊下拉圖標異步加載數(shù)據(jù)
load(tree, treeNode, resolve) {
this.maps.set(tree.id, { tree, treeNode, resolve })
axios.get(`url` + tree.id).then(res => {
if (res.data.code == 0) {
this.arr = res.data.data
this.arr.map(item => {
item.hasChildren = true
delete item.children
this.flattArray.push(item)
})
resolve(this.arr)
const tree = buildTree(this.flattArray, 1);
//組裝tree
function buildTree(nodes, parent) {
const res = [];
for (let item of nodes) {
if (item.parentId === parent) {
const children = buildTree(nodes, item.id);
if (children.length) {
item.children = children;
}
res.push(item);
}
}
return res;
}
//平鋪tree
let result = [];
function flatTree(nodes, parentId) {
if (!nodes || nodes.length === 0) return [];
nodes.forEach(node => {
result.push(node);
return flatTree(node.children, node.id);
});
}
flatTree(tree, 1);
this.originalData = result
this.getNewObject(this.originalData)
} else {
this.$message.error('沒有更多消息了');
}
})
},定義的行拖拽方法,因為排序是用的3個屬性去排序的,所以有3種情況去考慮
- 一是拖動到最上級,這樣prev的值就為空
- 二是拖動到最下級,next為空
- 三是正常的拖動,next prev都不為空
rowDrop() {
this.$nextTick(() => {
const tbody = document.querySelector('.el-table__body-wrapper tbody')
const _this = this
Sortable.create(tbody, {
animation: 300,
sort: true,
onEnd({
oldIndex,
newIndex,
item
}) {
const sourceObj = _this.originalData[oldIndex - 1] // 原本的位置
const targetObj = _this.originalData[newIndex - 1] // 移動到的位置
const frontObj = _this.originalData[newIndex - 2] //移動后位置的上一級
const behindObj = _this.originalData[newIndex] //移動后位置的下一級
if(sourceObj.parentId != targetObj.parentId) {
_this.$message.error("不支持跨級拖動,請拖回原來位置")
location.reload();
return;
}
let data = [];
if( oldIndex < newIndex ){//向下移動
//上一級
let predata = {
id: targetObj.id,
next: sourceObj.id,
prev: targetObj.prev
}
//自己
let curdata = {
id: sourceObj.id,
next: targetObj.next,
prev: targetObj.id,
groupId: sourceObj.groupId
}
//下一級
let nextdata = null
if (behindObj != undefined && sourceObj.parentId == behindObj.parentId) {
nextdata = {
id: behindObj.id,
next: behindObj.next,
prev: sourceObj.id
}
}
if(nextdata){
data.push(curdata, predata, nextdata)
}else{
data.push(curdata, predata)
}
_this.postdata(data, sourceObj.parentId)
}else if( oldIndex > newIndex ){//向上移動
//上一級
let predata = null
if (frontObj != undefined && sourceObj.parentId == frontObj.parentId) {
predata = {
id: frontObj.id,
next: sourceObj.id,
prev: frontObj.prev
}
}
//自己
let curdata = {
id: sourceObj.id,
next: targetObj.id,
prev: targetObj.prev,
groupId: sourceObj.groupId
}
//下一級
let nextdata = {
id: targetObj.id,
next: targetObj.next,
prev: sourceObj.id
}
if(predata){
data.push(curdata, predata, nextdata)
}else{
data.push(curdata, nextdata)
}
_this.postdata(data, sourceObj.parentId)
}
}
})
})
},mounted 里面去加載 改變行的方法
mounted() {
this.rowDrop()
},最后再去動態(tài)的更新數(shù)據(jù)
refreshLoadTree(parentId) {
// 根據(jù)父級id取出對應節(jié)點數(shù)據(jù)
const {tree, treeNode, resolve} = this.maps.get(parentId)
this.$set(this.$refs.tableData.store.states.lazyTreeNodeMap, parentId, [])
if (tree) {
this.load(tree, treeNode, resolve)
}
},到這里需求已經(jīng)實現(xiàn)了,就沒有去深入的挖掘,可能會有問題,但是隔的時間太久了,基本忘光了。
總結
以上為個人經(jīng)驗,希望能給大家一個參考,也希望大家多多支持腳本之家。
- Vue?+?ElementUI表格內(nèi)實現(xiàn)圖片點擊放大效果的兩種實現(xiàn)方式
- vue elementUI table表格自定義樣式滾動效果
- Vue+ElementUI表格狀態(tài)區(qū)分,row-class-name屬性詳解
- vue+elementui 表格分頁限制最大頁碼數(shù)的操作代碼
- elementui實現(xiàn)表格(el-table)默認選中功能
- Vue+ElementUI踩坑之動態(tài)顯示/隱藏表格的列el-table-column問題
- 使用elementUI的表格table給列添加樣式
- vue基于ElementUI動態(tài)設置表格高度的3種方法
相關文章
詳解無限滾動插件vue-infinite-scroll源碼解析
這篇文章主要介紹了詳解無限滾動插件vue-infinite-scroll源碼解析,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧2019-05-05
vue+webpack 打包文件 404 頁面空白的解決方法
下面小編就為大家分享一篇vue+webpack 打包文件 404 頁面空白的解決方法,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧2018-02-02

