如何通过验证绑定来自二维数组元素的输入?
How do I bind an input from an element of a 2D array with validation?
我正在尝试制作一个游戏,其中有一个 n*n 的网格,并且所有网格都包含一个输入。怎么绑定成一个盒子只能留一个字符?
<script>
let boxes = [
["", "", "", "", "", "", "", ""],
["", "", "", "", "", "", "", ""],
["", "", "", "", "", "", "", ""],
["", "", "", "", "", "", "", ""],
["", "", "", "", "", "", "", ""],
["", "", "", "", "", "", "", ""],
["", "", "", "", "", "", "", ""],
["", "", "", "", "", "", "", ""]
];
function isValid(keyCode) {
if ((keyCode >= 65 && keyCode <= 90) || (keyCode >= 97 && keyCode <= 122)) {
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]}"
/>
</span>
{/each}
</div>
{/each}
</div>
</main>
To make sure only a single character can be inside each input at a time you can use a keydown event on the input and preventDefault on the handler so that it doesn't double enter into the field. Then pass on some information about the key event to your function and set the value of the input to be the value of the current keyCode passed through by the event inside the function.
I see you're looking to limit it to a specific set of keycode's so you can take care of that in this function as well.
<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>
Here's an example in the REPL
编辑:
If tab functionality needs to be preserved (assuming this is not a point and click game, then some extra functionality will need to be added since preventDefault kills the tab key in this instance.
This can be done by changing bind:value to bind:this and all references that would change the boxes' value will need to be changed to boxes[i][j].value.
I added some additional functionality to handle the arrow keys and preserve tab key function while keeping focus inside the grid (usually tab would want to jump out of window)
<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>
Here is the link to that REPL example
我正在尝试制作一个游戏,其中有一个 n*n 的网格,并且所有网格都包含一个输入。怎么绑定成一个盒子只能留一个字符?
<script>
let boxes = [
["", "", "", "", "", "", "", ""],
["", "", "", "", "", "", "", ""],
["", "", "", "", "", "", "", ""],
["", "", "", "", "", "", "", ""],
["", "", "", "", "", "", "", ""],
["", "", "", "", "", "", "", ""],
["", "", "", "", "", "", "", ""],
["", "", "", "", "", "", "", ""]
];
function isValid(keyCode) {
if ((keyCode >= 65 && keyCode <= 90) || (keyCode >= 97 && keyCode <= 122)) {
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]}"
/>
</span>
{/each}
</div>
{/each}
</div>
</main>
To make sure only a single character can be inside each input at a time you can use a keydown event on the input and preventDefault on the handler so that it doesn't double enter into the field. Then pass on some information about the key event to your function and set the value of the input to be the value of the current keyCode passed through by the event inside the function.
I see you're looking to limit it to a specific set of keycode's so you can take care of that in this function as well.
<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>
Here's an example in the REPL
编辑: If tab functionality needs to be preserved (assuming this is not a point and click game, then some extra functionality will need to be added since preventDefault kills the tab key in this instance.
This can be done by changing bind:value to bind:this and all references that would change the boxes' value will need to be changed to boxes[i][j].value.
I added some additional functionality to handle the arrow keys and preserve tab key function while keeping focus inside the grid (usually tab would want to jump out of window)
<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>
Here is the link to that REPL example