英文:
Need help resetting variable I declared outside a function and iterated inside it?
问题
基本上我试图让网页能够使用箭头键在字段之间导航。我已经完成了大部分,只是变量 I 必须增加或减少 1 才能获得通过类访问的元素数组的索引,如下所示:
var isFocus;
var I = 0;
const prev = document.getElementsByClassName('prev');
const curr = document.getElementsByClassName('curr');
prev[0].focus()
var isFocused1;
var isFocused2;
document.addEventListener('keydown', fX)
function fX(event) {
key = event.key
isFocused1 = document.activeElement.classList.contains("prev");
isFocused2 = document.activeElement.classList.contains("curr");
if (isFocused1 == true) {
isFocus = prev
} else if (isFocused2 == true) {
isFocus = curr
}
if (key == 'ArrowDown' && I < 5) {
I++;
isFocus[I].focus();
} else if (key == 'ArrowUp' && I > 0) {
I--;
isFocus[I].focus();
}
}
<p>尝试选择第一列的顶部输入框,向下点击 3 次以到达第四个输入框,然后点击第二列的第一个输入框。现在向下点击一次,你会看到光标跳到第五个框。 </p>
<table>
<tr>
<td><input type="text" name="" class="prev"></td>
<td><input type="text" name="" class="curr"></td>
<td>
<p class="mtr-Result"></p>
</td>
</tr>
<tr>
<td><input type="text" name="" class="prev"></td>
<td><input type="text" name="" class="curr"></td>
<td>
<p class="mtr-Result"></p>
</td>
</tr>
<tr>
<td><input type="text" name="" class="prev"></td>
<td><input type="text" name="" class="curr"></td>
<td>
<p class="mtr-Result"></p>
</td>
</tr>
<tr>
<td><input type="text" name="" class="prev"></td>
<td><input type="text" name="" class="curr"></td>
<td>
<p class="mtr-Result"></p>
</td>
</tr>
<tr>
<td><input type="text" name="" class="prev"></td>
<td><input type="text" name="" class="curr"></td>
<td>
<p class="mtr-Result"></p>
</td>
</tr>
<tr>
<td><input type="text" name="" class="prev"></td>
<td><input type="text" name="" class="curr"></td>
<td>
<p class="mtr-Result"></p>
</td>
</tr>
</table>
英文:
basically i am trying to get the web page to navigate between fields with arrow keys. Ive got most if it down, just that the variable I has to be increased or decreased by 1 to get the index of the array of elements accessed by class, as such:
<!-- begin snippet: js hide: false console: false babel: false -->
<!-- language: lang-js -->
var isFocus;
var I = 0;
const prev = document.getElementsByClassName('prev');
const curr = document.getElementsByClassName('curr');
prev[0].focus()
var isFocused1;
var isFocused2;
document.addEventListener('keydown', fX)
function fX(event) {
key = event.key
isFocused1 = document.activeElement.classList.contains("prev");
isFocused2 = document.activeElement.classList.contains("curr");
if (isFocused1 == true) {
isFocus = prev
} else if (isFocused2 == true) {
isFocus = curr
}
if (key == 'ArrowDown' && I < 5) {
I++;
isFocus[I].focus();
} else if (key == 'ArrowUp' && I > 0) {
I--;
isFocus[I].focus();
}
}
<!-- language: lang-html -->
<p> try selecting first column's top input box, click down 3 times to get to the fourth one, then click the second column's first input box. Now click down once and you'll see the cursor skip to the fifth box. </p>
<table>
<tr>
<td><input type="text" name="" class="prev"></td>
<td><input type="text" name="" class="curr"></td>
<td>
<p class="mtr-Result"></p>
</td>
</tr>
<tr>
<td><input type="text" name="" class="prev"></td>
<td><input type="text" name="" class="curr"></td>
<td>
<p class="mtr-Result"></p>
</td>
</tr>
<tr>
<td><input type="text" name="" class="prev"></td>
<td><input type="text" name="" class="curr"></td>
<td>
<p class="mtr-Result"></p>
</td>
</tr>
<tr>
<td><input type="text" name="" class="prev"></td>
<td><input type="text" name="" class="curr"></td>
<td>
<p class="mtr-Result"></p>
</td>
</tr>
<tr>
<td><input type="text" name="" class="prev"></td>
<td><input type="text" name="" class="curr"></td>
<td>
<p class="mtr-Result"></p>
</td>
</tr>
<tr>
<td><input type="text" name="" class="prev"></td>
<td><input type="text" name="" class="curr"></td>
<td>
<p class="mtr-Result"></p>
</td>
</tr>
</table>
<!-- end snippet -->
https://jsfiddle.net/nw259to6/1/
The cursor will move down the fields, however upon switching to the other column input class = 'curr'
, I
's value keeps on iterating from whatever value it left of from. Meaning the next field to be active would be curr[I]
, clicking on the first input text box, then pressing down, makes the cursor skip a few input boxes.
Id like that every time i switch fields I
goes back to 0
so that i can scroll from top to bottom. THX!
答案1
得分: 1
因为您在两种类型的 <input>
上都使用了相同的变量。此外,当焦点在元素上时,您需要重置索引。
['prev', 'curr'].forEach(selector => {
// selector 是 'prev' 或 'curr'
// 选择所有具有该类的输入框
const inputs = [...document.querySelectorAll(`.${selector}`)];
let index = 0;
inputs[index].focus();
// 在按键按下时,如果可能,将焦点移动到另一个 <input>
function onkeydown(event) {
const key = event.key;
if (key == 'ArrowDown' && index < 5) {
index++;
} else if (key == 'ArrowUp' && index > 0) {
index--;
}
inputs[index].focus();
}
// 在焦点上时,我们找到原始列表中目标的索引,该列表始终由具有相同类的 <input> 组成
function onfocus(event) {
index = inputs.indexOf(event.target);
}
// 遍历列表,为这些 <input> 添加事件监听器
inputs.forEach(input => {
input.addEventListener('keydown', onkeydown);
input.addEventListener('focus', onfocus);
});
});
<p>尝试选择第一列的顶部输入框,点击三次向下箭头以到达第四个输入框,然后点击第二列的第一个输入框。</p>
<table>
<tr>
<td><input type="text" name="" class="prev"></td>
<td><input type="text" name="" class="curr"></td>
<td>
<p class="mtr-Result"></p>
</td>
</tr>
<tr>
<td><input type="text" name="" class="prev"></td>
<td><input type="text" name="" class="curr"></td>
<td>
<p class="mtr-Result"></p>
</td>
</tr>
<tr>
<td><input type="text" name="" class="prev"></td>
<td><input type="text" name="" class="curr"></td>
<td>
<p class="mtr-Result"></p>
</td>
</tr>
<tr>
<td><input type="text" name="" class="prev"></td>
<td><input type="text" name="" class="curr"></td>
<td>
<p class="mtr-Result"></p>
</td>
</tr>
<tr>
<td><input type="text" name="" class="prev"></td>
<td><input type="text" name="" class="curr"></td>
<td>
<p class="mtr-Result"></p>
</td>
</tr>
<tr>
<td><input type="text" name="" class="prev"></td>
<td><input type="text" name="" class="curr"></td>
<td>
<p class="mtr-Result"></p>
</td>
</tr>
</table>
如果要覆盖 ArrowRight
和 ArrowLeft
的行为,则上面的代码不起作用。在这种情况下,您将需要一个二维坐标。
英文:
That's because you're using the same variable for both types of <input>
s. Also, you need to reset the index when an element is focused.
<!-- begin snippet: js hide: false console: false babel: false -->
<!-- language: lang-js -->
['prev', 'curr'].forEach(selector => {
// selector is either 'prev' or 'curr'
// Selects all inputs with that class
const inputs = [...document.querySelectorAll(`.${selector}`)];
let index = 0;
inputs[index].focus();
// On keydown, we move focus to another <input> if possible.
function onkeydown(event) {
const key = event.key;
if (key == 'ArrowDown' && index < 5) {
index++;
} else if (key == 'ArrowUp' && index > 0) {
index--;
}
inputs[index].focus();
}
// On focus, we find the index of the target in the original list
// which always consists of <input>s with the same class
function onfocus(event) {
index = inputs.indexOf(event.target);
}
// Iterate over the list, add event listeners for those <input>s
inputs.forEach(input => {
input.addEventListener('keydown', onkeydown);
input.addEventListener('focus', onfocus);
});
});
<!-- language: lang-html -->
<p>Try selecting first column's top input box, click down 3 times to get to the fourth one, then click the second column's first input box.</p>
<table>
<tr>
<td><input type="text" name="" class="prev"></td>
<td><input type="text" name="" class="curr"></td>
<td>
<p class="mtr-Result"></p>
</td>
</tr>
<tr>
<td><input type="text" name="" class="prev"></td>
<td><input type="text" name="" class="curr"></td>
<td>
<p class="mtr-Result"></p>
</td>
</tr>
<tr>
<td><input type="text" name="" class="prev"></td>
<td><input type="text" name="" class="curr"></td>
<td>
<p class="mtr-Result"></p>
</td>
</tr>
<tr>
<td><input type="text" name="" class="prev"></td>
<td><input type="text" name="" class="curr"></td>
<td>
<p class="mtr-Result"></p>
</td>
</tr>
<tr>
<td><input type="text" name="" class="prev"></td>
<td><input type="text" name="" class="curr"></td>
<td>
<p class="mtr-Result"></p>
</td>
</tr>
<tr>
<td><input type="text" name="" class="prev"></td>
<td><input type="text" name="" class="curr"></td>
<td>
<p class="mtr-Result"></p>
</td>
</tr>
</table>
<!-- end snippet -->
The above will not work if you were to override ArrowRight
and ArrowLeft
's behaviour. In such a case, you will need a 2D coordinate.
答案2
得分: 1
你可以使导航与键盘按键的行和列数量无关 - 独立于keydown处理程序中的行和列计数:
const inputCols = document.querySelector("input#colCount");
const inputRows = document.querySelector("input#rowCount");
inputCols.addEventListener("input", buildTable);
inputRows.addEventListener("input", buildTable);
buildTable();
function buildTable() {
const html = Array.from({length: inputRows.value},
_ =>
"<tr>" +
Array.from({length: inputCols.value},
_ => "<td><input></td>"
).join("") +
"</tr>"
)
.join("");
const table = document.querySelector("table");
table.innerHTML = html;
table.querySelector("input").focus();
}
document.addEventListener("keydown", ({key}) => {
const delta = { ArrowDown: 1, ArrowUp: -1 }[key];
if (!delta) {
return; // 不是箭头上/下键
}
const table = document.querySelector("table");
const focused = table.querySelector("input:focus");
if (!focused) {
table.querySelector("input").focus(); // 焦点放在第一个输入框上
return;
}
// 查找具有给定列数的下一个输入框
const colCount = table.querySelectorAll("tr:first-child > td > input").length;
const inputs = [...table.querySelectorAll("td > input")];
const rowCount = inputs.length / colCount;
let idx = inputs.indexOf(focused);
const rowIdx = Math.floor(idx / colCount);
// 最后一个单元格,转到第一个
if (idx === inputs.length - 1 && delta > 0) {
idx = 0;
// 第一个单元格,转到最后一个
} else if (idx === 0 && delta < 0) {
idx = inputs.length - 1;
// 最后一行,转到下一列/第一行
} else if (rowIdx === rowCount - 1 && delta > 0 && idx) {
idx = (idx % colCount) + 1;
// 第一行,转到最后一行/前一列
} else if (rowIdx === 0 && delta < 0 && idx) {
idx = (idx % colCount) - 1 + (rowCount - 1) * colCount;
// 转到下一行
} else {
idx += delta * colCount;
}
inputs[idx].focus();
});
<p>
<label>列数
<input id="colCount" type="number" min="2" max="4" value="2">
</label>
<label>行数
<input id="rowCount" type="number" min="2" max="10" value="6">
</label>
</p>
<table>
</table>
英文:
You can make the navigation agnostic - independent of row and column count in the keydown handler:
<!-- begin snippet: js hide: false console: false babel: false -->
<!-- language: lang-js -->
const inputCols = document.querySelector("input#colCount");
const inputRows = document.querySelector("input#rowCount");
inputCols.addEventListener("input", buildTable);
inputRows.addEventListener("input", buildTable);
buildTable();
function buildTable() {
const html = Array.from({length: inputRows.value},
_ =>
"<tr>" +
Array.from({length: inputCols.value},
_ => "<td><input></td>"
).join("") +
"</tr>"
)
.join("");
const table = document.querySelector("table");
table.innerHTML = html;
table.querySelector("input").focus();
}
document.addEventListener("keydown", ({key}) => {
const delta = { ArrowDown: 1, ArrowUp: -1 }[key];
if (!delta) {
return; // not an arrow up/down key
}
const table = document.querySelector("table");
const focused = table.querySelector("input:focus");
if (!focused) {
table.querySelector("input").focus(); // focus the first input
return;
}
// find next input with given column count
const colCount = table.querySelectorAll("tr:first-child > td > input").length;
const inputs = [...table.querySelectorAll("td > input")];
const rowCount = inputs.length / colCount;
let idx = inputs.indexOf(focused);
const rowIdx = Math.floor(idx / colCount);
// last cell, go to first
if (idx === inputs.length - 1 && delta > 0) {
idx = 0;
// first cell, go to last
} else if (idx === 0 && delta < 0) {
idx = inputs.length - 1;
// last row, go to next column / first row
} else if (rowIdx === rowCount - 1 && delta > 0 && idx) {
idx = (idx % colCount) + 1;
// first row, go to last row / prevous column
} else if (rowIdx === 0 && delta < 0 && idx) {
idx = (idx % colCount) - 1 + (rowCount - 1) * colCount;
// go to next row
} else {
idx += delta * colCount;
}
inputs[idx].focus();
});
<!-- language: lang-html -->
<p>
<label>Number of cols
<input id="colCount" type="number" min="2" max="4" value="2">
</label>
<label>Number of rows
<input id="rowCount" type="number" min="2" max="10" value="6">
</label>
</p>
<table>
</table>
<!-- end snippet -->
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论