【问题标题】:Vue.js ref inside the v-for loopv-for 循环中的 Vue.js ref
【发布时间】:2019-02-04 18:07:41
【问题描述】:

我尝试在v-for 循环中使用组件并初始化ref 以便将来从父级访问其中的一些方法。这是我案例的简化代码:

<template>
    <div class="hello">
        {{ msg }}
        <ul>
            <list-item 
                v-for="item in items" 
                :key="item.id" 
                :value="item.text" 
                :ref="`item${item.id}`"
            />
        </ul>
    </div>
</template>

<script>
    import ListItem from "./ListItem";
    export default {
        name: "HelloWorld",
        components: {
            ListItem
        },
        data() {
            return {
                msg: "Welcome to Your Vue.js App",
                items: [
                    { id: 1, text: "foo" },
                    { id: 2, text: "bar" },
                    { id: 3, text: "baz" },
                    { id: 4, text: "foobar" }
                ]
            };
        },
        mounted() {
            setTimeout(() => this.$refs.item2.highlight(), 1500);
        }
    };
</script>

还有ListItem组件:

<template>
    <li v-bind:class="{ highlight: isHighlighted }">
        {{value}}
    </li>
</template>

<script>
    export default {
        name: "list-item",
        props: ["value"],
        data() {
            return {
                isHighlighted: false
            };
        },
        methods: {
            highlight() {
                this.isHighlighted = !this.isHighlighted;
            }
        }
    };
</script>

<!-- Add "scoped" attribute to limit CSS to this component only -->
<style scoped>
    .highlight {
        color: red;
    }
</style>

它只是呈现一些列表项并在一秒半后突出显示其中一个。但我收到一个错误:Uncaught TypeError: _this.$refs.item2.highlight is not a function
在调试会话之后,我发现了一个有趣的事实:在 v-for 循环中定义的引用不是组件,而是具有一个组件的数组。
什么是逻辑,什么是 f 包装器?有人遇到这种情况吗?有人可以解释这种行为吗?
上面显示的代码适用于setTimeout(() =&gt; this.$refs.item2[0].highlight(), 1500);
我必须总是通过[0] 吗?有没有更好的方法?请帮忙。

【问题讨论】:

  • When ref is used together with v-for, the ref you get will be an array containing the child components mirroring the data source. - 是吗?

标签: javascript vue.js vuejs2 vue-component


【解决方案1】:

<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/1.0.21/vue.js"></script>
<div 
   v-for="(item,index) in items"
   :key="index">
<q-popup-proxy
   ref="qDateProxy">
  <q-date
     :data-key="index"
     v-model="item.date"
     @input="CalendarHide(index)"
     mask="MM/DD/YYYY"
    range>
  </q-date>
</q-popup-proxy>
</div>

<script>
CalendarHide (Val) {
      this.$refs ['qDateProxy'] [val].hide()
}
</script>

【讨论】:

  • 您好,欢迎来到 StackOverflow!请提供更多详细信息,说明您的代码的作用以及它为什么回答问题。
【解决方案2】:

我通过使用动态参考解决了订购问题::ref="'myRef' + index"

如果你这样做,Vue 会为 v-for 中的每个项目创建一个新数组,其中唯一的元素将始终是你想要的 ref。然后您可以使用this.$refs['myRef' + index][0] 访问它。

(这在 Vue 3 中不起作用。)

