需求
树的数据是通过异步(懒)加载而来,且要求同级节点只能选择一个,一个常见的应用场景是选择住址,选择了山东省不能同时选择河北省,选择了每个节点,显示完整的从根节点到本节点的路径 。
分析
Element-ui的el-tree的选中是复选框实现,可以选择多个同级节点,如果用它自带的select api(getCheckedNodes
、getCheckedKeys
) 比较复杂且不可靠;因而换了一种实现思路,不用 它的select api,改为自己存储当前节点,tree组件支持node-click
事件,点击node时,存储当前点击的node,只存最后一次点击的node,node对象中可以拿到父node,父node可以拿到它的父node,一级一级上去就可以到根节点。
<el-tree
//对应后端返回数据格式中的key字段名称
node-key="key"
highlight-current
:props="treeProps"
:load="loadChildNode"
lazy
@node-click="handleNodeClick()"
/>
选择地址:{{ lastClickedNodePath.map(node => node.name).join("") }}
data(){
return {
// 搜索住址对话框
treeProps: {
//对应后端返回数据格式中的name字段名称
label: 'name',
isLeaf: 'leaf'
},
//被点击节点到root的完整节点路径
lastClickedNodePath:[]
}
}
//加载子节点
async loadChildNode(node, resolve) {
console.log('加载现住址子节点回调输入参数', node, resolve)
if (node.level === 0) {
console.log('根节点名称', this.curZone.name)
return resolve([{ name: this.curZone.name, key: this.curZone.key }])
}
const code = node.data.key
const { data } = await getChildZonesByCode(code) //发送请求从后端获取数据,数据格式 [{name:"",key:""}]
// 加载村级的下一级时,子节点设置为叶子节点
if (node.level === 2) {
data.map(ele => {
ele.leaf = true
})
}
return resolve(data)
},
//点击节点,获取完整节点路径
handleNodeClick(data,node,component){
this.lastClickedNodePath= this.getNodePath(node, [])
}
/**
* 获取完整的节点路径
*/
getNodePath(selectNode, nodePaths) {
if (!nodePaths) {
nodePaths = []
}
if (!selectNode.data) {
return nodePaths
}
//根节点代码
const ROOT_NODE_CODE = '0'
if (selectNode.data.value === ROOT_NODE_CODE) {
return nodePaths
}
//将元素添加到头部
nodePaths.unshift({...selectNode.data})
if (selectNode.parent) {
return this.getNodePath(selectNode.parent, nodePaths)
}
return nodePaths
},
回显/还原初始状态
上边的地址选择是在对话框中,要求每次打开选择框,只显示根节点,没找到好办法,一个偏hack的方法是,每次打开对话框,重新渲染。
<el-tree
v-if="digVisible"
/>