javascript v-for 循环中的 Vue.js 引用

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/52086128/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-29 09:49:04  来源:igfitidea点击:

Vue.js ref inside the v-for loop

javascriptvue.jsvuejs2vue-component

提问by Lev Khruschev

I tried to use components inside v-forloop and init the refto future access some methods of these from parent. Here a simplified code of my case:

我尝试在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>

And ListItemcomponent:

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>

It's just renders a few list items and highlights one of them after one and half second. But I got an error: Uncaught TypeError: _this.$refs.item2.highlight is not a function
After debug session I've found an interesting fact: refs defined inside v-forloop are not a components but the arrays with one component.
What is the logic, what is the f wrapper? Does anyone meet this case? Can somebody give the explanation of this behaviour?
Code presented above works fine with setTimeout(() => this.$refs.item2[0].highlight(), 1500);
Must I always pass [0]? Is there exist a better way? Help, please.

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

回答by Sagar Chakravarthy

When using refs with v-for, the component / DOM nodes are stored as an array directly to the variable name so you don't need to use index number in the ref name. So you can do this:

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

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

And use the refs in your component like this:

并在您的组件中使用 refs,如下所示:

this.$refs.items[index]

Also note that the refs may not be in order and would need to be handled in a different way which is a completely different issue. You can follow that here: https://github.com/vuejs/vue/issues/4952

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

回答by u6785157

I had faced the same issue.

我遇到了同样的问题。

As sobolevon mentioned, the returning value of $refs.{ref name}is an array in v-for refs, so my solution is to consider $refs.{ref name}is an array with one item only by default, and write $refs.{ref name}[0].methodToCall().

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

And it works for my case.

它适用于我的情况。

回答by sobolevn

Considering your primary question: https://vuejs.org/v2/api/#ref

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

The documentation says:

文档说:

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

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

But, I would say you are doing it wrong, because using refsare not a good way to go. We have very useful alternatives in vue-land. For example, one can use a prop.

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

That's how a rewritten version of your code would look like:

这就是代码的重写版本的样子:

<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>

And then change your component definition to receive a new prop:

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

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

This will solve your issue.

这将解决您的问题。