el-tree 树形结构 怎么添加下级菜单??

element中el-tree组件,无限制增加下级菜单
为避免一次性请求接口返回数据太多,每次请求接口只能返回该层下一级数据,不会返回下级多层数据

<el-tree
                :data="dataSource"
                show-checkbox
                node-key="id"
                ref="tree"
                lazy
                :load="loadNode"
                default-expand-all
                :props="defaultProps"
                class="knowledgePoint"
                :default-expanded-keys="defaultExpandedKeys"
                :default-expand-all="false"
                :render-after-expand="false"
                :expand-on-click-node="false"
            >
                <template slot-scope="{ node, data }">
                    <span class="custom-tree-node">
                        <el-input
                            v-if="data.isEgdit"
                            size="small"
                            class="egditName"
                            ref="inputVal"
                            @keyup.enter.native="updateName(node, data)"
                            @blur="updateName(node, data)"
                            v-model="input"
                            maxlength="20"
                            placeholder="请输入20个字以内标题">
                        </el-input>
                        <span v-else  @click="setName(data)">{{ node.label }}</span>
                        <span>
                            <a @click="append(data)"> 添加 </a>
                            <a style="margin-left: 8px" @click="删除(node, data)"> Delete </a>
                        </span>
                    </span>
                </template>
            </el-tree>

export default {
    data() {
        return {
            defaultProps: {
                children: 'sub_point_list',
                label: 'name',
                isLeaf: (data) => data.has_child === 0
            },
        }
    },
    methods: {
        //添加下级菜单
        append(data) {
            console.log('data', data)
        
            this.$set(data, 'sub_point_list', [])

            const newChild = { id: id++, name: 'testtest', isEgdit: true, sub_point_list: [] }
            if (!data.sub_point_list) {
                data.sub_point_list = []
            }
            data.sub_point_list.push(newChild)
                // 强制更新视图
              this.$forceUpdate();

              // 展开当前节点
              node.expand();
            this.$nextTick(() => {
                this.$refs.inputVal.focus();
            })
            // this.dataSource = [...this.dataSource]
        },
    }
}

当有下级菜单时,点击箭头展开下级菜单,在点击添加按钮,能正常显示输入框添加菜单 如下图

1.jpg

但是没有下级菜单时,即前边没有小箭头,点击添加按钮,数据也能打印出来,但是却显示不出来输入框,如下图
这里出错的原因在哪里呢?

还有就是当有数据时,点击添加按钮 怎么能直接展开下级并显示出输入框呢?现在是只有点击前边的小箭头展开下级后再点击添加按钮才能显示输入框,求教

2.jpg

阅读 1.4k
avatarAI BotBETA

解答

在Element UI的el-tree组件中,当使用lazy属性时,你需要正确地管理节点的加载和展开。对于你的问题,首先要注意的是在添加子节点时,你需要确保父节点被标记为不是叶子节点(即has_child应该不为0),这样它才会显示展开箭头。

此外,当你添加新的子节点时,你需要触发节点的加载,即使你实际上已经直接添加了子节点。这是因为el-treelazy模式下,只有当它认为节点需要加载时(即当节点是叶子节点但又被用户点击展开时),它才会调用load方法。

以下是你需要做的更改:

  1. 确保has_child字段正确设置:在添加子节点之前,确保父节点的has_child字段不为0(或任何表示它不是叶子节点的值)。
  2. 在添加子节点后触发加载:即使你直接添加了子节点,你仍然需要模拟加载过程,以便el-tree知道节点已经加载并且应该展开。
  3. 自动展开新添加的节点:你可以使用this.$refs.tree.setExpandedKeys来展开特定的节点。

以下是修改后的append方法:

