Vue.js ref внутри цикла v-for - PullRequest
       12

Vue.js ref внутри цикла v-for

0 голосов
/ 30 августа 2018

Я попытался использовать компоненты внутри цикла 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(() => this.$refs.item2[0].highlight(), 1500);
Должен ли я всегда передавать [0]? Есть ли лучший способ? Помогите, пожалуйста.

Ответы [ 3 ]

0 голосов
/ 27 июня 2019

Я столкнулся с той же проблемой.

Как уже упоминалось, возвращаемое значение $refs.{ref name} - это массив в v-for refs, поэтому мое решение состоит в том, чтобы рассмотреть $refs.{ref name} - это массив с одним элементом только по умолчанию и записать $refs.{ref name}[0].methodToCall().

И это работает для моего случая.

0 голосов
/ 11 июля 2019

При использовании ссылок с v-for узлы компонента / DOM сохраняются в виде массива непосредственно в имени переменной, поэтому вам не нужно использовать номер индекса в имени ссылки. Таким образом, вы можете сделать это:

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

И используйте ссылки в вашем компоненте так:

this.$refs.items[index]

Также обратите внимание, что ссылки могут быть не в порядке и должны обрабатываться другим способом, что является совершенно другой проблемой. Вы можете следить за этим здесь: https://github.com/vuejs/vue/issues/4952

0 голосов
/ 30 августа 2018

Учитывая ваш основной вопрос: https://vuejs.org/v2/api/#ref

В документации сказано:

Когда ref используется вместе с v-for, получаемый вами ref будет массивом, содержащим дочерние компоненты, отражающие источник данных.

Но я бы сказал, что вы делаете это неправильно, потому что использование refs не очень хороший способ. У нас есть очень полезные альтернативы на vue земле. Например, можно использовать 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>

Это решит вашу проблему.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...