<input>
タグに頼らずキー入力を取得したい!
みなさん、こんにちは。どんぶラッコです。
先日、Twitterでふとこんな投稿を目にしました。
自分がVue.jsを触っていることもあり、やり取りをさせていただきました。
話していくと、どうやら「inputではなく、画面全体のキー入力を取得したい!」ということのようでした。
Vue.jsには v-on
という機能が備わっています。例えば、DOMに対して v-on:keydown
と指定してあげるとキー入力のイベントを拾うことができます。
こういうことですね。
<div id="app">
<input
autofocus
placeholder="文字を入力"
type="text"
@keydown="onKeyDown"
>
<div>
<p>key: {{key}}</p>
<p>keyCode: {{keyCode}}</p>
</div>
</div>
<script src="https://unpkg.com/vue@next"></script>
const App = {
data() {
return {
key: '',
keyCode: null
}
},
methods: {
onKeyDown(event) {
this.key = event.key
this.keyCode = event.keyCode
}
}
}
Vue.createApp(App).mount('#app')
See the Pen vuejs キーコード取得 by cha1ra (@cha1ra) on CodePen.
しかし、これでは input
タグにフォーカスが当たっているときにしか keydown
イベントが発火しません。
どうしたらいいのでしょうか?
mounted()
の中に Pure JSで記述
この場合Vue.jsの機能に頼るのではなく、PureJS (生のJavaScript) で記述するしかないと思っています。
私の場合、 mounted()
の中に記述しています。
またサンプルコードを示しますね!
<div id="app">
<div>
<p>key: {{key}}</p>
<p>keyCode: {{keyCode}}</p>
</div>
</div>
<script src="https://unpkg.com/vue@next"></script>
const App = {
data() {
return {
key: '',
keyCode: null
}
},
mounted() {
document.addEventListener('keydown', this.onKeyDown)
},
beforeDestroy() {
document.removeEventListener('keydown', this.onKeyDown)
},
methods: {
onKeyDown(event) {
this.key = event.key
this.keyCode = event.keyCode
}
},
}
Vue.createApp(App).mount('#app')
ポイントは JavaScript側の mounted()
メソッドの中身です。
document.addEventListener('keydown', this.onKeyDown)
この部分でイベントリスナーを指定しています。
イベントリスナーの設定方法については公式サイトをご確認ください。
この書き方でいいのかな…?
とはいえ、この書き方でいいのでしょうか…?Vue.jsのフレームワークの中にPureJSがガッツリ登場するのってありなんだろうか?
不安になったので、Vue.js の日本コミュニティに上記の書き方でいいと思うか、アドバイスを求めてみました。
すると、下記2つのフィードバックをいただきました。
- 書き方はそれで問題ないと思う
- グローバルなオブジェクトに対して
addEventListener
するならremoveEventListener
についても記述するべき
書き方はそれで大丈夫
コメントを引用させていただきます。
個人的にはそれで問題ないと思いますよ。Vueはコンポーネントをうまく扱う、それについて
v-on
が簡単に使えるのがメリットで、Vueが関与しない部分(ページ全体)について無理にVueを使う必要はないと思います。ただ、やるとすれば一番RootのコンポーネントでListenする、というのはありかもです。
VueはあくまでもJSをうまく使うためのツールを提供しているのであって、そのツールで手が回らないところについてはPureJS書いちゃってもいいじゃない!という意見です。ごもっとも…!
最後に記載していただいている Rootのコンポーネントで...
というのは、
<App @keydown="..."> ... </App>
というように記述することを指しています。
removeEventListener() もあったほうがいいよ!
また、このようなご意見もいただきました。
ちなみに、pure JSでdocumentやwindowなどグローバルなオブジェクトに対してaddEventListenerする場合は、beforeDestroyなどでremoveEventListenerしておいた方が安全です。
一番最初サンプルを提示したときに removeEventListener していませんでした。これを書かないと、リスナーがずっと残り続けてしまう可能性があります。
上記の指摘を受け、 beforeDestroy()
の記述を追加しています。
beforeDestroy() {
document.removeEventListener('keydown', this.onKeyDown)
},
removeEventListener
の使い方は
対象.reomoveEventListener('イベントの種類', イベントリスナー関数)
のように、addEventListner で指定した関数をもう一回指定しなくてはなりません。今回で言うと this.onKeyDown
ですね。
なので、 removeEventListener
のことも考慮するとイベントリスナー関数は methods()
として定義しておくのが良いでしょう。
この記事のまとめ
というわけでまとめると、PureJSを併用するのはOK、ただしその場合はイベントリスナーの削除を忘れない!ということがポイントになりそうですね!
今回のコードサンプルは Codepenに置いてあります。活用してください♪
See the Pen vuejs キーコード取得(document) by cha1ra (@cha1ra) on CodePen.