vue elementUi+sortable.js實(shí)現(xiàn)嵌套表格拖拽問題
vue elementUi+sortable.js嵌套表格拖拽
首先說下項(xiàng)目需求,一個(gè)多層嵌套的表格,行可以進(jìn)行拖拽排序,但不能跨主級去拖拽,下拉可以異步獲取數(shù)據(jù),考慮了很久,還是用最熟悉的vue+element來做,但是element沒有拖拽排序的功能,所以在此基礎(chǔ)上加入sortable.js去實(shí)現(xiàn)拖拽功能。
后臺返回的排序規(guī)則是 每個(gè)數(shù)據(jù)都帶有3個(gè)屬性 id next prev
用這3個(gè)屬性實(shí)時(shí)的去更新排序
- id表示這一條數(shù)據(jù)的id
- next表示下一條數(shù)據(jù)的id
- prev表示上一條數(shù)據(jù)的id
html部分
data部分
flattArray:[], originalData:[], tableData: [], arr:[], maps:new Map()
我這里定義了四個(gè)數(shù)組和一個(gè)map
flattArray是平鋪的數(shù)據(jù) originalData數(shù)組也是平鋪的數(shù)據(jù)(以防數(shù)據(jù)出錯(cuò),沒有啥實(shí)際用途) tableData是表格渲染的數(shù)據(jù) arr是點(diǎn)擊下拉異步請求的數(shù)據(jù)
maps是tableData改變后去重新渲染數(shù)據(jù)用的
methods部分
首先我定義了一個(gè)方法去深拷貝,這樣改變一個(gè)數(shù)據(jù)的時(shí)候,其他數(shù)據(jù)不會(huì)改變
//深拷貝 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ò)錯(cuò)誤'); } }).catch(function (error) { this.$message.error('網(wǎng)絡(luò)錯(cuò)誤'); }); },
這里表格就已經(jīng)渲染出來了 ,因?yàn)橄吕臄?shù)據(jù)要異步去獲取,所以在element提供的下拉事件里面去請求數(shù)據(jù),這里去獲取子級的數(shù)據(jù),并給maps賦值,利用遞歸,把數(shù)據(jù)平鋪、組裝。
//點(diǎn)擊下拉圖標(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('沒有更多消息了'); } }) },
定義的行拖拽方法,因?yàn)榕判蚴怯玫?個(gè)屬性去排序的,所以有3種情況去考慮
- 一是拖動(dòng)到最上級,這樣prev的值就為空
- 二是拖動(dòng)到最下級,next為空
- 三是正常的拖動(dòng),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] // 移動(dòng)到的位置 const frontObj = _this.originalData[newIndex - 2] //移動(dòng)后位置的上一級 const behindObj = _this.originalData[newIndex] //移動(dòng)后位置的下一級 if(sourceObj.parentId != targetObj.parentId) { _this.$message.error("不支持跨級拖動(dòng),請拖回原來位置") location.reload(); return; } let data = []; if( oldIndex < newIndex ){//向下移動(dòng) //上一級 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 ){//向上移動(dòng) //上一級 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() },
最后再去動(dòng)態(tài)的更新數(shù)據(jù)
refreshLoadTree(parentId) { // 根據(jù)父級id取出對應(yīng)節(jié)點(diǎn)數(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)實(shí)現(xiàn)了,就沒有去深入的挖掘,可能會(huì)有問題,但是隔的時(shí)間太久了,基本忘光了。
總結(jié)
以上為個(gè)人經(jīng)驗(yàn),希望能給大家一個(gè)參考,也希望大家多多支持腳本之家。
- Vue?+?ElementUI表格內(nèi)實(shí)現(xiàn)圖片點(diǎn)擊放大效果的兩種實(shí)現(xiàn)方式
- vue elementUI table表格自定義樣式滾動(dòng)效果
- Vue+ElementUI表格狀態(tài)區(qū)分,row-class-name屬性詳解
- vue+elementui 表格分頁限制最大頁碼數(shù)的操作代碼
- elementui實(shí)現(xiàn)表格(el-table)默認(rèn)選中功能
- Vue+ElementUI踩坑之動(dòng)態(tài)顯示/隱藏表格的列el-table-column問題
- 使用elementUI的表格table給列添加樣式
- vue基于ElementUI動(dòng)態(tài)設(shè)置表格高度的3種方法
相關(guān)文章
vue動(dòng)態(tài)生成dom并且自動(dòng)綁定事件
本篇文章主要介紹了vue動(dòng)態(tài)生成dom并且自動(dòng)綁定事件,具有一定的參考價(jià)值,有興趣的可以了解一下。2017-04-04Vue+Electron打包桌面應(yīng)用(超詳細(xì)完整教程)
這篇文章主要介紹了Vue+Electron打包桌面應(yīng)用超詳細(xì)完整教程,在這大家要記住整個(gè)項(xiàng)目的json文件不能有注釋,及時(shí)沒報(bào)錯(cuò)也不行,否則運(yùn)行命令時(shí)還是有問題,具體細(xì)節(jié)問題參考下本文詳細(xì)講解2024-02-02使用vue3+TS實(shí)現(xiàn)簡易組件庫的全過程
當(dāng)市面上主流的組件庫不能滿足我們業(yè)務(wù)需求的時(shí)候,那么我們就有必要開發(fā)一套屬于自己團(tuán)隊(duì)的組件庫,下面這篇文章主要給大家介紹了如何使用vue3+TS實(shí)現(xiàn)簡易組件庫的相關(guān)資料,需要的朋友可以參考下2022-03-03詳解無限滾動(dòng)插件vue-infinite-scroll源碼解析
這篇文章主要介紹了詳解無限滾動(dòng)插件vue-infinite-scroll源碼解析,小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧2019-05-05vue+webpack 打包文件 404 頁面空白的解決方法
下面小編就為大家分享一篇vue+webpack 打包文件 404 頁面空白的解決方法,具有很好的參考價(jià)值,希望對大家有所幫助。一起跟隨小編過來看看吧2018-02-02