vue elementUi+sortable.js實現(xiàn)嵌套表格拖拽問題
vue elementUi+sortable.js嵌套表格拖拽
首先說下項目需求,一個多層嵌套的表格,行可以進(jìn)行拖拽排序,但不能跨主級去拖拽,下拉可以異步獲取數(shù)據(jù),考慮了很久,還是用最熟悉的vue+element來做,但是element沒有拖拽排序的功能,所以在此基礎(chǔ)上加入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)絡(luò)錯誤'); } }).catch(function (error) { this.$message.error('網(wǎng)絡(luò)錯誤'); }); },
這里表格就已經(jīng)渲染出來了 ,因為下拉的數(shù)據(jù)要異步去獲取,所以在element提供的下拉事件里面去請求數(shù)據(jù),這里去獲取子級的數(shù)據(jù),并給maps賦值,利用遞歸,把數(shù)據(jù)平鋪、組裝。
//點擊下拉圖標(biāo)異步加載數(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取出對應(yīng)節(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)了,就沒有去深入的挖掘,可能會有問題,但是隔的時間太久了,基本忘光了。
總結(jié)
以上為個人經(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)默認(rèn)選中功能
- Vue+ElementUI踩坑之動態(tài)顯示/隱藏表格的列el-table-column問題
- 使用elementUI的表格table給列添加樣式
- vue基于ElementUI動態(tài)設(shè)置表格高度的3種方法
相關(guān)文章
Vue+Electron打包桌面應(yīng)用(超詳細(xì)完整教程)
這篇文章主要介紹了Vue+Electron打包桌面應(yīng)用超詳細(xì)完整教程,在這大家要記住整個項目的json文件不能有注釋,及時沒報錯也不行,否則運行命令時還是有問題,具體細(xì)節(jié)問題參考下本文詳細(xì)講解2024-02-02詳解無限滾動插件vue-infinite-scroll源碼解析
這篇文章主要介紹了詳解無限滾動插件vue-infinite-scroll源碼解析,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧2019-05-05vue+webpack 打包文件 404 頁面空白的解決方法
下面小編就為大家分享一篇vue+webpack 打包文件 404 頁面空白的解決方法,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧2018-02-02