4
1

【Vue.js】v-forの中でrefを使用していて、要素を並べ替えたら、$refs配列の順番がずれた問題

Last updated at Posted at 2020-04-29

以下のように v-for の中で ref を使う場合、this.$refs[n] でオブジェクトを取得することができます。


// HogeHogeというコンポーネントを使っていますが、
// nameというメソッドを呼ぶとvalueパラメータで与えられた
// オブジェクトのnameを返すものとします。
<template>
  <ul>
    <li v-for="(item, i) in items" :key="i">
      <hoge-hoge ref="hoge" :value="item" />
      <button @click="test(i)">{{ item.name}}</button>
    </li>
  </ul>
</template>

<script>
  data() {
    return {
      items: [
        { name: 'AAA' },
        { name: 'BBB' },
        { name: 'CCC' }
      ]
    }
  }.
  methods: {
    test(i) {
      console.log(this.$refs.hoge[i].name)
    }
  }
</script>

このコードを実行すると、3つのボタンが表示されます。
AAAというボタンをクリックするとAAAがコンソールログ出力され、BBBというボタンをクリックするとBBBが出力されます。

ここで、プログラムの中で items 配列の要素の順番を入れ替えてみます。

this.item = [
  { name: 'BBB' },
  { name: 'AAA' },
  { name: 'CCC' }
]

ボタンのラベルはこの配列の順番に表示されますが、ボタンをクリックすると、困ったことに異なるnameが出力されることがあります。

refはリアクティブではないため、オブジェクトを再利用する際に、$refsの配列の順番まで面倒を見てくれないのかも知れません。

仕方ないので、こんな感じでこの問題を回避してみました。

<template>
  <ul>
    <li v-for="(item, i) in items" :key="i">
      <hoge-hoge ref="hoge" :value="item" :hoge-key="i" />  // hoge-keyを追加
      <button @click="test(i)">{{ item.name}}</button>
    </li>
  </ul>
</template>

<script>
  import _ from 'lodash'

  data() {
    return {
      items: [
        { name: 'AAA' },
        { name: 'BBB' },
        { name: 'CCC' }
      ]
    }
  }.
  methods: {
    test(i) {
      const hoge = _.find(this.$refs.hoge, (ref) => {
        return Number(_.get(ref, '$attrs.hoge-key', -1)) === i
      })
      if (hoge) {
        console.log(hoge.name)
      }
    }
  }
</script>

HogeHogeオブジェクトに、hoge-key というプロパティを追加して、インデックスの i を代入しておきます。

クリックイベントで、インデックス i を受け取り、this.$refs.hoge 配列の中から、hoge-key プロパティと i が一致するオブジェクトを探します。

hoge-key プロパティの値は、$attrs.hoge-key で取得できましたが、果たして$attrs は公式に使って良いプロパティなのか分からなかったので少々不安ではありますが、一応はこれで動いております。

4
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
4
1