使用element-ui tree获取子节点全选的父节点的信息

为解决el-tree组件在选中根节点时导致的性能问题,本文介绍了一种优化方案,通过递归遍历获取并仅传输父节点信息,避免了大量数据传输,提升了查询效率。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

使用el-tree来展示机构信息,然后传给后台用来作为查询条件。最初版本是把所有选中的节点都传给后端,后端使用in的方式来查询数据。这就出现一个问题,如果选中的是根节点,就会把整棵树的数据都传给后端,sql执行性能差。

后端提出要求,如果子节点都选中了,就不要传子节点了,只要把父节点的信息传出去。翻烂了element-ui文档,也没找到现成的方法。只能自己写了,具体代码如下(参考了element-ui tree的源码)

getSimpleCheckedNodes(store) {
	const checkedNodes = [];
	const traverse = function(node) {
		const childNodes = node.root ? node.root.childNodes : node.childNodes;
	
		childNodes.forEach(child => {
			if (child.checked) {
				checkedNodes.push(child.data);
			}
			if (child.indeterminate) {
				traverse(child);
			}
		});
	};
	traverse(store)
	return checkedNodes;
}

....
// 调用
getSimpleCheckedNodes(this.$refs.tree.store);// el-tree的ref是tree

希望能帮助到需要的朋友,有用请点赞,嘻嘻:)

