You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Vue递归组件数据变更后视图不显示问题排查

Vue递归组件修改二维数组后视图不更新的解决方法

问题根源

  • 违反props单向数据流规则:子组件直接修改传入的dir props,Vue中props是父向子单向传递的,子组件直接修改会导致更新无法同步到父组件,也触发不了响应式更新。
  • Vue2数组响应式局限:直接通过索引修改数组元素(比如this.dir[0][0] = !this.dir[0][0]),Vue2的响应式系统无法检测到这种操作,自然不会触发视图更新。

解决步骤

1. 子组件通过事件通知父组件更新数据

子组件不再直接修改dir,而是通过$emit触发父组件的方法,由父组件负责更新数据,严格遵循单向数据流规则。

2. 使用Vue.set触发数组响应式更新

父组件中更新二维数组时,用this.$set(或Vue.set)修改数组元素,这样Vue就能检测到变化并同步更新视图。

修改后的完整代码

<html>
  <body>
    <script src="https://cdn.jsdelivr.net/npm/vue@2.5.16/dist/vue.js"></script>
    <div class="container">
      <h4>
        Vue.js Expandable Tree Menu<br />
        <small>(Recursive Components)</small>
      </h4>
      <div id="app">
        <tree-menu :nodes="tree.nodes" :depth="0" :label="tree.label" :dir="dir" @toggle="handleToggle"></tree-menu>
      </div>
    </div>

    <script>
      let tree = {
        label: "root",
        nodes: [
          {
            label: "item1",
            nodes: [
              {
                label: "item1.1",
              },
              {
                label: "item1.2",
                nodes: [
                  {
                    label: "item1.2.1",
                  },
                ],
              },
            ],
          },
          {
            label: "item2",
          },
        ],
      };

      Vue.component("tree-menu", {
        props: ["nodes", "label", "depth", "dir"],
        template: `
    <div >
    <div class="label-wrapper" @click="toggleChildren">
      <div :style="indent" :class="labelClasses">
        <i v-if="nodes" class="fa" :class="iconClasses"></i>
        {{ label }}
      </div>
    </div>
    <tree-menu
      v-if="dir[0][0]"
      v-for="node in nodes"
      :nodes="node.nodes"
      :label="node.label"
      :depth="depth + 1"
      :dir="dir"
      @toggle="handleToggle"
    >
    </tree-menu>
  </div>`,

        data() {
          return {
            showChildren: false,
          };
        },
        computed: {
          iconClasses() {
            return {
              "fa-plus-square-o": !this.showChildren,
              "fa-minus-square-o": this.showChildren,
            };
          },
          labelClasses() {
            return { "has-children": this.nodes };
          },
          indent() {
            return { transform: `translate(${this.depth * 50}px)` };
          },
        },
        methods: {
          toggleChildren() {
            // 触发父组件的toggle事件,传递要修改的数组索引
            this.$emit('toggle', 0, 0);
            this.showChildren = !this.showChildren;
          },
          handleToggle(row, col) {
            // 向上传递事件,确保所有层级的点击都能通知到父组件
            this.$emit('toggle', row, col);
          }
        },
      });

      new Vue({
        el: "#app",
        data: {
          tree,
          dir: [
            [1, 1, 1, 1, 1],
            [0, 0, 0, 0, 0],
            [0, 0, 0, 0, 0],
            [0, 0, 0, 0, 0],
          ],
        },
        methods: {
          handleToggle(row, col) {
            // 使用$set修改二维数组元素,触发响应式更新
            const newValue = !this.dir[row][col];
            this.$set(this.dir[row], col, newValue);
            alert(newValue);
          }
        }
      });
    </script>
    <style>
      body {
        font-family: "Open Sans", sans-serif;
        font-size: 18px;
        font-weight: 300;
        line-height: 1em;
      }

      .container {
        width: 300px;
        margin: 0 auto;
      }

      .tree-menu {
        .label-wrapper {
          padding-bottom: 10px;
          margin-bottom: 10px;
          border-bottom: 1px solid #ccc;
          .has-children {
            cursor: pointer;
          }
        }
      }
    </style>
  </body>
</html>

关键修改说明

  • 子组件的toggleChildren方法不再直接修改dir,而是通过$emit把修改需求传递给父组件。
  • 父组件用this.$set修改二维数组元素,确保Vue能检测到变化并更新视图。
  • 递归的子组件绑定@toggle事件并向上传递,保证所有层级的点击操作都能触发父组件的数据更新。

注:如果你的需求是让每个节点对应dir中不同的状态,而非所有节点共用dir[0][0],可以在触发事件时传递当前节点对应的索引,让每个节点控制自身的显示状态,这部分可根据实际需求调整。

内容的提问来源于stack exchange,提问作者artur nowakowski

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.13 16:35:50