elment-ui的折叠tree表单实现纯前端搜索,展开收起功能

好久没更新博客了~
记录一下本次做的一个很扯的需求
在这里插入图片描述
纯前端去实现这个查询的功能,后台返回的是个数组对象,前端要给他包装成树结构先展示
之后参考代码路径src\views\goods\category\index.vue
需求描述:
搜索输入任何一个关键字,都会展开他的父级,两个栏目都包含了,那么两个父级都展开
先模拟数据,上代码:

categoryList=[
    {
        categoryName:'测试1',
        children:[
            {
                categoryName:'haha1',
                children:[

                ]
            },
        ]
    },{
        categoryName:'测试2',
        children:[
            {
                categoryName:'haha2',
                children:[

                ]
            },
        ]
    },{
        categoryName:'钦佩',
        children:[
            {
                categoryName:'haha2',
                children:[

                ]
            },
        ]
    }
]
<el-table
      v-loading="loading"
      :data="categoryList"
      row-key="categoryId"
      stripe
      :tree-props="{ children: 'children', hasChildren: 'hasChildren' }"
      :expand-row-keys="expandedCategoryIds"
    >
      <el-table-column label="分类名称" prop="categoryName" />
      <el-table-column label="分类等级" prop="level" />
      <el-table-column label="状态" prop="status" :formatter="statusFormat" />
      <el-table-column label="关键字" prop="keywords" />
      <el-table-column label="排序" prop="sortNum" />
      <el-table-column label="创建时间" prop="createTime" width="180" />
      <el-table-column label="操作" min-width="120">
      </el-table-column>
    </el-table>

根据categoryName进行前端模糊搜索,会递归categoryList 里面所有的值,包括children,children的不固定多少级,
比如我所有一个haha,不管是哪一级,都会把,包含这个haha的都展开,别的项目也不会隐藏

<el-input
v-model=“searchText”
placeholder=“请输入搜索关键词”
class=“inpClass”
clearable
@keydown.enter.native=“onSearchChange”

  data() {
    return {
      searchText: "",
        }
      }
    // 处理搜索
    onSearchChange() {
      const expandIds = new Set();
      // 递归搜索函数
      const searchInCategory = (categories, parentIds = []) => {
        if (!categories) return false;

        let hasMatch = false;

        for (const category of categories) {
          const currentIds = [...parentIds, category.categoryId];

          // 检查当前项是否匹配
          const isMatch = category.categoryName
            .toLowerCase()
            .includes(this.searchText.toLowerCase());

          // 递归检查子项
          const hasChildMatch = searchInCategory(category.children, currentIds);

          // 如果当前项或子项匹配,添加所有父级ID到展开集合
          if (isMatch || hasChildMatch) {
            currentIds.forEach((id) => expandIds.add(id));
            hasMatch = true;
          }
        }

        return hasMatch;
      };

      if (this.searchText) {
        searchInCategory(this.categoryList);
        this.expandedCategoryIds = Array.from(expandIds).map(String);
      } else {
        // 确保设置一个新的空数组
        this.expandedCategoryIds = [];
        // 2. 确保在DOM更新后执行收起操作
        this.$nextTick(() => {
          // 3. 遍历所有数据强制收起
          const closeRows = (data) => {
            data.forEach((row) => {
              if (this.$refs.tableRef) {
                this.$refs.tableRef.toggleRowExpansion(row, false);
              }
              if (row.children && row.children.length) {
                closeRows(row.children);
              }
            });
          };
          closeRows(this.categoryList);
        });
      }
    },

在获取列表数据的时候也进行初始化数据

    /** 查询商品分类列表 */
    getList() {
      this.loading = true;
      listCategory(this.queryParams).then((response) => {
        if (response.data) {
          this.categoryList = this.handleTree(response.data, "categoryId");
          this.expandedCategoryIds = [];
          // 2. 确保在DOM更新后执行收起操作
          this.$nextTick(() => {
            // 3. 遍历所有数据强制收起
            const closeRows = (data) => {
              data.forEach((row) => {
                if (this.$refs.tableRef) {
                  this.$refs.tableRef.toggleRowExpansion(row, false);
                }
                if (row.children && row.children.length) {
                  closeRows(row.children);
                }
              });
            };
            closeRows(this.categoryList);
          });
        }
        this.loading = false;
      });
    },

这样就实现纯前端去模拟搜索的效果

注意,后来又遇到一个问题:

<el-table
      v-loading="loading"
      :data="categoryList"
      row-key="categoryId"
      stripe
      :tree-props="{ children: 'children', hasChildren: 'hasChildren' }"
      :expand-row-keys="expandedCategoryIds"
    >
      categoryList 的树形结构里面有categoryId,我直接设置下面这个,也不会展开
    expandedCategoryIds: [758, 753, 748]

因为element-ui会把那个数值自动转换为String一直匹配不上…,后来转值了解决