<think>在用户的问题中,他们希望找到在el-tree组件中,当子节点被选中时如何实现父节点自动选中的解决方案或代码示例。用户引用了两段内容,但指出这些引用并非他们的真实需求,而是希望参考用户上一次的问题和我的回答。由于这是新对话,没有之前的上下文,但用户提到了“用户上一次的问题”,可能是指在当前对话中之前的问题。然而,在当前对话中,这是用户提出的第一个问题。从用户提供的引用中,虽然他们提到这些引用不是完全符合需求,但可以提取一些线索:-引用[1]提到使用`treeRef1.value!.setChecked(key_id,true,false)`,其中第三个参数`false`表示在设置节点选中状态时,父节点不会因为子节点的选中而被选中。这似乎是与用户需求相反的,因为用户希望子节点选中时父节点自动选中。-引用[2]提到“子节点取消选中,父节点选中效果不变”,并且需要修改node-key。用户的实际需求是:在el-tree中,当子节点被选中时,父节点也自动被选中。这是一种常见的级联选择功能。在el-tree中,这可以通过设置`check-strictly`属性来控制是否严格遵循子关联。默认情况下,el-tree子节点是关联的,即选中子节点会同时选中父节点。但是,有时候因为配置问题或版本差异,可能没有生效。解决方案:1.确认是否使用了正确的props配置,特别是`check-strictly`属性。如果`check-strictly`设置为true,则会断开子关联,因此需要设置为false(默认值)以保持关联。2.使用`node-key`属性指定节点的唯一标识字段。3.如果需要手动控制,可以使用`setCheckedKeys`方法,但要注意子关联的逻辑。根据element-ui(或element-plus)的官方文档,默认情况下,选中子节点会改变父节点的状态(半选或全选),但不会自动选中父节点(当选中一个子节点时,父节点会变成半选状态,而不是全选)。用户希望的是当子节点被选中时,父节点也被自动选中。实际上,在el-tree中,如果希望选中子节点时同时选中父节点,默认行为是:当所有子节点都被选中时,父节点才被自动选中。但用户希望的是:只要有一个子节点被选中,父节点就自动选中。这不属于默认行为,因此需要自定义处理。实现思路:-监听节点的选中事件(`check`事件)。-当某个节点被选中时,获取父节点,并将父节点也设为选中状态。-注意递归,因为父节点可能还有父节点。具体步骤(以Vue.js为例):1.为el-tree设置ref,比如`treeRef`,用于在代码中操作树。2.监听`check`事件,该事件在节点选中状态改变时触发。3.在事件处理函数中:-获取当前被选中的节点(通过`getCheckedNodes`或事件参数)以及当前操作节点的数据-遍历当前操作节点的父节点,逐级向上选中父节点。但是要注意:如果直接设置父节点为选中状态,可能会触发事件循环,因为选中父节点又会触发`check`事件。因此需要小心处理。另一种方法:使用`setCheckedKeys`手动设置选中的key数组。可以在每次节点选中时,将当前选中的所有节点(包括父节点)计算出来,然后设置。然而,el-tree本身提供了自动更新父节点状态的机制(通过`check`事件的数据变化),但不会自动选中父节点(只更新为半选状态)。所以我们需要在事件中手动选中父节点。代码示例(基于element-ui/element-plus):```vue<template><el-treeref="treeRef":data="treeData"show-checkboxnode-key="id":props="defaultProps"@check="handleNodeCheck"></el-tree></template><script>exportdefault{data(){return{treeData:[//树的数据,通常是一个数组,每个节点有id,label,children等字段//示例数据省略],defaultProps:{children:'children',label:'label'}}},methods:{handleNodeCheck(data,checkedStatus){//data:当前点击节点对应的node对象(注意:在element-ui中,第一个参数是节点数据,第二个参数是状态对象)//在element-plus中,@check事件的第一个参数是节点数据,第二个参数是包含checkedKeys,checkedNodes等的一个对象//这里以element-ui的event参数为准:第一个参数是节点数据,第二个参数是状态对象(有checkedKeys,checkedNodes等)//但实际上,element-plus的el-tree的check事件参数为(data:NodeData,status:{checkedNodes,checkedKeys,...})//我们想要当节点被选中时(即checked为true)去选中其父节点//注意:在事件中我们只关心被选中的节点,但实际上在取消选中时可能也要处理父节点的状态,但这里用户需求是选中时自动选中父节点,所以只处理选中情况//获取当前节点的idconstcurrentNode=data;//找到当前节点的父节点(需要借助tree的getNode方法)consttree=this.$refs.treeRef;constnodeInstance=tree.getNode(currentNode);//获取节点实例if(!nodeInstance)return;constparentNode=nodeInstance.parent;//如果父节点存在(不是根节点)if(parentNode&&parentNode.data!==undefined){//判断当前节点是否被选中(注意:事件触发时,节点的选中状态已经改变)//我们可以通过tree的getCheckedKeys方法获取当前选中的所有key,或者通过状态对象//这里使用状态对象:在element-ui中,第二个参数status.checkedKeys包含当前选中的所有keyconstisChecked=checkedStatus.checkedKeys.includes(currentNode.id);if(isChecked){//设置父节点为选中,第三个参数为false表示不选中子节点(因为我们只是要选中父节点,并且避免递归触发)//注意:这里要设置父节点的keytree.setChecked(parentNode.data.id,true,false);}}}}}</script>```注意:上述代码在element-ui中可能有效,但在element-plus中事件参数可能不同。另外,上述方法在每次选中子节点时都会将父节点选中,但这样可能会选中所有的祖先节点吗?不,这里只处理了直接父节点。如果希望递归到最顶层,可以写一个循环:```javascriptletp=nodeInstance.parent;while(p&&p.data!==undefined&&p.data.id!==undefined){//检查父节点是否已经选中,避免重复设置导致事件多次触发if(!this.$refs.treeRef.getCheckedKeys().includes(p.data.id)){this.$refs.treeRef.setChecked(p.data.id,true,false);}p=p.parent;//继续向上处理}```但是要注意,如果树的结构很深,这样递归可能会影响性能,并且要避免循环引用。另外,如果节点被取消选中,是否要取消父节点?用户需求只提到选中时父节点自动选中,但通常逻辑是:当一个父节点的所有子节点都被取消选中时,父节点才会取消选中。所以这里我们只处理选中的情况。最后,需要注意:如果设置了`check-strictly`为true,那么子节点不关联,需要设置为false(默认就是false)或者不设置。如果用户使用的是element-plus,文档中关于el-tree的事件和API类似。请根据实际使用的版本调整。在element-plus中,`@check`事件的第一个参数是节点数据,第二个参数是一个对象,包含:-checkedNodes:当前被选中的节点数组-checkedKeys:当前被选中的key数组-halfCheckedNodes:半选节点数组-halfCheckedKeys:半选key数组因此,上面的代码可以迁移到element-plus。注意事项:1.循环设置父节点时,要确保父节点存在,并且没有设置过(避免重复设置触发事件)。2.使用`setChecked`或`setCheckedKeys`时,第三个参数(deep)设置为false,避免影响子节点。由于用户需求是“当子节点被选中时,父节点自动选中”,所以我们只需要在选中子节点时,将其所有父节点(直到根)都选中即可。最后,因为用户引用了之前的代码,但并没有提供具体版本,这里给出通用方案。如果用户遇到问题,可以根据实际框架版本调整。</think> 在 el-tree 组件中实现子节点选中时父节点自动选中的功能,可以通过以下解决方案实现: ### 解决方案代码 (Vue3 + Element Plus) ```vue <template> <el-tree ref="treeRef" node-key="id" :props="props" :data="treeData" show-checkbox @check="handleNodeCheck" :check-strictly="false" /> </template> <script setup> import { ref } from 'vue'; const treeRef = ref(null); const treeData = ref([ { id: 1, label: '父节点1', children: [ { id: 4, label: '子节点1' }, { id: 5, label: '子节点2' } ] }, { id: 2, label: '父节点2', children: [ { id: 6, label: '子节点3' }, { id: 7, label: '子节点4' } ] } ]); const props = { label: 'label', children: 'children' }; // 核心处理函数 const handleNodeCheck = (nodeObj, status) => { const { checkedNodes, checkedKeys } = status; // 当选中子节点时自动选中父节点 if (nodeObj.children) return; // 当前选中的是父节点则不处理 const parentNode = treeRef.value.getNode(nodeObj).parent; if (parentNode && parentNode.data) { const parentKey = parentNode.data.id; if (checkedKeys.includes(nodeObj.id) && !checkedKeys.includes(parentKey)) { treeRef.value.setChecked(parentKey, true, false); } } }; </script> ``` ### 关键实现逻辑说明: 1. **子关联设置**:`check-strictly="false"` 允许子关系联动(但注意默认行为是选父节点自动选所有子节点,反之不然) 2. **处理节点选中事件**: ```javascript @check="handleNodeCheck" ``` 监听所有节点选中状态变化事件 3. **核心处理逻辑**: ```javascript const handleNodeCheck = (nodeObj, status) => { // 仅处理子节点操作 if (nodeObj.children) return; // 获取父节点引用 const parentNode = treeRef.value.getNode(nodeObj).parent; // 当子节点被选中但父节点未选中时 if (status.checkedKeys.includes(nodeObj.id) && !status.checkedKeys.includes(parentNode.data.id)) { // 设置父节点为选中状态(false参数防止级联选择子节点treeRef.value.setChecked(parentNode.data.id, true, false); } }; ``` 4. **注意事项**: - `setChecked` 第三个参数 `false` 至关重要,防止选择父节点时自动全选子节点 - 使用 `getNode` 获取完整节点信息以便找到父节点 - 通过 `checkedKeys` 判断当前选中状态避免重复触发 ### 实际应用效果: - ✅ 当选中任意子节点时,其直接父节点自动选中 -父节点不会强制选中所有子节点 - ✅ 取消子节点不会影响其他同级子节点状态 - ✅ 选中父节点时不会自动全选子节点 ### 完整功能优化建议: 若需要处理多层级自动选中(如选中子节点时自动选中祖父节点),可添加递归逻辑: ```javascript const checkAllParents = (node) => { const parentNode = treeRef.value.getNode(node).parent; if (parentNode && parentNode.data) { treeRef.value.setChecked(parentNode.data.id, true, false); checkAllParents(parentNode.data); } }; // 在handleNodeCheck中调用 if (status.checkedKeys.includes(nodeObj.id)) { checkAllParents(nodeObj); } ``` [^1]: 引用涉及权限树处理中父节点半选状态的解决方案参考 [^2]: 引用涉及子节点取消选中时父节点状态不变的需求实现
评论 21
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值