Vue使用el-tree 懒加载进行增删改查
关于vue的树形展示 使用到项目:以树的形式异步展现
效果图先放:
找到element-ui的官方文档,el-tree。(地址:https://element.eleme.cn/#/zh-CN/component/tree )
项目需求:以懒加载的形式展示,目录根据需求需要有新增 编辑 删除 操作以及操作后的刷新树结构
那我们现在开始吧
一、
懒加载:Tree的懒加载,用一个属性控制:lazy。使用lazy,就要使用load来加载数据进行渲染树
原理:初始化触发load函数先加载初始数据,通过点击某个节点,触发load函数,来加载这个节点下的子节点。
优点:适合数据量比较大的时候,对部分节点刷新也比较友好
二、
自定义节点:节点后添加操作按钮
简单例子官网上就有示例
**
主要讲讲更新节点
**
当对节点进行编辑、删除时,需要更新树,只需更新节点,不必更新全部的树即可。
原理:更新节点,其实更新的是该节点的子节点,不包括本节点。删除该节点的子节点,重新请求数据获取本节点的子节点数据进行重新渲染。
// refreshNode:要刷新的节点;newNodeData:新的子节点数据
refreshNode.splice(0, refreshNode.length);
refreshNode.doCreateChildren(newNodeData);
理解一下:
1>.方法node-click调用函数menuNodeClick,记录点击的节点信息,对节点操作前,必然先点击选中某个节点。此函数监听点击节点事件,只要点击了节点,就触发:
menuNodeClick(data, node, treeNode) {
this.selectNodeData = data
this.selectNode = node
}
2>.节点操作后刷新节点即可,通过不同场景可以选择刷新本节点(node)还是刷新本节点的父节点(node.parent):
/**
* 刷新节点数据
* @node [node/Object]: 刷新的节点node,刷新node以下的所有节点
* @type [String]: node的类型,'node'表示node是树的节点信息Node;'data'表示node是树节点信息中的data数据
*/
refreshTreeNode(node, type) {
let refreshNode;
// 拿到要更新节点的子节点
if(type === 'node') {
refreshNode = node.childNodes
}else if(type === 'data') {
let getNode = this.$refs.tree.getNode(node)
refreshNode = getNode.childNodes
}
// 删除原有的子节点
refreshNode.splice(0, refreshNode.length);
//重新请求数据,更新节点
this.requestTreeNode(node)
}
3.选择框checkBox:
如果懒加载中,有选择框,需要将有选择框的数据加载出来,然后通过属性default-checked-keys来勾选,通过default-expanded-keys设置展开的节点。
4.单选:
如果在懒加载中,有单选项,则设置选中即可:
// 设置当前节点选中
this.$refs.tree.setCurrentKey(
this.selectNodeData[this.nodeKey]
)
不管是单选还是多选,在第一次加载时,后台要给的,不只是选中信息,还需要选中节点所在分支的所有节点信息,赋值给default-expanded-keys以便可使节点所在分支从上到选择项都展开。但往往,后台可能给的,只是选中值的信息,这就要前端自己封装数据,获取需要展开的分支信息。根据数据格式不同,用不同的方法
1)树形单层数据格式:
[
{...},
{...},
{...}
]
这种格式的数据,【点击一层,加载一层】、【点击一层,加载该点击层的多层子节点】两种情况都可以满足。第一种不需要进行数据处理;第二种情况,需要在每条数据中注入一个字段,用来关联父子节点,然后将数据封装处理成el-tree所需要的格式,用一个递归函数整合数据(假设关联字段为parentId,nodeKey为id,树的子节点字段为children,需要加载id为’N’的多层子节点)(注:递归函数会影响性能,谨慎使用)
2).多层数据(假设子节点的属性名是children)
[
{
...,
children: [
{
...,
children: [
{
...,
children: [...],
},
{
...,
children: [...],
}
]
},
{
...,
children: [
{
...,
children: [...],
}
]
}
]
}
]
这种格式的数据,单层、多层都可以满足,不需要做处理。
选中值整合并展开选中值所在的树:多层数据可由后台给出选中节点所在的整个分支的值,赋给default-expanded-keys进行展开。也可以自己做筛选,写一个递归函数,将多层数据循环,找到选中值的节点的分支来设置展开(假设nodeKey为id,树的子节点字段为children,需要展开id为’N’的节点所在的整个分支)
懒加载示例:
HTML控件:
<el-tree
:data="treeData"
:props="defaultProps"
:load="loadNodeTree"
@node-click="handleNodeClick"
lazy
:expand-on-click-node="false"
:default-expanded-keys="['1']"
node-key="id"
:highlight-current="true"
>
<span class="custom-tree-node" slot-scope="{ node, data }">
<span class="treeLeft">{{ node.label }}</span>
<span class="treeRight">
<i
v-if="node.level === 1"
@click="() => appendNode(node, data)"
class="el-icon-plus"
style="color: blue"
></i>
<!--增加分组-->
<!-- 根节点不需要删除和重命名 -->
<i
v-if="data.id !== 0"
@click="() => deleteNode(node, data)"
class="el-icon-delete"
style="color: red"
></i>
<!--删除分组-->
<i
v-if="data.id !== 0"
@click="() => editNode(node, data)"
class="el-icon-edit"
style="color: blue"
></i>
<!--重命名分组-->
</span>
</span>
</el-tree>
vue:
data里面定义变量
// 树形菜单
treeData: [], // 树节点
defaultProps: { // 修改el-tree默认data数组参数
children: 'children',
label: 'name',
id: 'id',
parentId: 'parentId',
isLeaf: 'leaf' // 指定节点是否为叶子节点,仅在指定了 lazy 属性的情况下生效
},
methods:
加载树形菜单部分
// 加载 树数据
loadNodeTree(node, resolve) {
const that = this
if (node.level === 0) {
that.loadtreeData(node, resolve)
} else if (node.level === 1) {
that.getChildByList(node, resolve)
}
},
// 获取loadtreeData 就是父节点数据,getChildByList就是异步获取子节点数据
loadtreeData(nodeData, resolve) {
const dataType = {
pageIndex: 1,
pageSize: 100000
}
getAlltype(dataType)
.then(res => {
const rootChildren = []
if (res.code === 200) {
const data = res.data.list
data.map(item => {
rootChildren.push({
name: item.typeName,
parentId: '',
id: item.id,
leaf: false,
children: []
})
})
//如果resolve有内容就是懒加载走查询 否则走的是修改
if (resolve) {
resolve(rootChildren)
} else {
nodeData.childNodes = []
nodeData.doCreateChildren(rootChildren)
}
} else {
resolve([])
}
})
},
// 获取子节点请求
getChildByList(nodeData, resolve) {
var _parentID = nodeData.data.id
const typeSpec = {
typeId: _parentID,
pageIndex: 1,
pageSize: 100000
}
getAlltypeSpec(typeSpec).then(res => {
const rootChildren = []
if (res.code === 200) {
const data = res.data.list
data.map(item => {
rootChildren.push({
name: item.description,
parentId: item.typeId,
id: item.id,
leaf: true,
children: []
})
})
if (resolve) {
resolve(rootChildren)
} else {
nodeData.childNodes = []
nodeData.doCreateChildren(rootChildren)
}
} else {
return false
}
}).catch(err => {
console.log(err)
})
},
// 节点点击事件
handleNodeClick(data, node) {
this.addnode = node
this.adddata = data
if (node.level === 1) {
this.queryForm.typeId = node.data.id
this.queryForm.typeSpecId = ''
} else if (node.level === 2) {
this.queryForm.typeId = node.data.parentId
this.queryForm.typeSpecId = node.data.id
}
this.query()
},
节点操作:增加节点 修改节点 删除节点 (操作自己节点要传父节点信息才能找到自己当前节点,操作子节点就传当前节点 结论:父节点操作子节点)
// 树节点增加 类型规格
appendNode(node, data) {
this.addTypesSpec = {
typeName: node.data.name,
typeId: node.data.id
}
this.createTypesSpecDialog = true
},
// 树类型修改
editNode(node, data) {
const typeId = node.data.parentId
// 一级 类型
if (node.level === 1) {
this.editTypesDialog = true
this.editTypes = {
id: node.data.id,
typeName: node.data.name
}
} else {
this.editTypesSpecDialog = true
this.getSelectTypes()
// this.editTypesSpec = Object.assign({}, node.data)
this.editTypesSpec = {
typeId: typeId,
id: node.data.id,
description: node.data.name
}
}
},
// 树类型删除
deleteNode(node, data) {
// 一级 类型
if (node.level === 1) {
this.$msgbox.confirm('此操作将删除资产类型数据, 是否继续?', '删除提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning'
}).then(() => {
typeDel(node.data.id).then(
resp => {
this.$message('删除成功')
this.query()
this.loadNodeTree(node.parent)
},
err => {
console.log('err', err)
}
)
}).catch(() => {
this.$message.error('已取消')
})
} else {
this.$msgbox.confirm('此操作将删除资产类型规格数据, 是否继续?', '删除提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning'
}).then(() => {
typeSpecDel(node.data.id).then(
resp => {
this.loadNodeTree(node.parent)
this.$message('删除成功')
this.query()
},
err => {
console.log('err', err)
}
)
}).catch(() => {
this.$message.error('已取消')
})
}
},
节点触发之后显示弹框 走正常的弹框增加修改删除操作,只不过在提交后台请求返回操作成功之后需要再一次加载树形结构 所以在这里再一次调用加载树形方法,传的node 当触发点击树形的时候可以保存一下,我的是handleNodeClick这个方法 不管点击修改 增加还是删除都保存下点击的node
this.$message('编辑成功')
this.loadNodeTree(this.addnode.parent)
1.设置展开和收缩
if (!node.expanded) {
node.expand();
}else {
node.collapse();
}
2.获取父节点
node.parent
看得懂的就看吧 代码可以优化 但是最近没啥时间 看不懂的能清楚这个逻辑也行啊 下次见
更多推荐
所有评论(0)