当前vue2版本没有在优化,vue3版本更简洁
实现的效果: 其中一个节点展开时,其他节点关闭,一直保持最多只有一个节点是展开的。
需要解决的问题: element-ui 树形懒加载表格自带的节点展开时,默认只有第一次才会触发load函数,之后在重新展开节点时,并不会触发load函数。
实现原理:同一个的节点多次重复操作展开子节点时只触发一次load加载函数。当一个节点的子节点展开时,其他节点的子节点收起,同时新展开的节点都需要触发load函数
手风琴模式: 根据element-ui文档创建树形表格
row-key : 用来优化 Table 的渲染;在使用 reserve-selection 功能与显示树形数据时,该属性是必填的
lazy : 开启懒加载模式
tree-props :指定哪些行是包含子节点
load :绑定节点加载函数
<template>
<el-table ref="multipleTable" :data="list" row-key="id" lazy :load="load" :tree-props="{children: 'children', hasChildren: 'hasChildren'}"></el-table>
</template>
<script>
import { listCategoryfrom } form '@/api/category'
export default {
data() {
return {
listQuery: {
page: 1,
limit: 10
},
list: []
}
},
methods: {
load(tree, treeNode, resolve) {
const newListQuery = JSON.parse(JSON.stringify(this.listQuery))
newListQuery.cid = tree.id
// 动态加载子节点数据
listCategory(newListQuery).then(response => {
this.$nextTick(function() {
this.list.map(item => {
if (item.id != tree.id) {
// 使用手风琴模式 expanded 控制子节点关闭还是开启,loaded设置为false,可以使树形表格每次都能加载
this.$set(this.$refs.multipleTable.store.states.treeData[item.id], 'loading', false)
this.$set(this.$refs.multipleTable.store.states.treeData[item.id], 'loaded', false)
this.$set(this.$refs.multipleTable.store.states.treeData[item.id], 'expanded', false)
}
})
})
resolve(response.data.data.items)
})
},
}
}
</script>
需要显示为手风琴模式,重点的代码是 this.$nextTick() 中的函数:
this.$refs.multipleTable.store.states.treeData 获取所有父节点的状态
重新设置加载状态(这里是加载防止异常所以设置)
this. s e t ( t h i s . set(this. set(this.refs.multipleTable.store.states.treeData[item.id], ‘loading’, false)
重新设置节点未加载(手风琴重点代码,使load函数能够多次触发,解决了load不能多次触发的问题)
this. s e t ( t h i s . set(this. set(this.refs.multipleTable.store.states.treeData[item.id], ‘loaded’, false)
关闭已经打开的子节点 (expanded 为true 表示子节点展开, false 表示子节点关闭)
this. s e t ( t h i s . set(this. set(this.refs.multipleTable.store.states.treeData[item.id], ‘expanded’, false)
安装拖动插件 sortablejs
npm install sortablejs --save
在页面中引入
import Sortable from ‘sortablejs’
<template>
<el-table ref="multipleTable" :data="list" row-key="id" lazy :load="load" :tree-props="{children: 'children', hasChildren: 'hasChildren'}"></el-table>
</template>
<script>
import Sortable from 'sortablejs'
import { listCategoryfrom } form '@/api/category'
export default {
data() {
return {
listQuery: {
page: 1,
limit: 10
},
list: [],
treeDate: {
children: [],
display: true,
expanded: false,
lazy: true,
level: 0,
loaded: false,
loading: false
}
}
},
mounted() {
// 表格拖拽
document.body.ondrop = function(event) {
event.preventDefault();
event.stopPropagation();
}
this.rowDrop()
},
methods: {
load(tree, treeNode, resolve) {
const newListQuery = JSON.parse(JSON.stringify(this.listQuery))
newListQuery.cid = tree.id
// 动态加载子节点数据
listCategory(newListQuery).then(response => {
this.$nextTick(function() {
this.list.map(item => {
if (item.id != tree.id) {
// 使用手风琴模式 expanded 控制子节点关闭还是开启,loaded设置为false,可以使树形表格每次都能加载
this.$set(this.$refs.multipleTable.store.states.treeData[item.id], 'loading', false)
this.$set(this.$refs.multipleTable.store.states.treeData[item.id], 'loaded', false)
this.$set(this.$refs.multipleTable.store.states.treeData[item.id], 'expanded', false)
}
})
})
resolve(response.data.data.items)
})
},
rowDrop() {
// 获取表格节点
const tbody = document.querySelector('.el-table__body-wrapper tbody')
const _this = this
// 插件调用函数
Sortable.create(tbody, {
// 拖拽开始时
onStart({
oldIndex
}) {
_this.list.forEach(item => {
// 重新设置 treeData 的值,让表格行拖动的过程方向图标不会消失(由于重新渲染表格数据,这一行看个人需求是否添加)
_this.$set(_this.$refs.multipleTable.store.states.treeData, item.id, _this.treeDate)
// 置空子节点数据,保证拖拽时只计算一级节点的数量,否则会造成节点拖拽无法正确计算位置。 lazyTreeNodeMap 是存放子节点的数据
_this.$set(_this.$refs.multipleTable.store.states.lazyTreeNodeMap, item.id, [])
})
},
// 拖拽结束
onEnd({
newIndex,
oldIndex
}) {
// newIndex表格数据拖动后数据角标 oldIndex表格数据拖动前数据角标
let from, end
from = _this.list[oldIndex].id
end = _this.list[newIndex].id
// console.log(from, end)
// 排序成功后重新获取数据 _this.list = [] 置空数据强制刷新数据,否则子节点数据无法更新,同时会出现bug ,使子节点出现在原来的位置
// 后台排序,排序成功,重置数据
paixu().then(res => {
_this.list = []
// 重新请求数据渲染
_this.getList()
})
}
})
},
}
}
</script>