Vue3 v-for内でrel属性を使用する

個人開発したアプリの宣伝
目的地が設定できる手帳のような使い心地のTODOアプリを公開しています。
Todo with Location

Todo with Location

  • Yoshiko Ichikawa
  • Productivity
  • Free

スポンサードリンク

ハマったのでメモしておきます。

利用したVueはCDNの

<script src="https://cdn.jsdelivr.net/npm/vue@3.0.0/dist/vue.global.js"></script>

v-for内にrel属性を配置すると$refsに配列で参照できることを期待したんだけどうまく行かなかった。

<tr v-for="(item, index) in items">
  <td>
    <span v-if="!item.editable" @click="edit(item, index)">{{ item.name }}</span>
    <input v-show="item.editable" v-model="item.name" ref="item">
  </td>
</tr>

v-showなのでレンダリング + display:noneなり、DOM上では同名の複数のref属性が定義されていることになっている。

やりたいことはloopで表示したitemをクリックすると、autofocusした入力フォームが表示されるという仕様。

Vueで以下のように記述しても色んな原因で動かなかった。

edit: function(item, index){
  item.editable = true
  this.$nextTick( function() {
    this.$refs.item[index].focus()
   })
}


$refsが参照できない問題

this.$refs.item[index].focus()

この部分、$refsundefinedになる問題。

$nextTickの無名関数内ではthisの参照がwindowオブジェクトになるので、DOM更新前にrefsの参照を受けておけばよい。

edit: function(item, index){
  item.editable = true
  refs = this.$refs
  this.$nextTick( function() {
    refs.item[index].focus()
   })
}

これで解決と思いきや、まだまだitem[index]undefinedになる笑

ref属性が最後の要素のみ参照される問題

試しにconsole.log(refs)を出力してみたら、itemが配列とならず最後のrel属性がついた要素のみ参照している模様。

ググれども原因は分からず、rel属性をユニークな名前をつける方針でいく方法に舵を取る。

<input v-show="item.editable" v-model="item.name" ref="`item${index}`">

単純に変数埋め込みじゃ、こうなるのでうまくいかない笑

Proxy {`item${index}`: input}


v-bindでloopインデックスを埋め込む
<input v-show="item.editable" v-model="item.name" :ref="`item`+index">

これで、item0, item1, ...といったようなloopインデックス付きの属性名となる。


Vueから$refsを特定する

あとはVue側でブラケット記法で$refs要素にアクセスすればよい。

edit: function(item, index){
  item.editable = true
  refs = this.$refs
  this.$nextTick( function() {
    refs.[ "item" + index] .focus()
   })
}