append(data) {
  // 确保不是叶子节点
  if (data.has_child === 0) {
    this.$set(data, 'has_child', 1); // 假设1表示有子节点
  }

  // 添加新子节点
  const newChild = { id: id++, name: 'testtest', isEgdit: true, sub_point_list: [] };
  if (!data.sub_point_list) {
    this.$set(data, 'sub_point_list', []);
  }
  data.sub_point_list.push(newChild);

  // 触发节点的加载(即使我们直接添加了子节点)
  this.$refs.tree.load(data);

  // 设置下一个tick以确保DOM已经更新
  this.$nextTick(() => {
    // 展开包含新子节点的节点
    this.$refs.tree.setExpandedKeys([data.id]); // 假设id是唯一的节点键
    this.$refs.inputVal.focus(); // 假设inputVal是对应新节点的输入框引用(这里可能需要调整)
  });
}

注意:上面的代码假设了一些事情,例如id是唯一的节点键,并且inputVal是对应新节点的输入框引用。你可能需要根据你的实际代码进行调整。

另外,关于输入框的引用,由于你是在模板中动态创建的输入框,因此直接使用this.$refs.inputVal可能无法正确引用到新添加的节点的输入框。你可能需要为每个节点创建一个唯一的引用,或者使用其他方法来定位输入框。

3 个回答

不太清楚你使用的 element-ui 还是 element-plus。但是原理是类似的,把你当前添加元素节点的 leaf 设置为 false 就行了。

也就是说在你点击添加按钮的事件上面把对应的 node 节点上面的 isLeaf 属性调整为 false

Element Plus Playground

试试data的has_child属性设为1。若不行可尝试使用el-tree实例方法append 方法来新增节点

参考官方例子

我觉得你先备份一下现有的代码,然后做减法,参考官方例子来没有问题且能满足你的需求。

image.png

    <template>
      <div class="custom-tree-container">
        <div class="block">
          <p>使用 scoped slot</p>
          <el-tree
            :data="dataArr"
            :props="defaultProps"
            :expand-on-click-node="false"
            show-checkbox
            node-key="id"
            default-expand-all
          >
            <span class="custom-tree-node" slot-scope="{ node, data }">
              <el-input
                v-if="data.isEgdit"
                size="small"
                class="egditName"
                v-model="node.name"
                maxlength="20"
                placeholder="请输入20个字以内标题"
              >
              </el-input>

              <span v-else>{{ node.label }}</span>

              <span>
                <el-button type="text" size="mini" @click="() => append(data)">
                  添加
                </el-button>
                <el-button
                  type="text"
                  size="mini"
                  @click="() => remove(node, data)"
                >
                  删除
                </el-button>
              </span>
            </span>
          </el-tree>
        </div>
      </div>
    </template>

    <script>
    let id = 1000;
    const data = [
      {
        id: 1,
        name: "一级 1",
        sub_point_list: [
          {
            id: 4,
            name: "二级 1-1",
            sub_point_list: [
              {
                id: 9,
                name: "三级 1-1-1",
              },
              {
                id: 10,
                name: "三级 1-1-2",
              },
            ],
          },
        ],
      },
      {
        id: 2,
        name: "一级 2",
        sub_point_list: [
          {
            id: 5,
            name: "二级 2-1",
          },
          {
            id: 6,
            name: "二级 2-2",
          },
        ],
      },
    ];

    export default {
      data() {
        return {
          defaultProps: {
            children: "sub_point_list",
            label: "name",
            isLeaf: (data) => data.has_child === 0,
          },
          dataArr: [],
        };
      },

      created() {},

      mounted() {
        this.dataArr = data;
        console.log("🚀 ~ mounted ~ this.dataArr:", this.dataArr);
      },

      methods: {
        append(data) {
          const newChild = {
            id: id++,
            name: "",
            sub_point_list: [],
            isEgdit: true,
          };
          if (!data.sub_point_list) {
            this.$set(data, "sub_point_list", []);
          }
          data.sub_point_list.push(newChild);
        },

        remove(node, data) {
          const parent = node.parent;
          const sub_point_list = parent.data.sub_point_list || parent.data;
          const index = sub_point_list.findIndex((d) => d.id === data.id);
          sub_point_list.splice(index, 1);
        },
      },
    };
    </script>

    <style lang="scss" scoped>
    .egditName {
      width: 150px;
      height: 20px !important;
    }

    ::v-deep.el-input--small .el-input__inner {
      height: 23px !important;
    }
    </style>
撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题
宣传栏