需求
树的数据是通过异步(懒)加载而来,且要求同级节点只能选择一个,一个常见的应用场景是选择住址,选择了山东省不能同时选择河北省,选择了每个节点,显示完整的从根节点到本节点的路径 。
分析
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.keyconst { 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-treev-if="digVisible"
/>