Ag Grid树形列表过滤器:如何记住展开/折叠状态
树形列表刷新时保留展开/折叠状态的解决方案
不管你用的是Element UI、Ant Design这类现成组件库,还是自己手写的树形列表,核心思路都是先记录当前展开的节点标识,数据刷新后再把这些标识回传给组件,具体实现分几种情况:
1. 用Element UI Tree组件的情况
- 给Tree组件绑定
expanded-keys属性控制展开节点,同时监听node-expand和node-collapse事件,把展开/折叠的节点key同步到变量(比如expandedKeys)里。 - 刷新数据前先保存当前的
expandedKeys,数据加载完成后直接把这个变量赋值给Tree的expanded-keys。 - 注意:节点的
key必须用后端返回的唯一ID这类稳定标识,别用数组索引,不然数据刷新后匹配不上。
示例代码片段:
<el-tree :data="treeData" :expanded-keys="expandedKeys" @node-expand="handleNodeExpand" @node-collapse="handleNodeCollapse" ></el-tree> <script> export default { data() { return { treeData: [], expandedKeys: [] } }, methods: { handleNodeExpand(data) { if (!this.expandedKeys.includes(data.id)) { this.expandedKeys.push(data.id) } }, handleNodeCollapse(data) { this.expandedKeys = this.expandedKeys.filter(key => key !== data.id) }, async refreshData() { // 保存当前展开状态 const currentExpanded = [...this.expandedKeys] // 加载新数据 this.treeData = await fetchNewData() // 恢复展开状态 this.expandedKeys = currentExpanded } } } </script>
2. 用Ant Design Tree组件的情况
- 思路和Element UI类似,通过
expandedKeys状态管理展开节点,监听onExpand事件更新这个状态。 - 数据刷新后,把保存的
expandedKeys传给组件即可,同样要保证节点key的唯一性。
示例代码片段:
import { Tree } from 'antd'; const MyTree = () => { const [treeData, setTreeData] = useState([]); const [expandedKeys, setExpandedKeys] = useState([]); const handleExpand = (keys) => { setExpandedKeys(keys); }; const refreshData = async () => { const currentExpanded = [...expandedKeys]; const newData = await fetchNewData(); setTreeData(newData); setExpandedKeys(currentExpanded); }; return ( <Tree treeData={treeData} expandedKeys={expandedKeys} onExpand={handleExpand} /> ); };
3. 自己手写树形列表的情况
- 给每个节点分配唯一ID,用
localStorage或者全局状态管理工具(比如Vuex、Redux)存储展开的节点ID列表。 - 渲染节点时,根据存储的ID列表判断是否展开;点击展开/折叠时,更新存储的列表。
示例逻辑:
// 存储展开节点到localStorage const saveExpandedNodes = (keys) => { localStorage.setItem('treeExpandedKeys', JSON.stringify(keys)); }; // 获取保存的展开节点 const getExpandedNodes = () => { const keys = localStorage.getItem('treeExpandedKeys'); return keys ? JSON.parse(keys) : []; }; // 渲染节点时判断展开状态 const renderTreeNode = (node) => { const expandedKeys = getExpandedNodes(); const isExpanded = expandedKeys.includes(node.id); return ( <div className="tree-node"> <div onClick={() => toggleExpand(node.id)}> {isExpanded ? '▼' : '▶'} {node.name} </div> {isExpanded && node.children && node.children.map(child => renderTreeNode(child))} </div> ); }; // 切换展开状态并更新存储 const toggleExpand = (nodeId) => { const expandedKeys = getExpandedNodes(); const newKeys = expandedKeys.includes(nodeId) ? expandedKeys.filter(key => key !== nodeId) : [...expandedKeys, nodeId]; saveExpandedNodes(newKeys); // 触发重新渲染 };
注意事项
- 绝对不要用数组索引作为节点唯一标识,数据刷新后索引会变化,导致展开状态匹配错误。
- 如果过滤后节点有新增或删除,要额外处理:比如删除的节点要从展开列表中移除,新增节点可根据业务需求决定是否自动展开。
内容的提问来源于stack exchange,提问作者khchew
相关产品推荐
相关产品推荐

