プログラムを中心とした個人的なメモ用のブログです。 タイトルは迷走中。
内容の保証はできませんのであしからずご了承ください。

2021/03/17

jQuery Keypad を使ってみた

event_note2021/03/17 0:12

キーボードがない環境での操作にも対応するため、ソフトウェアキーボードを実装することになったので、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 で発火するようにすればリアルタイムで同期がとれそうです。

参考 URL