【问题标题】:Why does Vue not update the array order in $ref when using unshift?为什么Vue在使用unshift时不更新$ref中的数组顺序?
【发布时间】:2020-10-20 20:24:14
【问题描述】:

考虑以下示例:

<template>
  <div>
    <button @click="addItem">Add Item</button>
    <h1>Fruits</h1>
    <ul>
      <li
        v-for="(item, index) in items"
        ref="items"
        v-bind:key="item.id"
        @click="logIndex(index)"
      >
        {{ item.name }}
      </li>
    </ul>
  </div>
</template>

<script>
export default {
  name: "Fruits",
  data() {
    return {
      items: [
        { name: "apple", id: 1 },
        { name: "banana", id: 2 },
      ],
    };
  },
  methods: {
    addItem() {
      const nextNumber = Math.max(...this.items.map((x) => x.id)) + 1;
      this.items.unshift({
        name: "peach " + nextNumber,
        id: nextNumber,
      });
      console.log(this.$refs);
      console.log(this.items);
    },
    logIndex(index) {
      console.log(index);
      console.log(this.items[index]);
      console.log(this.$refs.items[index]); //this seems reasonable to assume
      //using the index here would return
      //the correct reference, but maybe not
    },
  },
};
</script>

如果您查看控制台输出,您会注意到 refs 和 item 的顺序不同。单击水果项目将记录该特定项目。您会注意到这些项目是不同的。为什么会这样?裁判的顺序不同是有原因的吗?

这里有一个 CodeSandbox 来测试它View example

一些背景知识:

我今天遇到了这种情况。例如,假设您有一个带有一组子组件的组件。如果您需要访问兄弟组件,您可以从原始组件发出,处理父组件上的事件,然后从父组件访问另一个兄弟组件。我发现如果已添加原始数组,则传递索引并使用它根本不起作用。我能够通过对组件数据使用 .find 和匹配来解决它。

我确实意识到在上述情况下使用 Vuex 或类似方法可能是理想的,但我仍然想知道 this.$refs 是否不会反映基础数据的排序顺序以及为什么会这样所以。

任何解决方法的代码示例都会很有帮助。

【问题讨论】:

    标签: javascript vue.js


    【解决方案1】:

    它没有与您的数据相关联。第一个引用 [0] 将对应于第一个渲染元素,第二个 [1] 将对应于第二个渲染元素,依此类推。

    $refs 仅在组件被渲染后才被填充,并且它们不是响应式的。它仅用作直接操纵儿童的逃生舱。

    Source from the doc

    我同意你关于 vuex 的说法

    【讨论】:

      【解决方案2】:

      这是基于@Michal 提到的link 的解决方法的实际代码示例。

      <template>
        <div>
          <button @click="addItem">Add Item</button>
          <h1>Fruits</h1>
          <ul>
            <li
              v-for="(item, index) in items"
              ref="items"
              v-bind:key="item.id"
              @click="logIndex(index)"
              :data-index="index"
            >
              {{ item.name }}
            </li>
          </ul>
        </div>
      </template>
      
      <script>
      export default {
        name: "Fruits",
        data() {
          return {
            items: [
              { name: "apple", id: 1 },
              { name: "banana", id: 2 },
            ],
          };
        },
        methods: {
          addItem() {
            const nextNumber = Math.max(...this.items.map((x) => x.id)) + 1;
            this.items.unshift({
              name: "peach " + nextNumber,
              id: nextNumber,
            });
            console.log(this.$refs);
            console.log(this.items);
          },
          logIndex(index) {
            console.log(index);
            console.log(this.items[index]);
            console.log(this.$refs.items.find(x => index === parseInt(x.dataset.index)));
          },
        },
      };
      </script>
      

      这个想法是将索引或其他键存储为 DOM 属性,然后在您需要 $ref 时查找它。不理想,但这是建议作为解决方法的最佳想法。理想情况下,最好使用不涉及访问 $refs 的方法。

      至于为什么会发生这种情况,由于性能原因,似乎无法保证顺序。 Vue 简直就是pushes the ref onto the array

       refs[key].push(ref) 
      

      【讨论】:

        【解决方案3】:

        Refs 不是响应式的,refs 的顺序是 not guaranteed to be the same order as your source array

        你可以在线程中找到一些解决方法,但如果你问我,我会选择不同的策略来实现它而不使用 refs

        【讨论】:

        • 感谢 GitHub 链接,我找不到有关此问题的任何信息。是的,遇到这个问题帮助我更好地理解了如何完全避免使用 refs。
        • 我找不到关于这个问题的任何信息是什么意思?那里描述了多种解决方法,人们使用它们来避免这个问题......
        • 我的意思是我无法通过 Google 搜索找到有关此问题的任何信息,这就是我在这里提出问题的原因。 GitHub 链接有解决方法并且很有帮助,因此感谢您提供它。
        • 那么我的回答是否帮助您解决了问题?如果是,请将其标记为答案并投票(我不明白为什么这么多人无法理解...)
        猜你喜欢
        • 2018-03-02
        • 2021-12-31
        • 2019-01-30
        • 2021-12-31
        • 1970-01-01
        • 2019-10-24
        • 2020-11-12
        • 1970-01-01
        • 2021-06-20
        相关资源
        最近更新 更多