web-dev-qa-db-ja.com

v-forループ内のVue.js ref

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

いくつかのリストアイテムをレンダリングし、1つ半秒後にそのうちの1つを強調表示するだけです。しかし、エラーが発生しました:_Uncaught TypeError: _this.$refs.item2.highlight is not a function_
デバッグセッションの後、興味深い事実を見つけました。_v-for_ループ内で定義されたrefはコンポーネントではなく、1つのコンポーネントを持つ配列です。
ロジックとは何ですか、fラッパーとは何ですか?誰もがこのケースに会いますか?誰かがこの行動の説明をすることができますか?
上記のコードは、setTimeout(() => this.$refs.item2[0].highlight(), 1500);で正常に動作します
常に_[0]_を渡す必要がありますか?より良い方法はありますか?助けてください。

8
Lev Khruschev

V-forでrefを使用する場合、コンポーネント/ DOMノードは配列として変数名に直接保存されるため、ref名にインデックス番号を使用する必要はありません。だからあなたはこれを行うことができます:

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

そして、次のようにコンポーネントで参照を使用します。

this.$refs.items[index]

また、refが適切でない場合があり、完全に異なる問題である異なる方法で処理する必要があることに注意してください。ここでフォローできます: https://github.com/vuejs/vue/issues/4952

6

私は同じ問題に直面していました。

Sobolevonが述べたように、$refs.{ref name}の戻り値はv-for refの配列であるため、私の解決策は$refs.{ref name}がデフォルトで1つの項目のみを持つ配列であり、$refs.{ref name}[0].methodToCall()

そして、私の場合はうまくいきます。

2
杨成林

あなたの主な質問を考慮してください: 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>

これで問題が解決します。

0
sobolevn