input内でenterを押下した際に次のinputにフォーカスさせる処理、よくありますよね。
フォーカスしたいinputがコンポーネントの時に悩んだので備忘録です。
#子コンポーネントの書き方
<template>
<div>
<input
ref="input"
:value="value"
:type="type"
:placeholder="placeholder"
@keydown="event=>$emit('focus', event)" />
</div>
</template>
<script>
export default {
name: 'Input',
props: {
type: {
type: String,
required: false,
default: 'text'
},
value: {
type: String,
required: false,
default: ''
},
placeholder: {
type: String,
required: false,
default: ''
}
},
methods: {
focus () {
this.$refs.input.focus()
}
}
}
</script>
#親コンポーネントの書き方
コンポーネントのinput -> 通常input -> コンポーネントのinputの順でフォーカス移動するサンプルにしました。
<template>
<div>
<Input
:value="value"
type="text"
placeholder="name"
@focus="event=>nextFocus(event,'emailRef')"/>
<input
ref="emailRef"
:value="value"
type="text"
placeholder="email"
@keydown="event=>nextFocus(event,'passwordRef')"/>
<Input
ref="passwordRef"
:value="value"
type="text"
placeholder="password"/>
</div>
</template>
<script>
import Input from '@/components/Input.vue'
export default {
components: { Input },
data() {
return {
value: ''
}
},
methods: {
nextFocus(event, refName) {
if (event.keyCode != 13) {return}
this.$refs[refName].focus()
}
}
}
</script>
#解説
<input
ref="input"
:value="value"
:type="type"
:placeholder="placeholder"
@keydown="event=>$emit('focus', event)" />
子コンポーネント側の@keydown="event=>$emit('focus', event)"
で、何かしらキーが押下されるたびにeventを渡すfocus
メソッドを読んでいます。
このeventを元にフォーカス処理をするために@focus="event=>nextFocus(event,'ref名')"
でメソッドを呼びます。
通常のinputの場合は直接@keydown
で問題ありません。
nextFocus(event, refName) {
if (event.keyCode != 13) {return}
this.$refs[refName].focus()
}
nextFocus
メソッドでイベントと対象のref名をもらいます。今回はenterの場合に移動したいので、keyCode
が13(enter)の時以外はなにも処理しません。
this.$refs[refName].focus()
で受け取ったref名に対して focus処理をしています。
focus () {
this.$refs.input.focus()
}
フォーカス先がコンポーネントの場合、コンポーネント(Input)のrefではなく、コンポーネント内に実際に書かれているinput
要素にフォーカスする必要があります。
そのため実際にフォーカスしたいコンポーネント内のinput
に対するフォーカスのメソッドが必要になります(説明が下手ですみません)
私はこれを書かなかったことによりfocus() is undefined
になり原因解明に時間がかかってしまいました。。。
#最後に
他にもっといい書き方がありそうな気がしますが、フォーカス移動付きコンポーネントに関する記事が全く見つからなかったので私にはこれが限界でした。。。
今の現場では$listeners
を使用する方法で記述していましたが、vue3では廃止されているようなので自分で考えて書いてみました。ものすごく時間がかかった。。。
もっといい書き方があるよ〜とか、俺ならこう書くぜ!などコメントいただけると大変嬉しいです。
最後まで読んでいただきありがとうございます!