Чтобы убедиться, что только один символ может быть внутри каждого ввода за раз, вы можете использовать событие keydown на входе и warnDefault на обработчике, чтобы он не дважды вводился в поле. Затем передайте некоторую информацию о ключевом событии в вашу функцию и установите значение ввода равным значению текущего ключевого кода, пройденного событием внутри функции.
Я вижу, вы хотите ограничить это к указанному c набору кодов клавиш, так что вы можете позаботиться об этом и в этой функции.
<script>
let boxes = [
["", "", "", "", "", "", "", ""],
["", "", "", "", "", "", "", ""],
["", "", "", "", "", "", "", ""],
["", "", "", "", "", "", "", ""],
["", "", "", "", "", "", "", ""],
["", "", "", "", "", "", "", ""],
["", "", "", "", "", "", "", ""],
["", "", "", "", "", "", "", ""]
];
function isValid(val, i, j) {
if ((val.keyCode >= 65 && val.keyCode <= 90) || (val.keyCode >= 97 && val.keyCode <= 122)) {
boxes[i][j] = val.key;
return true;
}
return false;
}
</script>
<main>
<div class="root">
{#each boxes as row, i}
<div class="row">
{#each row as column, j}
<span class="column">
<input
class="col-input"
type="text"
bind:value="{boxes[i][j]}"
on:keydown|preventDefault={e => isValid(e, i, j)}
/>
</span>
{/each}
</div>
{/each}
</div>
</main>
Вот пример в REPL
РЕДАКТИРОВАТЬ: Если необходимо сохранить функциональность вкладок (при условии, что это не игра типа «укажи и щелкни»), необходимо будет добавить некоторые дополнительные функции, так как в этом случае warnDefault убивает клавишу вкладки.
Это можно сделать с помощью изменение привязки: значение для привязки: эту и все ссылки, которые могли бы изменить значение блоков, нужно будет заменить на боксы [i] [j] .value.
Я добавил некоторые дополнительные функции для обработки клавиш со стрелками и сохранить функцию клавиши табуляции, сохраняя фокус внутри сетки (обычно табуляция должна выпрыгивать из окна)
<script>
let boxes = [
["", "", "", "", "", "", "", ""],
["", "", "", "", "", "", "", ""],
["", "", "", "", "", "", "", ""],
["", "", "", "", "", "", "", ""],
["", "", "", "", "", "", "", ""],
["", "", "", "", "", "", "", ""],
["", "", "", "", "", "", "", ""],
["", "", "", "", "", "", "", ""]
];
function isValid(val, i, j) {
const width = boxes[i].length, height = boxes.length, prevCol = j - 1, nextCol = j + 1, prevRow = i - 1, nextRow = i + 1, left = 37, up = 38, right = 39, down = 40, tab = 9;
// Preserve tab functionality,
// loop to first input of next row
// when end of row is reached or to
// first row and column when end of
// matrix is reached
if (val.keyCode == tab) {
nextCol != width? boxes[i][nextCol].focus() : i != height - 1? boxes[nextRow][0].focus() : boxes[0][0].focus();
return;
}
// Loop around single row with right and left arrows
if (val.keyCode == right) {
nextCol != width? boxes[i][nextCol].focus() : boxes[i][0].focus();
return;
}
if (val.keyCode == left) {
j != 0? boxes[i][prevCol].focus() : boxes[i][width - 1].focus();
return;
}
// loop around single column with up and down arrows
if (val.keyCode == up) {
i != 0? boxes[prevRow][j].focus() : boxes[height - 1][j].focus();
return;
}
if (val.keyCode == down) {
i != height - 1? boxes[nextRow][j].focus() : boxes[0][j].focus();
return;
}
if ((val.keyCode >= 65 && val.keyCode <= 90) || (val.keyCode >= 97 && val.keyCode <= 122)) {
boxes[i][j].value = val.key;
return true;
}
return false;
}
</script>
<main>
<div class="root">
{#each boxes as row, i}
<div class="row">
{#each row as column, j}
<span class="column">
<input
class="col-input"
type="text"
bind:this="{boxes[i][j]}"
on:keydown|preventDefault={e => isValid(e, i, j)}
/>
</span>
{/each}
</div>
{/each}
</div>
</main>
Вот ссылка к этому примеру REPL