前言
需求 来自于一些实际的场景
这里 仅仅是一个 样例来实现 这一部分需求
这部分 处理也相对比较简单, 就直接 展示 代码了
1. 节点 增删改查 的实现(一种基于模型的实现, 一种基于 el-tree api 的实现)
2. 保存 el-tree 的 选择状态
3. 保存 el-tree 的 展开状态
样例代码
如下 增删改查两种实现方式, 注释掉的是基于 el-tree 的 api 的使用
<template>
<div>
<div style="width: 20%; float: left;">
(\#-_-)\┯━┯
</div>
<div style="width: 20%; float: left;">
<el-tree
ref="treeRef"
:data="tree.nodeList"
show-checkbox
node-key="id"
:default-checked-keys="tree.defaultCheckedKeys"
:default-expanded-keys="tree.defaultExpandedKeys"
:check-on-click-node="true"
:props="tree.defaultProps"
@node-expand="handleNodeExpand"
@node-collapse="handleNodeCollapse"
/>
</div>
<div style="width: 15%; float: left;">
<span> 新增 </span>
<el-select v-model="newNode.parentId" filterable placeholder="请选择父节点">
<el-option v-for="item in treeNodeList" :key="item.id" :label="item.name" :value="item.id"/>
</el-select>
<el-input placeholder="please input id" v-model="newNode.id">
<template slot="prepend">key</template>
</el-input>
<el-input placeholder="please input name" v-model="newNode.name">
<template slot="prepend">name</template>
</el-input>
<el-button @click="handleNewNode">提交</el-button>
</div>
<div style="width: 15%; float: left;">
<span> 更新 </span>
<el-select v-model="updateNode.id" filterable placeholder="请选择节点">
<el-option v-for="item in treeNodeList" :key="item.id" :label="item.name" :value="item.id"/>
</el-select>
<el-input placeholder="please input name" v-model="updateNode.name">
<template slot="prepend">name</template>
</el-input>
<el-button @click="handleUpdateNode">提交</el-button>
</div>
<div style="width: 15%; float: left;">
<span> 移除 </span>
<el-select v-model="removeNode.id" filterable placeholder="请选择节点">
<el-option v-for="item in treeNodeList" :key="item.id" :label="item.name" :value="item.id"/>
</el-select>
<el-button @click="handleRemoveNode">提交</el-button>
</div>
</div>
</template>
<script>
export default {
name: 'ElTreeCrud',
computed: {
treeNodeList: function () {
let collector = []
this.collectNodeRecursed(this.tree.nodeList, collector)
return collector
}
},
data () {
return {
newNode: {
parentId: 'backend',
id: '',
name: '',
},
updateNode: {
id: 'backend',
name: '',
},
removeNode: {
id: 'backend',
},
tree: {
nodeList: [{
id: 'backend',
name: '后端',
children: [
{
id: 'backend1',
name: '后端1',
children: []
}, {
id: 'backend2',
name: '后端2',
children: []
}
]
}, {
id: 'frontend',
name: '前端',
children: [
{
id: 'frontend1',
name: '前端1',
children: []
}, {
id: 'frontend2',
name: '前端2',
children: []
}
]
}, {
id: 'preprocess',
name: '数据',
children: [
{
id: 'preprocess1',
name: '数据1',
children: []
}, {
id: 'preprocess2',
name: '数据2',
children: []
}
]
}],
defaultExpandedKeys: [],
defaultCheckedKeys: ['backend1', 'preprocess1'],
defaultProps: {
children: 'children',
label: 'name'
}
}
}
},
mounted () {
window.addEventListener('beforeunload', e => this.beforeLeaveFunc(e))
this.tree.defaultExpandedKeys = this.treeNodeList.map(ele => ele.id)
// check if already stored
// todo, if defaultCheckedKeys is not blank at data's init, then specified node will always be checked
let treeNodeCheckedKeysStr = sessionStorage.getItem('treeNodeCheckedKeys')
if (treeNodeCheckedKeysStr) {
this.tree.defaultCheckedKeys = JSON.parse(treeNodeCheckedKeysStr)
// JSON.parse(treeNodeCheckedKeysStr).forEach(ele => this.tree.defaultCheckedKeys.push(ele))
}
let expandedKeysStr = sessionStorage.getItem('expandedKeys')
if (expandedKeysStr) {
this.tree.defaultExpandedKeys = JSON.parse(expandedKeysStr)
}
},
created () {
},
methods: {
// beforeLeaveFunc
beforeLeaveFunc () {
let treeRef = this.$refs.treeRef
let checkedKeys = treeRef.getCheckedKeys()
sessionStorage.removeItem('treeNodeCheckedKeys')
sessionStorage.setItem('treeNodeCheckedKeys_tmp', JSON.stringify(checkedKeys))
if (checkedKeys.length > 0) {
sessionStorage.setItem('treeNodeCheckedKeys', JSON.stringify(checkedKeys))
}
// let treePropRoot = treeRef.root
// let expandedKeys = []
// this.expandedKeys(treePropRoot, expandedKeys)
// sessionStorage.removeItem('expandedKeys')
// sessionStorage.setItem('expandedKeys_tmp', JSON.stringify(expandedKeys))
// if(expandedKeys.length > 0) {
// sessionStorage.setItem('expandedKeys', JSON.stringify(expandedKeys))
// }
},
// curd
handleNewNode () {
if (!this.newNode.id || !this.newNode.name) {
this.$message.error('please input id and name')
return
}
let targetNode = this.lookUpNode(this.tree.nodeList, this.newNode.id)
if (targetNode) {
this.$message.error('update node\'s with id ' + this.newNode.id + ' already exists')
return
}
let newNode = {
id: this.newNode.id,
name: this.newNode.name,
children: []
}
// let treeRef = this.$refs.treeRef
// treeRef.append(newNode, treeRef.getNode(this.newNode.parentId))
// this.$message.success(' add new node ' + this.newNode.name + ' at parentNode ' + this.lookUpNode(this.tree.nodeList, this.newNode.parentId).name + ' success')
let parentNode = this.lookUpNode(this.tree.nodeList, this.newNode.parentId)
parentNode.children.push(newNode)
},
handleUpdateNode () {
if (!this.updateNode.id || !this.updateNode.name) {
this.$message.error('please input id and name')
return
}
let targetNode = this.lookUpNode(this.tree.nodeList, this.updateNode.id)
if (!targetNode) {
this.$message.error('update node\'s with id ' + this.newNode.id + ' does not exists')
return
}
// let treeRef = this.$refs.treeRef
// targetNode.name = this.updateNode.name
// treeRef.updateKeyChildren(this.updateNode.id, targetNode)
targetNode.name = this.updateNode.name
},
handleRemoveNode () {
// let treeRef = this.$refs.treeRef
// let targetNode = this.lookUpNode(this.tree.nodeList, this.removeNode.id)
// if (!targetNode) {
// this.$message.error('update node\'s with id ' + this.removeNode.id + ' does not exists')
// return
// }
// treeRef.remove(targetNode)
let parentNode = this.lookUpParentNode(this.tree.nodeList, null, this.removeNode.parentId)
let idxOfNode = parentNode.children.map(ele => ele.id).indexOf(this.removeNode.id)
parentNode.children.splice(idxOfNode, 1)
},
handleNodeExpand (node, nodeProp, treeNode) {
console.log('handleNodeExpand')
let treeRef = this.$refs.treeRef
let treePropRoot = treeRef.root
let expandedKeys = []
this.expandedKeys(treePropRoot, expandedKeys)
sessionStorage.removeItem('expandedKeys')
sessionStorage.setItem('expandedKeys_tmp', JSON.stringify(expandedKeys))
if (expandedKeys.length > 0) {
sessionStorage.setItem('expandedKeys', JSON.stringify(expandedKeys))
}
},
handleNodeCollapse (node, nodeProp, treeNode) {
// update current node's expand
nodeProp.expanded = false
this.handleNodeExpand(node, nodeProp, treeNode)
},
// assist methods
collectNodeRecursed (nodeList, collector) {
if (!nodeList) {
return null
}
for (let idx in nodeList) {
let childNode = nodeList[idx]
collector.push({id: childNode.id, name: childNode.name})
if (childNode.children) {
this.collectNodeRecursed(childNode.children, collector)
}
}
},
lookUpNode (nodeList, id) {
if (!nodeList) {
return null
}
for (let idx in nodeList) {
let childNode = nodeList[idx]
if (id === childNode.id) {
return childNode
}
if (childNode.children) {
let result = this.lookUpNode(childNode.children, id)
if (result) {
return result
}
}
}
return null
},
lookUpParentNode (nodeList, parentNode, id) {
if (!nodeList) {
return null
}
for (let idx in nodeList) {
let childNode = nodeList[idx]
if (id === childNode.id) {
if (!parentNode) {
parentNode = {
children : this.tree.nodeList
}
}
return parentNode
}
if (childNode.children) {
let result = this.lookUpParentNode(childNode.children, childNode, id)
if (result) {
return result
}
}
}
return null
},
expandedKeys (nodeFromRef, collector) {
if (nodeFromRef.expanded) {
collector.push(nodeFromRef.data.id)
}
// 如果不是 root 节点, 并且没有展开, 不继续处理
if ((nodeFromRef.id !== 0) && (!nodeFromRef.expanded)) {
return
}
if (nodeFromRef.childNodes) {
for (let idx in nodeFromRef.childNodes) {
let childNode = nodeFromRef.childNodes[idx]
this.expandedKeys(childNode, collector)
}
}
}
}
}
</script>
<!-- Add 'scoped' attribute to limit CSS to this component only -->
<style scoped>
</style>
选中状态, 展开状态 的持久化和初始化
刷新页面的时候 保存选中状态
节点展开/收缩的时候 保存展开状态
初始化的时候 初始化 选中状态, 展开状态
展示效果
增删改查的演示
保存 选中状态, 展开状态
我们看一下 sessionStorage 中存放的 expandedKeys, chekcedKeys 的数据, 是没有问题的
刷新之后的状态, 可以看到这里 "后端1" 的状态是没有保存下来的, 这是另外的一个问题
这个我们下一个文章 再来讲解, 需要 调试到 element 的代码
完