本稿は、Vue.js公式サイトの「例」のページにおける「TodoMVC の例」の、日本語入力の不具合とその修正の仕方についてご説明します。
[追記: 2018/12/14]この問題はvuejs/vue
の開発ブランチで修正されました。つぎのリリースでは解消するはずです(なお、「[TodoMVC Example] [enter] key event to determin transform of Japanese characters makes the item added to list」参照)。
TodoMVC の例
Vue.jsサイトの「TodoMVC の例」は、洗練されたインタフェースのTodoリストです(図001)。機能は、項目の追加と削除、未処理と処理済みの表示切り替えなど、基本的といえます。
図001■TodoMVCの画面表示
けれど、ありがちのTodoリストのようなボタンだらけの画面ではありません(図002)。削除ボタンは項目にロールオーバーすると表れ、項目の追加は[enter]キーで確定します。
図002■ありがちのTodoリスト
日本語変換確定の[enter]キーで項目が追加されてしまう
ところが、この洗練されたインタフェースが、日本語入力ではアダになります。日本語変換確定の[enter]キーで項目が追加されてしまうのです(図003)。
図003■日本語変換確定の[enter]キーで追加された項目
はじめはChromeで、イベント@keyup.enter
と@keydown.enter
とでは、取得する入力値に時間差があることを見つけました。そこで、ふたつの値を比べることにより、変換の確定と[enter]キーの単独入力を切り分けたのです。けれど、Safariではふたつの値は同じでした。つまり、この案は却下ということです。
keypressイベントを捉える
調べたところ、@keypress
イベントは変換確定の[enter]キーは拾わないことがわかりました。つまり、イベント@keypress.enter
で、変換の確定ではなく、単独で入力された[enter]キーが捉えられるのです。
そこで、TodoMVCの修正です。<header>
に置かれた<input>
要素のキーイベントを、つぎのように@keyup.enter
から@keypress.enter
に書き替えます。コールバックメソッドaddTodo()
は、そのままで構いません。
<section class="todoapp">
<header class="header">
<h1>todos</h1>
<input class="new-todo"
@keypress.enter="addTodo">
<!-- @keyup.enter="addTodo"> -->
</header>
</section>
リスト項目を編集する処理についても、同じように書き替えます。<input>
要素のキーイベントは、@keyup.enter
でなく@keypress.enter
です。こちらも、キーイベントから呼び出すメソッドdoneEdit()
は手を触れません。
<section class="main" v-show="todos.length" v-cloak>
<ul class="todo-list">
<li v-for="todo in filteredTodos"
>
<input class="edit" type="text"
@keypress.enter="doneEdit(todo)"
@keyup.esc="cancelEdit(todo)">
<!-- @keyup.enter="doneEdit(todo)" -->
</li>
</ul>
</section>
これらの修正が加えられたTodoMVCのサンプルを「Vue.js: TodoMVC revised」としてFiddleに掲げます。また、Qiitaに埋め込めるよう、同じコードをCodePenにコピーしてつぎのサンプル001に掲げました。
サンプル001■ Vue.js: TodoMVC revised
See the Pen Vue.js: TodoMVC revised by Fumio Nonaka (@FumioNonaka) on CodePen.
標準JavaScriptのキーイベント
標準のJavaScriptでは、イベントkeydown
はkeypress
と同じように、日本語の変換を確定したときの[enter]は拾わないようです。たとえば、つぎのように入力して変換していったとします([確定]は[enter]キーによる変換の決定です)。
日本語の[確定]項目を[確定]入力[確定]する[確定][enter]
すると、捕らえられた[enter]キーイベントとそのときの入力値はつぎのとおりです。以下のサンプル002で実際に確かめられます(enterは[enter]キーの単独入力)。
keyup: 日本語の
keyup: 日本語の項目を
keyup: 日本語の項目を入力
keyup: 日本語の項目を入力する
keydown: 日本語の項目を入力する
keypress: 日本語の項目を入力する
enter: 日本語の項目を入力する
keyup:
サンプル002■テキストの入力について[enter]キーのイベントを確かめる
See the Pen Testing key events for [enter] when inputting Japanese characters by Fumio Nonaka (@FumioNonaka) on CodePen.
Vue.jsもv2.3.4では、keydown
イベントは日本語変換を確定する[enter]キーは拾いませんでした(「Vue.js: TodoMVCをつくる 01 ー 項目の追加と削除および残り項目数表示」注[*1]参照)。この動きが、v2.5.14で仕様変更されたようです(GitHubのjp.vuejs.org[TodoMVC Example] [enter] key event to determin transform of Japanese characters makes the item added to list参照)。