input 要素で日本語入力が完了したのか submit のエンターなのかを判定する
軽くググるとすでに数多くの記事が書かれており、たくさんの先人の方々が苦しんだことが分かりますが、古かったり超厳密に実装しようとして少々複雑度が増しているものだったりしますので、完璧ではないですが妥協できるくらいのレベルでの実装で良い、という人のために書きます。(おそらく未来の自分になるかもw)
実装方針
基本的には KeyboradEvent
オブジェクトの key
プロパティや keyCode
プロパティを見て判定する形です。詳しくは、MDN の記事が参考になりますのでご参照ください。
※余談ですが、MDN によると keyCode
プロパティは Deprecated で code
プロパティを使えとのことだそうですが、様々なサービスやブラウザではまだ使えない*1ので、本記事では keyCode
プロパティを利用します。
完成品のデモ
まずは完成品のデモのリンクを載せておきます。
アクセスされましたら、画面右ペイン下の console
をクリックして表示してください。その後は、日本語でパタパタ入力して完了したり、アルファベット入力のままでエンターキーを押下してみたりしてください。
実際のコード
今回は styled-components という便利なライブラリ*2を利用して、入力欄(input 要素)を作っていますのでそのコードを先に記載します。
import React from "react"; import styled from "styled-components"; const Input = styled.input.attrs({ type: "text" })` border-color: ${props => (props.error ? "#ff0000" : "skyblue")}; width: 200px; border-radius: 8px; padding: 5px; line-height: 1.5; font-size: 1rem; `; const TextField = ({ value, placeholder, onChange, onKeyUp, onKeyDown }) => ( <Input value={value} placeholder={placeholder} onChange={e => onChange && onChange(e.target.value)} onKeyUp={e => onKeyUp && onKeyUp(e)} onKeyDown={e => onKeyDown && onKeyDown(e)} /> ); export default TextField;
特に説明することもないですw
では、今回コアとなるコンポーネントのコードを紹介します。
import React, { useState } from "react"; import TextField from "./TextField"; const handleKeyUp = e => { // ※ここと if (e.key === "Enter" && e.keyCode === 13) { console.log("KeyUp: Japanese input!!"); } }; const handleKeyDown = e => { // ※ここがキーポイント if (e.key === "Enter" && e.keyCode === 13) { console.log("KeyDown: Japanese input!!"); } }; const SearchField = ({ text, placeholder }) => { const [inputText, setInputText] = useState(text); const checkAndSetText = newText => { if (newText.length > 10) return; setInputText(newText); localStorage.setItem("text", newText); }; return ( <> <TextField value={inputText} placeholder={placeholder} onChange={checkAndSetText} onKeyUp={handleKeyUp} onKeyDown={handleKeyDown} /> <p>variable text: {inputText}</p> </> ); }; export default SearchField;
解説
上記コードにもコメントしていますが、今回の肝は if (e.key === "Enter" && e.keyCode === 13)
の判定条件です。更に言うと、keyDown
イベントを使う事 です。当初は keyUp
イベントを使っていたのですが、日本語入力には使えませんでした。
以下、日本語完了と submit の Enterキーを押下したときの比較 をしていきます。
keyUp | 日本語 | submit |
---|---|---|
key | 'Enter' | 'Enter' |
keyCode | 13 | 13 |
keyDown | 日本語 | submit |
---|---|---|
key | 'Enter' | 'Enter' |
keyCode | 229 | 13 |
上記のように、keyUp
イベントでは Enter キーを押下した時、それが日本語入力の完了なのか submit するときのものなのか判定ができませんでした。よって、日本語の一単語を入力し終わって次の単語を入力しようとした時、すでに submit が走ってしまい入力ができない状況になっていました。
したがって、keyDown
イベントを用いることにしました。ちなみに日本語入力の場合は、常に keyCode
は 229
になっているので、そこは注意が必要です。
ではでは(=゚ω゚)ノ