10
8

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

keydownとkeyupの違いに気をつけて!IME入力時に順番が違う!

Last updated at Posted at 2020-09-03

はじめに

フロントエンド開発していると、日本語入力確定時のEnterキーが、確定時のEnterキー打鍵と判別がつかず更新されてしまう事象に悩むことは誰しも遭遇したことあることかと思います。

 workload.gif
↑↑例)調査という文字を打って、漢字変換を確定Enterを押したらそのまま更新になっちゃう

そんな時は、compositionイベントを利用すれば良いのですが、不可解な事象に少しハマってしまい数時間溶けてしまいました。

同じ事象でハマる人が減りますように :pray:

compositionイベントの使い方

一般的には以下のように、datacomposingのような変数を用意し、compositionstart, compositionendでそれぞれcomposingを更新することで、状態のチェックができると思います。

vue.js
<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入れてますが、わかりやすいように省略)

そして上記のようにmethodsthis.composingを判定して後続処理を止めてたりします。これで日本語入力確定時に更新処理を走らないようにしたりします。

しかし問題は起きた

上記のようにやっていて、問題なくcomposing値も更新され問題なかったのですが、おや?日本語入力確定時にも更新処理が走ってしまうぞ?!という状況に遭遇したのが今回のケースです。

試しにconsoleを仕込んでデベロッパーツールを見てみると、「composing値が先に終わって、更新処理時の判定時には使えていない!?」状態となっていたのでした。

vue.js
// 省略

<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>
...
mojikyo45_640-2.gif

もう発狂ものです。

どうしたらよいのか?

結論から行くと、メソッドを呼び出しているkeyupイベントをkeydownイベントに変更してください。

vue.js
<template>
  ...
  <input
    v-model="name"
    type="text"
    @compositionstart="composing = true"
    @compositionend="composing = false"
    @keydown.enter="onChangeName" // ←keyupからkeydownに変更
  >
  ...
</template>
// 省略
mojikyo45_640-2.gif

そうすると見事に、methodsでの判定箇所でcomposingfalseになる箇所が後になってくれてます

なんでkeydownで回避できるの?

keydownイベントは文字通り、キーが押された時に発火し、keyupイベントはキーを押して話した時に発火します。また今回これで事象を回避できたことから、keyupイベントはcompositionendと同時に呼び出すとcompositionendが優先されることがわかりました。また、keydownを利用することで明示的にcompositionendイベントよりも先に発火させることができるものだと思います。

さいごに

keyCodeプロパティやkeyPressイベントがDeprecatedになっていくので、日本語IME入力時にはcompositionイベントを利用していくことになると思いますが、こういうケースもあるのでご注意ください〜

ちょくちょく詰まったネタは記事にしていきたいと思います!

10
8
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
10
8

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?