【讨论】:

    【解决方案3】:

    对于 Vue 3 用户:

    在 Vue 3 中,这种用法将不再自动在 $refs 中创建数组。要从单个绑定中检索多个 ref,请将 ref 绑定到提供更多灵活性的函数(这是一项新功能):

    HTML

    <div v-for="item in list" :ref="setItemRef"></div>
    

    使用选项 API:

    export default {
      data() {
        return {
          itemRefs: []
        }
      },
      methods: {
        setItemRef(el) {
          if (el) {
            this.itemRefs.push(el)
          }
        }
      },
      beforeUpdate() {
        this.itemRefs = []
      },
      updated() {
        console.log(this.itemRefs)
      }
    }
    

    使用组合 API:

    import { onBeforeUpdate, onUpdated } from 'vue'
    
    export default {
      setup() {
        let itemRefs = []
        const setItemRef = el => {
          if (el) {
            itemRefs.push(el)
          }
        }
        onBeforeUpdate(() => {
          itemRefs = []
        })
        onUpdated(() => {
          console.log(itemRefs)
        })
        return {
          setItemRef
        }
      }
    }
    

    这里是文档链接:https://v3.vuejs.org/guide/migration/array-refs.html

    【讨论】:

    • 请添加一行关于如何使用 ref 的内容,例如关注一个元素,引用它的 ref
    • @JoelGMathew 这是非常具体的要求,如果您需要帮助,请在 Skype 上联系我:syed_haroon
    【解决方案4】:

    我尝试通过从方法传递索引来处理 v-for 中的引用:

    <div v-for="(item, index) in items" @click="toggle(index)">
      <p ref="someRef"></p>
    </div>
    
    toggle(index) {
      this.refs['someRef'][index].toggle();
    }
    

    但实际上它切换了错误的元素,因为引用的索引没有排序。

    所以我所做的就是将 data 属性添加到 ref 元素:

    <div v-for="(item, index) in items" @click="toggle(index)">
      <p ref="someRef" :data-key="index"></p>
    </div>
    

    现在每个 ref 都有其特定的数据键。并且可以像这样切换:

    toggle(index) {
      const dropdown = this.$refs['someRef'].find(
            el => el.$attrs['data-key'] === index
        );
      dropdown.toggle();
    }
    

    【讨论】:

    【解决方案5】:

    在 v-for 中使用 refs 时,组件/DOM 节点作为数组直接存储到变量名称中,因此您不需要在 ref 名称中使用索引号。所以你可以这样做:

    <list-item
      v-for="item in items" 
      :key="item.id" 
      :value="item.text" 
      ref="items"
    />
    

    并像这样在组件中使用 refs:

    this.$refs.items[index]
    

    另请注意,参考可能不按顺序排列,需要以不同的方式处理,这是一个完全不同的问题。你可以在这里关注:https://github.com/vuejs/vue/issues/4952

    【讨论】:

    • 确实,v-for 循环中的ref 不需要索引。
    • 如何将它与组合 api 一起使用?
    • 请注意,这在 Vue 3 中不起作用
    • 如果你在 v-for 中有多个元素,包括一个输入。你会想要集中输入。您将如何访问此参考解决方案中的特定输入。
    • 编辑我发现了如何,您可以将 .children[index] 添加到末尾以浏览 v-for 内的元素
    【解决方案6】:

    我也遇到过同样的问题。

    正如sobolevon所说,$refs.{ref name}的返回值是v-for refs中的一个数组,所以我的解决方案是认为$refs.{ref name}是一个默认只有一项的数组,写成$refs.{ref name}[0].methodToCall()

    它适用于我的情况。

    【讨论】:

      【解决方案7】:

      考虑您的主要问题:https://vuejs.org/v2/api/#ref

      文档说:

      当ref和v-for一起使用时,得到的ref是一个数组,包含镜像数据源的子组件。

      但是,我会说你做错了,因为使用refs 不是一个好方法。我们在vue-land 中有非常有用的替代方案。例如,可以使用prop

      这就是重写后的代码的样子:

      <template>
          <div class="hello">
              {{ msg }}
              <ul>
                  <list-item 
                      v-for="item in items" 
                      :key="item.id" 
                      :value="item.text" 
                      :isHighlighed="item.isHighlighed"
                  />
              </ul>
          </div>
      </template>
      
      <script>
          import ListItem from "./ListItem";
          export default {
              name: "HelloWorld",
              components: {
                  ListItem
              },
              data() {
                  return {
                      msg: "Welcome to Your Vue.js App",
                      items: [
                          // We have moved `isHighlighed` falg into the data array:
                          { id: 1, text: "foo", isHighlighed: false },
                          { id: 2, text: "bar", isHighlighed: true },
                          { id: 3, text: "baz", isHighlighed: false },
                          { id: 4, text: "foobar", isHighlighed: false }
                      ]
                  };
              };
          };
      </script>
      

      然后更改您的组件定义以接收新的prop

      <script>
          export default {
              name: "list-item",
              props: ["value", "isHighlighted"]
          };
      </script>
      

      这将解决您的问题。

      【讨论】:

      • 我需要调用子组件的方法,我无法提供真实项目的代码。
      猜你喜欢
      • 2018-01-07
      • 1970-01-01
      • 2020-05-06
      • 2019-03-02
      • 1970-01-01
      • 1970-01-01
      • 2019-04-24
      • 1970-01-01
      • 2019-03-27
      相关资源
      最近更新 更多