【Vue3】ref属性を使ってfocusメソッドで要素にフォーカスする

vue3でWEBアプリを開発している時、ページを開いた時に特定のinput要素へすぐ文字入力ができる環境を作りたくなった。
色々調べてみたところ、vue2ではtemplate内の該当する要素にはref属性を指定し、scriptには$refsを使ってfocusメソッドを使うとのことだった。
ただ、vue3だと勝手が違ってつまづいたので、備忘録的にまとめておく。

## 環境
・vue3(Composition-API）
・VS code

## 結論
templateでは、
・フォーカスさせたいinput要素に「ref」属性を設定する。

scriptでは、
・setup()内でref属性に指定する変数を初期値「ref()」として新規作成する
・関数を作成し、
 「input要素に指定したrefの変数名」.focus();
を記述。

これでref属性を設定した要素タイプの取得と、そこを目印にfocusさせるための関数が完成。
生のJSを書かなくてもしっかりfocusしてくれる。

## 実際のコード
まずは全文掲載。

↓Githubにも公開しているので、必要な方はこちら↓
[https://github.com/tkmn7486/ref-element-vue3.git](https://github.com/tkmn7486/ref-element-vue3.git)

```
<template>
  <div id="app">
    <div class="function-preview">
      <h3>【各変数の中身】</h3>
      <table class="table">
        <tr>
          <th>変数</th>
          <th>中身</th>
        </tr>
        <tr>
          <td>メイン-inputの入力文字</td>
          <td>{{input_word_main}}</td>
        </tr>
        <tr>
          <td>メイン-inputのref</td>
          <td>{{ref_main}}</td>
        </tr>
        <tr>
          <td>サブ-inputの入力文字</td>
          <td>{{input_word_sub}}</td>
        </tr>
        <tr>
          <td>サブ-inputのref</td>
          <td>{{ref_sub}}</td>
        </tr>
      </table>
    </div>

    <!-- メインのinput要素 -->
    <label>メイン：</label><input type="text" v-model="input_word_main" ref="ref_main">
    <br>

    <!-- サブのinput要素 -->
    <label>サブ：</label><input type="text" v-model="input_word_sub" ref="ref_sub">
    <br>
    <br>

    <!-- メインinputにフォーカスさせるボタン -->
    <button class="btn" @click="focusMain()">メインinputにfocus</button>

    <!-- サブinputにフォーカスさせるボタン -->
    <button class="btn" @click="focusSub()">サブinputにfocus</button>
  </div>
</template>

<script>
import {ref} from 'vue'
export default {
  name: 'App',
  setup(){
    let ref_main = ref()
    let ref_sub = ref()

    let input_word_main = ref("")
    let input_word_sub = ref("")

    const focusMain=()=>{
      ref_main.value.focus();
    }

    const focusSub=()=>{
      ref_sub.value.focus();
    }

    return{
      ref_main,
      ref_sub,
      input_word_main,
      input_word_sub,
      focusMain,
      focusSub
    }
  }
}
</script>

<style>
#app {
  font-family: Avenir, Helvetica, Arial, sans-serif;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  text-align: center;
  color: #2c3e50;
  margin-top: 60px;
}

.table{
  margin: 0 auto;
  padding: 10px;
}

.function-preview{
  border: 1px solid;
  margin: 20px;
}

.btn{
  margin: 20px;
}
</style>

```

今回は切り替えている様子がわかりやすいように、メインinputとサブinputを設け、それぞれにref属性を指定して切り替えができるようにした。


### 解説
各部位の解説をしていく。

まずはtemplate内の
```
<div class="function-preview">
...
```
　これは入力文字やref属性を設定した要素の情報がちゃんと変数に格納されているかを視認できるようにするための機能なので、ここは飛ばして良い。


一番大事なところは29行目
```
<!-- メインのinput要素 -->
<label>メイン：</label><input type="text" v-model="input_word_main" ref="ref_main">
```
v-model="input_word_main"で、inputに入力された情報をリアルタイムでinput_word_main変数に格納する。
ref="ref_main"で、「input」というHTML上での要素のタイプをref_main変数に送っている。
ここが大事。

JavaScriptでinputにフォーカスをさせたい場合は、
```
document.getElementById.[inputのID].focus();
```
というコードを書く。
.focus()以前のコード、これはinputの要素タイプを取得する処理である。
つまり、focusメソッドへ「HTML上での要素タイプを渡すこと」が実行に際しての必須事項であることになる。
だから、今回vue3でfocusメソッドを使用する際にも、ref属性を設定することでHTML上での要素タイプ（inputの場合は”HTMLInputElement”という形で取得される）を変数に渡すことが求められる。

話を戻す。
template内のinputへ無事にref属性を付与できたら、scriptに移る。
57行目に以下のように関数を定義している。
```
    const focusMain=()=>{
      ref_main.value.focus();
    }
```
これはメインのinput要素にフォーカスさせるためのコードだ。
今回はref_main変数にinputの要素タイプが格納されているので、ref_main.value.focus()という書き方になった。

ちなみに、ref_main変数に.valueがついているのは、変数定義時に
```
let ref_main = ref()
```
という具合に、refを使っているからである。
ref要素の中身を取り出すには.valueをつけないといけないので、忘れるべからず。

## 最後に
実はこの件で数時間悩んだが、focusメソッドの仕組みさえ理解できればすぐに解決できた。
生のJSを書く以外の方法を調べても、vue2(Options-API)での実践例しか出てこず、$refsというvue3では使えない記法しか出てこなかった。
この記事が必要な人のところへ届くことを祈る。


↓実際に触って動きを確認したい方はこちらへ↓
[ref-element-vue3.netlify.app](ref-element-vue3.netlify.app)