JS实现一键展开、折叠所有树节点

本文介绍了如何通过JavaScript实现快速操作,利用按钮控制大数据分析报表中的结构树节点展开和折叠,提高工作效率。

在数据分析报表中,通常会有结构树展开的分析报表。在结构树节点较多的时候,逐个进行展开、折叠等操作时,会比较繁琐、费时间、费手劲;此处示例通过点击按钮的方式,使用js实现一键展开、折叠所有的树节点(不限制层数

1、设置JS事件

在需要事件展开/折叠的单元格/按钮上,添加“超级链接”,分别键入JavaScript事件控制:

展开事件:

// 一般都是匹配到的量几十个几百个,可以正常运行,比如省市区
$('.x-treenode-unexpand').trigger('click');

值得注意的是,如果匹配到的元素太多的话,会比较吃电脑性能,比如几千个(让我遇上了),这时候建议尝试官方文档:

JS实现自定义折叠树节点展开层数- FineReport帮助文档|报表开发|报表使用|学习教程


折叠事件:

$(".x-treenode-expand").attr("class","x-text fr-widget-click x-treenode-unexpand");
$('.fr-widget-click').eq(0).trigger('click');
$(".tntr").css('display','none');


2、效果图

  

如上,就可以实现分析报表中,通过点击按钮的方式,实现一键展开、折叠所有的树节点

<think> 根据用户的问题,需要实现el-tree-v2在清空筛选后折叠所有节点的功能。结合之前的解决方案,我们可以使用操作store.nodesMap的方法来实现折叠所有节点。同时,清空筛选后,树节点会恢复显示,此时折叠所有节点可以提升体验。 实现步骤: 1. 在el-tree-v2上设置ref,以便访问组件实例。 2. 设置node-key属性,确保每个节点有唯一标识。 3. 在清空筛选的方法中,先执行清空筛选的操作(如果使用filter-node-method,则清空筛选条件),然后折叠所有节点。 注意:由于清空筛选后,树会重新渲染,我们需要在清空筛选后立即折叠所有节点。这里可能需要在nextTick中执行折叠操作,以确保DOM更新完成。 示例代码: ```html <template> <div> <el-input v-model="filterText" placeholder="输入关键字进行过滤" @input="onFilterInput" /> <el-button @click="clearFilter">清空筛选并折叠所有节点</el-button> <el-tree-v2 ref="treeRef" :data="data" :props="defaultProps" :filter-node-method="filterNode" node-key="id" height="400" /> </div> </template> <script setup> import { ref, nextTick } from 'vue' const treeRef = ref(null) const filterText = ref('') const data = ref([...]) // 树数据 const defaultProps = { children: 'children', label: 'label', } // 过滤节点方法 const filterNode = (value, data) => { if (!value) return true return data.label.includes(value) } // 监听输入框输入,触发筛选 const onFilterInput = (value) => { treeRef.value?.filter(value) } // 清空筛选并折叠所有节点 const clearFilter = () => { // 清空筛选条件 filterText.value = '' // 触发清空筛选 treeRef.value?.filter('') // 等待筛选清空后,折叠所有节点 nextTick(() => { collapseAllNodes() }) } // 折叠所有节点 const collapseAllNodes = () => { const tree = treeRef.value if (!tree) return // 获取所有节点 const nodesMap = tree.store.nodesMap // 遍历所有节点并折叠 for (const key in nodesMap) { if (Object.prototype.hasOwnProperty.call(nodesMap, key)) { // 设置节点为折叠状态 // 注意:根节点可能没有expanded属性,需要判断 if (nodesMap[key].expanded !== undefined) { nodesMap[key].expanded = false } } } } </script> ``` ### 关键点说明: 1. **清空筛选**:将绑定输入框的`filterText`置空,并调用`treeRef.value.filter('')`来清空筛选条件。 2. **折叠时机**:在清空筛选后,使用`nextTick`确保树已经更新完成,然后再折叠所有节点。 3. **折叠方法**:遍历`store.nodesMap`,将每个节点的`expanded`属性设为`false`(注意排除根节点,因为根节点可能没有`expanded`属性)。 ### 注意事项: - 如果树节点数据量很大,折叠操作可能会造成短暂卡顿,可以考虑使用防抖或异步处理。 - 如果树使用了懒加载,需要确保在折叠操作时,懒加载的节点已经加载完成(否则可能无法折叠)。 ### 相关问题: 1. 如何在清空筛选后保持某些节点的展开状态? 可以记录当前展开的节点,在清空筛选后重新展开这些节点。 2. 如何只折叠特定层级的节点? 在遍历节点时,可以通过节点的`level`属性判断层级,只折叠满足条件的节点。 3. 如何避免折叠操作影响懒加载节点? 在懒加载完成后再执行折叠操作,或者使用递归折叠方法,确保子节点加载完成后再折叠。 4. 如何实现展开/折叠切换按钮? 添加一个状态变量,记录当前是展开还是折叠状态,根据状态执行相应操作。 5. 折叠所有节点后如何保持当前选中节点? 折叠操作不会改变节点的选中状态,选中状态由`current-node-key`或`checked-keys`等属性控制。 [^1]: 通过操作store.nodesMap折叠所有节点 [^4]: 使用node-key和store.nodesMap操作节点状态 </think> # el-tree-v2 清空筛选后折叠所有节点的实现方法 在 Element Plus 的 `el-tree-v2` 组件中,清空筛选后折叠所有节点可以通过以下步骤实现: ## 完整解决方案 ```html <template> <div class="tree-container"> <!-- 搜索框和操作按钮 --> <div class="tree-controls"> <el-input v-model="filterText" placeholder="输入关键字进行过滤" clearable @clear="clearFilterAndCollapse" > <template #prefix> <el-icon><Search /></el-icon> </template> </el-input> <el-button type="primary" plain @click="clearFilterAndCollapse" > 清空筛选并折叠 </el-button> </div> <!-- el-tree-v2 组件 --> <el-tree-v2 ref="treeRef" :data="treeData" :props="defaultProps" :filter-node-method="filterNode" node-key="id" height="500" class="custom-tree" /> </div> </template> <script setup> import { ref, watch } from 'vue'; import { Search } from '@element-plus/icons-vue'; const treeRef = ref(null); const filterText = ref(''); // 示例树数据 const treeData = ref([ { id: 1, label: '一级节点 1', children: [ { id: 4, label: '二级节点 1-1', children: [ { id: 9, label: '三级节点 1-1-1' }, { id: 10, label: '三级节点 1-1-2' }, ] }, ], }, { id: 2, label: '一级节点 2', children: [ { id: 5, label: '二级节点 2-1' }, { id: 6, label: '二级节点 2-2' }, ], }, { id: 3, label: '一级节点 3', children: [ { id: 7, label: '二级节点 3-1' }, { id: 8, label: '二级节点 3-2' }, ], }, ]); const defaultProps = { children: 'children', label: 'label', }; // 节点过滤方法 const filterNode = (value, data) => { if (!value) return true; return data.label.includes(value); }; // 监听搜索文本变化,应用筛选 watch(filterText, (val) => { treeRef.value?.filter(val); }); // 清空筛选并折叠所有节点 const clearFilterAndCollapse = () => { // 清空搜索框 filterText.value = ''; // 应用空筛选条件(使所有节点可见) treeRef.value?.filter(''); // 折叠所有节点 collapseAllNodes(); }; // 折叠所有节点的方法 const collapseAllNodes = () => { const tree = treeRef.value; if (!tree) return; // 获取所有节点 const nodesMap = tree.store.nodesMap; // 遍历所有节点并折叠 for (const key in nodesMap) { if (Object.prototype.hasOwnProperty.call(nodesMap, key)) { // 跳过根节点(没有expanded属性) if (nodesMap[key].expanded !== undefined) { nodesMap[key].expanded = false; } } } }; </script> <style scoped> .tree-container { padding: 20px; border: 1px solid #ebeef5; border-radius: 4px; background-color: #fff; max-width: 600px; margin: 20px auto; } .tree-controls { display: flex; gap: 10px; margin-bottom: 15px; } .custom-tree { margin-top: 15px; border: 1px solid #ebeef5; border-radius: 4px; padding: 10px; } </style> ``` ## 关键实现点说明 1. **清空筛选功能**: ```javascript const clearFilterAndCollapse = () => { filterText.value = ''; // 清空输入框 treeRef.value?.filter(''); // 应用空筛选条件 collapseAllNodes(); // 折叠所有节点 }; ``` 2. **折叠所有节点**: ```javascript const collapseAllNodes = () => { const nodesMap = treeRef.value.store.nodesMap; for (const key in nodesMap) { if (nodesMap[key].expanded !== undefined) { nodesMap[key].expanded = false; // 折叠节点 } } }; ``` 3. **搜索框与树的交互**: - 使用 `filter-node-method` 属性指定过滤方法 - 监听搜索框变化并应用过滤 - 搜索框的 `clearable` 属性允许用户一键清空 ## 注意事项 1. **node-key 属性**:必须设置并确保唯一性,这是操作节点的关键 2. **筛选后状态保留**:筛选不会改变节点展开状态,需要手动折叠 3. **大型树性能**:对于超大型树,建议添加防抖处理: ```javascript import { debounce } from 'lodash-es'; const collapseAllNodes = debounce(() => { // 折叠逻辑 }, 300); ``` 4. **异步数据加载**:如果使用懒加载,确保数据加载完成后再折叠: ```javascript // 示例:等待懒加载完成 await Promise.all(pendingLoadPromises); collapseAllNodes(); ``` ## 替代方案:使用 default-expanded-keys 如果需要更精确控制展开状态,可以使用 `default-expanded-keys` 属性: ```html <el-tree-v2 :default-expanded-keys="expandedKeys" ... /> ``` ```javascript const expandedKeys = ref([]); const clearFilterAndCollapse = () => { filterText.value = ''; treeRef.value?.filter(''); expandedKeys.value = []; // 设置为空数组折叠所有 }; ``` ## 相关问题 1. **如何在折叠所有节点时保持当前选中状态?** 折叠操作不会影响选中状态,选中状态由 `current-node-key` 或 `checked-keys` 单独维护[^4]。 2. **如何实现展开/折叠切换功能?** 添加状态变量控制: ```javascript const isCollapsed = ref(false); const toggleAll = () => { isCollapsed.value = !isCollapsed.value; const expandedState = !isCollapsed.value; for (const key in treeRef.value.store.nodesMap) { const node = treeRef.value.store.nodesMap[key]; if (node.expanded !== undefined) { node.expanded = expandedState; } } }; ``` 3. **如何只折叠特定层级的节点?** 修改折叠方法,添加层级判断: ```javascript const collapseToLevel = (targetLevel = 1) => { for (const key in treeRef.value.store.nodesMap) { const node = treeRef.value.store.nodesMap[key]; if (node.expanded !== undefined && node.level > targetLevel) { node.expanded = false; } } }; ``` 4. **如何在折叠后自动展开第一级节点?** 折叠后设置第一级节点为展开状态: ```javascript const collapseAllButFirstLevel = () => { // 先折叠所有 collapseAllNodes(); // 展开第一级节点 for (const key in treeRef.value.store.nodesMap) { const node = treeRef.value.store.nodesMap[key]; if (node.level === 1) { node.expanded = true; } } }; ``` 5. **清空筛选后如何保持部分节点展开?** 记录需要保持展开的节点ID: ```javascript const importantExpandedKeys = ref([2, 5]); // 需要保持展开的节点ID const clearFilter = () => { filterText.value = ''; treeRef.value?.filter(''); // 折叠除重要节点外的所有节点 for (const key in treeRef.value.store.nodesMap) { const node = treeRef.value.store.nodesMap[key]; if (node.expanded !== undefined) { node.expanded = importantExpandedKeys.value.includes(node.data.id); } } }; ``` [^1]: 通过操作 store.nodesMap 折叠所有节点 [^4]: 使用 node-key 和 store.nodesMap 操作节点状态 [^5]: 树结构和节点操作
评论 1
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值