はじめに
フロントエンド開発していると、日本語入力確定時のEnterキーが、確定時のEnterキー打鍵と判別がつかず更新されてしまう事象に悩むことは誰しも遭遇したことあることかと思います。
↑↑例)調査という文字を打って、漢字変換を確定Enterを押したらそのまま更新になっちゃう
そんな時は、compositionイベントを利用すれば良いのですが、不可解な事象に少しハマってしまい数時間溶けてしまいました。
同じ事象でハマる人が減りますように
compositionイベントの使い方
一般的には以下のように、data
にcomposing
のような変数を用意し、compositionstart
, compositionend
でそれぞれcomposing
を更新することで、状態のチェックができると思います。
<template>
...
<input
v-model="name"
type="text"
@compositionstart="composing = true"
@compositionend="composing = false"
@keyup.enter="onChangeName"
>
...
</template>
<script>
export default {
data() {
return {
composing: false // IME入力中かどうか
}
},
methods: {
onChangeName () {
if(this.composing) return
// 更新処理を書く
}
}
}
<script>
...
(普段はTS入れてますが、わかりやすいように省略)
そして上記のようにmethods
でthis.composing
を判定して後続処理を止めてたりします。これで日本語入力確定時に更新処理を走らないようにしたりします。
しかし問題は起きた
上記のようにやっていて、問題なくcomposing
値も更新され問題なかったのですが、おや?日本語入力確定時にも更新処理が走ってしまうぞ?!という状況に遭遇したのが今回のケースです。
試しにconsoleを仕込んでデベロッパーツールを見てみると、「composing値が先に終わって、更新処理時の判定時には使えていない!?」状態となっていたのでした。
// 省略
<script>
export default {
data() {
return {
composing: false
}
},
watch: {
composing(val) {
console.info(val, 'watch') // ←追加!
}
}
methods: {
onChangeName () {
console.info(val, 'methods') // ←追加!
if(this.composing) return
// 更新処理を書く
}
}
}
<script>
...
もう発狂ものです。
どうしたらよいのか?
結論から行くと、メソッドを呼び出しているkeyup
イベントをkeydown
イベントに変更してください。
<template>
...
<input
v-model="name"
type="text"
@compositionstart="composing = true"
@compositionend="composing = false"
@keydown.enter="onChangeName" // ←keyupからkeydownに変更
>
...
</template>
// 省略
そうすると見事に、methods
での判定箇所でcomposing
がfalse
になる箇所が後になってくれてます
なんでkeydownで回避できるの?
keydown
イベントは文字通り、キーが押された時に発火し、keyup
イベントはキーを押して話した時に発火します。また今回これで事象を回避できたことから、keyup
イベントはcompositionend
と同時に呼び出すとcompositionend
が優先されることがわかりました。また、keydown
を利用することで明示的にcompositionend
イベントよりも先に発火させることができるものだと思います。
さいごに
keyCode
プロパティやkeyPress
イベントがDeprecatedになっていくので、日本語IME入力時にはcomposition
イベントを利用していくことになると思いますが、こういうケースもあるのでご注意ください〜
ちょくちょく詰まったネタは記事にしていきたいと思います!