<think>我们参考ElementUITree树形控件文档,来实现默认展开和默认选中的效果。在ElementUI中,我们可以使用以下属性来实现:1.`default-expand-all`:是否默认展开所有节点,默认值为false,设置为true则展开所有节点。2.`default-expanded-keys`:设置默认展开的节点数组(需要每个节点有一个唯一的key,通过`node-key`属性设置节点key的属性名,然后传入需要展开节点的key数组)3.`default-checked-keys`:设置默认选中的节点数组(同样需要设置node-key,然后传入需要选中的节点的key数组)另外,我们可能还需要使用`props`属性来指定树节点的标签、子节点等字段名。具体实现步骤:1.在模板中,使用`el-tree`组件,并设置`node-key`(必须),然后根据需求设置`default-expand-all`或`default-expanded-keys`和`default-checked-keys`。2.在数据中,我们需要有一个树形结构的数据,并且每个节点要有唯一的标识(比如id)。3.如果使用`default-expanded-keys`和`default-checked-keys`,我们需要在data中定义两个数组:expandedKeys(存放要展开的节点的key)和checkedKeys(存放要选中的节点的key)。注意:如果节点数据中的key字段不是'id',那么node-key需要设置成对应的字段名。下面是一个示例代码:假设我们的节点数据格式如下:```javascriptdata:[{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'}]}]```我们想要默认展开一级1和一级2,默认选中id为5和10的节点。那么,在data中我们可以定义:```javascriptdefaultProps:{children:'children',label:'label'},expandedKeys:[1,2],//要展开的节点的id数组checkedKeys:[5,10]//要选中的节点的id数组```在模板中,我们可以这样写:```html<el-tree:data="data"show-checkboxnode-key="id":default-expanded-keys="expandedKeys":default-checked-keys="checkedKeys":props="defaultProps"></el-tree>```另外,如果希望默认展开所有节点,则可以直接使用`default-expand-all`属性,不需要设置`default-expanded-keys`:```html<el-tree:data="data"show-checkboxnode-key="id"default-expand-all:default-checked-keys="checkedKeys":props="defaultProps"></el-tree>```注意:`default-expand-all`和`default-expanded-keys`同时存在时,`default-expand-all`会覆盖`default-expanded-keys`,即会展开所有节点。如果节点数据是异步加载的,那么可能需要在数据加载完成后,再设置`default-expanded-keys`和`default-checked-keys`。此时,可以使用`this.$nextTick`来确保DOM更新。但是,如果异步加载数据,则可能需要在加载完数据后,调用Tree组件的setCheckedKeys方法来设置选中节点,因为默认值只在初始化时有效。因此,对于异步数据,我们可以在获取数据后,使用:```javascriptthis.$refs.tree.setCheckedKeys(this.checkedKeys);```同时,我们也可能需要手动展开节点:```javascriptthis.$refs.tree.setExpandedKeys(this.expandedKeys);```下面给出一个异步加载数据并设置展开和选中的示例:模板:```html<el-treeref="tree":data="data"show-checkboxnode-key="id":props="defaultProps":load="loadNode"lazy></el-tree>```在数据加载完成后(比如在某个方法中):```javascript//假设在某个方法中获取到了数据,并赋值给了this.data//然后设置选中和展开this.$nextTick(()=>{this.$refs.tree.setExpandedKeys(this.expandedKeys);this.$refs.tree.setCheckedKeys(this.checkedKeys);});```总结:1.同步数据:直接使用`default-expanded-keys`和`default-checked-keys`(或`default-expand-all`)属性。2.异步数据:在数据加载完成后,通过调用`setExpandedKeys`和`setCheckedKeys`方法来实现。根据需求选择合适的方式。参考文献:ElementUI官方文档中Tree树形控件部分[^1]。</think> # Element UI Tree 树形控件的默认展开与默认选中实现Element UI实现 Tree 树形控件的默认展开与默认选中效果非常简单,下面我将详细说明实现方法并提供完整代码示例。 ## 核心属性说明 Element UI 提供了两个重要属性来控制默认行为: 1. **default-expand-all**: 设置为 `true` 时展开所有节点[^1] 2. **default-expanded-keys**: 设置默认要展开的节点 key 数组[^1] 3. **default-checked-keys**: 设置默认要选中的节点 key 数组(需配合 `show-checkbox` 属性)[^1] ## 实现步骤 ### 1. 安装依赖 确保已安装 Element UI: ```bash npm install element-ui --save ``` ### 2. 完整代码示例 ```vue <template> <div class="tree-container"> <el-tree ref="tree" :data="treeData" :props="defaultProps" node-key="id" :default-expand-all="defaultExpandAll" :default-expanded-keys="defaultExpandedKeys" :default-checked-keys="defaultCheckedKeys" show-checkbox ></el-tree> <div class="control-panel"> <el-button @click="expandAll">展开所有</el-button> <el-button @click="collapseAll">折叠所有</el-button> <el-button @click="resetChecked">重置选中</el-button> </div> </div> </template> <script> export default { data() { return { // 树形数据(一般从API获取) treeData: [ { id: 1, label: '一级 1', children: [ { id: 4, label: '二级 1-1' }, { id: 5, label: '二级 1-2' } ] }, { id: 2, label: '一级 2', children: [ { id: 6, label: '二级 2-1' }, { id: 7, label: '二级 2-2', children: [ { id: 8, label: '三级 2-2-1' }, { id: 9, label: '三级 2-2-2' } ] } ] }, { id: 3, label: '一级 3', children: [ { id: 10, label: '二级 3-1' }, { id: 11, label: '二级 3-2' } ] } ], // Element Tree配置 defaultProps: { children: 'children', label: 'label' }, // 默认展开所有节点 defaultExpandAll: false, // 默认展开特定节点(通过id) defaultExpandedKeys: [1, 7], // 默认展开一级1和二级2-2 // 默认选中节点 defaultCheckedKeys: [5, 8, 10] // 默认选中二级1-2、三级2-2-1、二级3-1 }; }, methods: { // 展开所有节点 expandAll() { this.defaultExpandAll = true; }, // 折叠所有节点 collapseAll() { this.defaultExpandAll = false; this.defaultExpandedKeys = []; // 清空展开的节点 this.$refs.tree.setCurrentKey(null); // 取消当前选中节点 }, // 重置选中状态 resetChecked() { this.defaultCheckedKeys = [5, 8, 10]; this.$nextTick(() => { this.$refs.tree.setCheckedKeys([5, 8, 10]); }); } } }; </script> <style> .tree-container { max-width: 600px; margin: 20px auto; padding: 20px; border: 1px solid #ebeef5; border-radius: 4px; box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.1); } .control-panel { margin-top: 20px; text-align: center; } /* 自定义节点样式 */ .el-tree-node { padding: 8px 0; } /* 选中节点样式 */ .el-tree-node.is-checked > .el-tree-node__content { background-color: #ecf5ff; font-weight: bold; } /* 展开/收起图标 */ .el-tree-node__expand-icon { font-size: 16px; padding: 0 6px; } </style> ``` ### 3. 关键点解释 1. **树形数据结构**: - 每个节点需要唯一 `id` - 包含 `label` 属性作为显示文本 - 子节点放在 `children` 属性中 2. **默认展开所有节点**: ```html <el-tree :default-expand-all="true" ...> ``` 3. **默认展开特定节点**: ```js data() { return { defaultExpandedKeys: [1, 7] // 设置要展开的节点id } } ``` 4. **默认选中节点**: ```js data() { return { defaultCheckedKeys: [5, 8, 10] // 设置要选中的节点id } } ``` 5. **动态控制**: ```js // 展开所有节点 this.defaultExpandAll = true; // 折叠所有节点 this.defaultExpandAll = false; this.defaultExpandedKeys = []; // 重置选中 this.$refs.tree.setCheckedKeys([要选中的节点id数组]); ``` ### 4. 使用技巧 1. 如果节点数据是**异步加载**的,可以在数据加载完成后设置默认展开/选中状态: ```js loadData() { axios.get('/api/tree-data').then(res => { this.treeData = res.data; // 数据加载后设置默认状态 this.$nextTick(() => { this.defaultExpandedKeys = [1, 7]; this.defaultCheckedKeys = [5, 8, 10]; }); }); } ``` 2. 在**表单提交**时获取选中的节点: ```js getSelectedNodes() { // 获取选中节点的key数组 const keys = this.$refs.tree.getCheckedKeys(); // 获取选中节点的完整数据 const nodes = this.$refs.tree.getCheckedNodes(); return { keys, nodes }; } ``` 3. 自定义展开图标样式可以使用 CSS: ```css .el-tree-node__expand-icon { color: #ff5918; /* 设置展开图标颜色 */ } ``` ## 常见问题解决 1. **动态更新数据后默认状态失效**: ```js // 在数据更新后重新设置默认状态 updateData() { this.treeData = newData; this.$nextTick(() => { this.$refs.tree.setExpandedKeys(this.defaultExpandedKeys); this.$refs.tree.setCheckedKeys(this.defaultCheckedKeys); }); } ``` 2. **解决节点不可见问题**: 使用 `highlight-current` 属性结合 CSS 提升可见性: ```vue <el-tree highlight-current ...> ``` ```css .el-tree--highlight-current .el-tree-node.is-current > .el-tree-node__content { background-color: #ecf5ff; } ``` 3. **提升性能建议**: 对于大型树结构,使用 `lazy` 属性进行异步加载[^3]: ```vue <el-tree :load="loadNode" lazy ...> ``` Tree 树形控件是实现层级数据展示的理想解决方案,Element UITree 组件提供了丰富的 API 和配置选项[^1]。在实际项目中,可以根据需求结合这些属性灵活控制树的默认状态。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值