[Vue] 任意のタグにフォーカスする際などに、$refsが最適すぎた件

いきなり結論サンプル

See the Pen
$refsで特定のinputタグにフォーカス
by riotam (@riotam4)
on CodePen.

はじめに

今回、Vue.jsで任意のタグにフォーカスする機能を実装していた際、職場の上司から教えてもらったことがあったので、まとめつつ共有します。
まずは、良くないと指摘されたコードから…

getElementByIdを使った、あまりよくない例

See the Pen
$refsで特定のinputタグにフォーカス(5)
by riotam (@riotam4)
on CodePen.

解説

単純な仕組みです。
ボタンを押すと、focusInputメソッドが発火します。メソッドはこんな感じ。

focusInput() {
    document.getElementById('focusThis').focus();
}

getElementByIdが、そのあとの引数に入っているidを持つ要素を読み込んでいます。

なぜVue.jsでこの方法が良くないか

いくつものコンポーネントで構成されることの多いVue.jsでは、安易にidを指定すること自体が高リスクとのこと。
Vue.jsでは、1つのページがたくさんのファイル(コンポーネント)でできていることも多いので、どうしても見通しが悪くなりがち。
確かに、idがぐちゃぐちゃに書かれてしまったら、狙っていたタグでの挙動が得られなかったときに、原因の究明が大変になりそう。

$refsを使って任意のタグを読み込む

See the Pen
$refsで特定のinputタグにフォーカス
by riotam (@riotam4)
on CodePen.

そこで、$refsでの書き方に変更しました。

focusInput() {
    this.$refs.focusThis.focus();
},
<input ref="focusThis">

メソッドの中身と、タグ内を書き換えただけです。
thisは「new Vueしたオブジェクト」を指します。
$refsとその後ろのfocusThis組み合わせは、HTML側でref=focusThisを指定しているタグを読み込みます。
ちなみに、ワンライナーで書いたら、こんな感じになります。

See the Pen
$refsで特定のinputタグにフォーカス(2)
by riotam (@riotam4)
on CodePen.

$refsで指定したrefが複数あった場合の挙動

getElementByIdの場合は、同じidのタグが複数あった場合、1番目のタグが読み込まれます。
Vue.jsでは、この挙動が問題になると考えられるのですが、$refsは少し違った挙動をします。
今回、inputタグ3つに同じrefをつけて出力してみました。
すると…

TypeError: this.$refs.focusThis.focus is not a function

この様なエラーで返されます。
そんな関数ないとのこと…。

this.$refs.focusThisの中身

console.logでthis.$refs.focusThisを出力してみると…

See the Pen
$refsで特定のinputタグにフォーカス(3)
by riotam (@riotam4)
on CodePen.

(3) [input, input, input]
0: input
1: input
2: input

なんと、同じrefが書かれたタグ達が配列になって格納されている…!!
これで、たくさんのコンポーネントでぐちゃぐちゃになってしまっているVueファイルであっても、安心。
なんせ、全部拾ってくれるので。

キーを指定する

配列として格納されているので、キー指定してやると動作してくれます。1番目を取得したい場合は、

this.$refs.focusThis[0].focus()"

このようにすると良いです。動作を試してみてください。

See the Pen
$refsで特定のinputタグにフォーカス(4)
by riotam (@riotam4)
on CodePen.

まとめ

  • Vue.jsでは安易にidで指定するとカオスになる怖れがある
  • 任意のタグを取得したいなら、idではなくrefでタグを指定して、$refsを使うのがおすすめ
  • refで指定したタグが複数あった場合、配列に格納される便利仕様
  • その際は、キーを忘れずに

PON

PON

30代で、完全未経験から独学でWeb系エンジニアになった人。 前職では、超絶ブラック企業にはまり込んでしまい、年間1200時間の残業をしていたが、娘が生まれたことで我に返って転職を決意。 現在は、大阪にあるベンチャー企業の自社開発プロジェクトで、リードエンジニアとして奮闘中。 主戦場はバックエンドで、Pythonでのデータ分析が武器。 とは言いつつ、SPAのフロントエンドを実装したり、インフラ設計したり、スクラム開発でプロジェクト運営したりするなんでも屋。 いつも、ググってきては誰かが書いてくれた記事を見て開発していたが、もらってばかりでなく世の中に返すこともしたいと思い、技術ブログをはじめる。 妻と1歳になる娘の3人暮らし。 最近は一日一食。 何かご用件がある方は、TwitterのDMからどうぞ。