ハマったのでメモしておきます。
利用した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()
この部分、$refs
がundefined
になる問題。
$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() }) }
リンク