キーボードがない環境での操作にも対応するため、ソフトウェアキーボードを実装することになったので、jQuery Keypad というものを使ってみました。
選定理由は一番簡単に導入できそうだったからです。
ダウンロード方法や使い方は以下で簡単に説明されていました。
表示/非表示用のボタンを用意
デフォルトではフォーカスした際に jQuery Keypad が表示されますが、キーボードで入力したい人にとっては邪魔だと思うので、jQuery Keypad 表示用のボタンを用意し、必要な人だけが表示できるようにしてみました。
具体的には、showOn
を空文字にし、表示ボタンを押したときに表示するようにしています。
また、表示ボタンを連打するとテンキーが表示されたまま閉じれなくなってしまったので、ボタンの連打対策だけしておきました。
以下サンプルコードです。
<input id="inputKeypad" type="text">
<button type="button" onclick="showKeypad">表示</button>
$('#inputKeypad').keypad({
showOn: '',
showAnime: 'blind',
duration: 'fast',
keypadOnly: false,
});
var keypadFlag = false;
function showKeypad(){
if (!keypadFlag) {
keypadFlag = true;
// ボタン連打対策として、一定時間後にフラグを落とす
setTimeout(function(){
keypadFlag = false;
}, 500);
if ($(".keypad-popup").css('display') == 'block') {
// 表示されている場合の処理
// ※フォーカスが外れた時点で非表示になるので、明示的に非表示にしなくてもよい?
//$('#inputKeypad').keypad('hide') // Hide the keypad
} else {
// 非表示の場合の処理
$('#inputKeypad').keypad('show') // Show the keypad
}
}
}
type="number" への対応
jQuery Keypad は type="number"
の input
には対応しておらず、キーを押したときの入力内容が思っていたような動作になりません。
そこで、0~9
+
-
のボタンを独自で定義して無理矢理対応させました。
// keypad は type="number" の input に対応していないため、数値ボタンをカスタムで追加して無理矢理対応する
var customNumberKeys = [
['ZERO', 'zero', 0],
['ONE', 'one', 1],
['TWO', 'two', 2],
['THREE', 'three', 3],
['FOUR', 'four', 4],
['FIVE', 'five', 5],
['SIX', 'six', 6],
['SEVEN', 'seven', 7],
['EIGHT', 'eight', 8],
['NINE', 'nine', 9]
];
customNumberKeys.forEach(customNumberKey => {
$.keypad.addKeyDef(customNumberKey[0], customNumberKey[1], function (inst) {
this.val(this.val() + String(customNumberKey[2])).focus();
});
});
$.keypad.addKeyDef('MINUS', 'minus', function (inst) {
let val = Number(this.val())
if (val > 0) {
this.val(val * -1).focus();
}
});
$.keypad.addKeyDef('PLUS', 'plus', function (inst) {
let val = Number(this.val())
if (val < 0) {
this.val(val * -1).focus();
}
});
$('#inputKeypad').keypad({
showOn: '',
showAnime: '',
duration: 'fast',
keypadOnly: false,
closeText: '閉じる',
closeStatus: '',
clearText: 'クリア',
clearStatus: '',
zeroText: '0',
zeroStatus: '',
oneText: '1',
oneStatus: '',
twoText: '2',
twoStatus: '',
threeText: '3',
threeStatus: '',
fourText: '4',
fourStatus: '',
fiveText: '5',
fiveStatus: '',
sixText: '6',
sixStatus: '',
sevenText: '7',
sevenStatus: '',
eightText: '8',
eightStatus: '',
nineText: '9',
nineStatus: '',
minusText: '-',
minusStatus: '',
plusText: '+',
plusStatus: '',
layout: [
$.keypad.SEVEN + $.keypad.EIGHT + $.keypad.NINE + $.keypad.CLOSE,
$.keypad.FOUR + $.keypad.FIVE + $.keypad.SIX + $.keypad.CLEAR,
$.keypad.ONE + $.keypad.TWO + $.keypad.THREE,
$.keypad.MINUS + $.keypad.ZERO + $.keypad.PLUS
],
});
※デザインは変更しています(後述)
デザインの調整
デフォルトのデザインがちょっとダサいので、Bootstrap に合わせてちょっとだけ修正しました。
/* キーパッド */
.keypad-popup {
/* 線が太くて濃くてダサいので、bootstrap に合わせる */
border: 1px solid #dee2e6;
}
.keypad-special, .keypad-key {
/* 線が太くて濃くてダサいので、bootstrap に合わせる */
border: 1px solid #dee2e6;
/* border を細くしたので、ちょっとだけ広げる */
padding: 4px;
}
.keypad-close {
/* bootstrap の success に合わせる */
background-color: #28a745;
}
.keypad-clear {
/* bootstrap の danger に合わせる */
background-color: #dc3545;
}
.keypad-back {
/* bootstrap の primary に合わせる */
background-color: #007bff;
}
.keypad-shift {
/* bootstrap の info に合わせる */
background-color: #17a2b8;
}
.keypad-spacebar {
/*デフォルトは 13.25em だけど、keypad-tab を 2em 大きくしたので、その分小さくする */
width: 11.25em;
}
.keypad-tab {
/*デフォルトは 2em だけど小さいので大きくする*/
width: 4em;
}
/* キーパッド(独自追加分) */
.keypad-zero, .keypad-one, .keypad-two, .keypad-three, .keypad-four, .keypad-five, .keypad-six, .keypad-seven, .keypad-eight, .keypad-nine, .keypad-ten, .keypad-plus, .keypad-minus {
/* keypad-key に合わせる */
width: 2em;
}
vue.js で v-model と共存させる
私は部分的に vue.js を使っていますが、jQuery Keypad で入力した値が v-model
でバインディングした変数に反映されていませんでした。
どうやら、この手の入力補助 UI を使う場合、input
イベントを発火させないといけないようです。
とりあえず jQuery Keypad の onClose
でイベントを発火するようにしたら上手くいきました。
$('#inputKeypad').keypad({
showOn: 'focus',
showAnime: 'blind',
duration: 'fast',
keypadOnly: false,
onKeypress: null,
onClose: function () {
var evt = document.createEvent('HTMLEvents');
evt.initEvent('input', true, false);
this.dispatchEvent(evt);
}
});
試していませんが、onKeypress
で発火するようにすればリアルタイムで同期がとれそうです。