需要帮助重置我在函数外部声明并在函数内部迭代的变量吗?

huangapple go评论63阅读模式
英文:

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(&#39;prev&#39;);
const curr = document.getElementsByClassName(&#39;curr&#39;);
prev[0].focus()
var isFocused1;
var isFocused2;
document.addEventListener(&#39;keydown&#39;, fX)
function fX(event) {
key = event.key
isFocused1 = document.activeElement.classList.contains(&quot;prev&quot;);
isFocused2 = document.activeElement.classList.contains(&quot;curr&quot;);
if (isFocused1 == true) {
isFocus = prev
} else if (isFocused2 == true) {
isFocus = curr
}
if (key == &#39;ArrowDown&#39; &amp;&amp; I &lt; 5) {
I++;
isFocus[I].focus();
} else if (key == &#39;ArrowUp&#39; &amp;&amp; I &gt; 0) {
I--;
isFocus[I].focus();
}
}

<!-- language: lang-html -->

&lt;p&gt; try selecting first column&#39;s top input box, click down 3 times to get to the fourth one, then click the second column&#39;s first input box. Now click down once and you&#39;ll see the cursor skip to the fifth box. &lt;/p&gt;
&lt;table&gt;
&lt;tr&gt;
&lt;td&gt;&lt;input type=&quot;text&quot; name=&quot;&quot; class=&quot;prev&quot;&gt;&lt;/td&gt;
&lt;td&gt;&lt;input type=&quot;text&quot; name=&quot;&quot; class=&quot;curr&quot;&gt;&lt;/td&gt;
&lt;td&gt;
&lt;p class=&quot;mtr-Result&quot;&gt;&lt;/p&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;input type=&quot;text&quot; name=&quot;&quot; class=&quot;prev&quot;&gt;&lt;/td&gt;
&lt;td&gt;&lt;input type=&quot;text&quot; name=&quot;&quot; class=&quot;curr&quot;&gt;&lt;/td&gt;
&lt;td&gt;
&lt;p class=&quot;mtr-Result&quot;&gt;&lt;/p&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;input type=&quot;text&quot; name=&quot;&quot; class=&quot;prev&quot;&gt;&lt;/td&gt;
&lt;td&gt;&lt;input type=&quot;text&quot; name=&quot;&quot; class=&quot;curr&quot;&gt;&lt;/td&gt;
&lt;td&gt;
&lt;p class=&quot;mtr-Result&quot;&gt;&lt;/p&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;input type=&quot;text&quot; name=&quot;&quot; class=&quot;prev&quot;&gt;&lt;/td&gt;
&lt;td&gt;&lt;input type=&quot;text&quot; name=&quot;&quot; class=&quot;curr&quot;&gt;&lt;/td&gt;
&lt;td&gt;
&lt;p class=&quot;mtr-Result&quot;&gt;&lt;/p&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;input type=&quot;text&quot; name=&quot;&quot; class=&quot;prev&quot;&gt;&lt;/td&gt;
&lt;td&gt;&lt;input type=&quot;text&quot; name=&quot;&quot; class=&quot;curr&quot;&gt;&lt;/td&gt;
&lt;td&gt;
&lt;p class=&quot;mtr-Result&quot;&gt;&lt;/p&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;input type=&quot;text&quot; name=&quot;&quot; class=&quot;prev&quot;&gt;&lt;/td&gt;
&lt;td&gt;&lt;input type=&quot;text&quot; name=&quot;&quot; class=&quot;curr&quot;&gt;&lt;/td&gt;
&lt;td&gt;
&lt;p class=&quot;mtr-Result&quot;&gt;&lt;/p&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;/table&gt;

<!-- end snippet -->

https://jsfiddle.net/nw259to6/1/

The cursor will move down the fields, however upon switching to the other column input class = &#39;curr&#39; , 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>

如果要覆盖 ArrowRightArrowLeft 的行为,则上面的代码不起作用。在这种情况下,您将需要一个二维坐标。

英文:

That's because you're using the same variable for both types of &lt;input&gt;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 -->

[&#39;prev&#39;, &#39;curr&#39;].forEach(selector =&gt; {
// selector is either &#39;prev&#39; or &#39;curr&#39;
// Selects all inputs with that class
const inputs = [...document.querySelectorAll(`.${selector}`)];
let index = 0;
inputs[index].focus();
// On keydown, we move focus to another &lt;input&gt; if possible.
function onkeydown(event) {
const key = event.key;
if (key == &#39;ArrowDown&#39; &amp;&amp; index &lt; 5) {
index++;
} else if (key == &#39;ArrowUp&#39; &amp;&amp; index &gt; 0) {
index--;
}
inputs[index].focus();
}
// On focus, we find the index of the target in the original list
// which always consists of &lt;input&gt;s with the same class
function onfocus(event) {
index = inputs.indexOf(event.target);
}
// Iterate over the list, add event listeners for those &lt;input&gt;s
inputs.forEach(input =&gt; {
input.addEventListener(&#39;keydown&#39;, onkeydown);
input.addEventListener(&#39;focus&#39;, onfocus);
});
});

<!-- language: lang-html -->

&lt;p&gt;Try selecting first column&#39;s top input box, click down 3 times to get to the fourth one, then click the second column&#39;s first input box.&lt;/p&gt;
&lt;table&gt;
&lt;tr&gt;
&lt;td&gt;&lt;input type=&quot;text&quot; name=&quot;&quot; class=&quot;prev&quot;&gt;&lt;/td&gt;
&lt;td&gt;&lt;input type=&quot;text&quot; name=&quot;&quot; class=&quot;curr&quot;&gt;&lt;/td&gt;
&lt;td&gt;
&lt;p class=&quot;mtr-Result&quot;&gt;&lt;/p&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;input type=&quot;text&quot; name=&quot;&quot; class=&quot;prev&quot;&gt;&lt;/td&gt;
&lt;td&gt;&lt;input type=&quot;text&quot; name=&quot;&quot; class=&quot;curr&quot;&gt;&lt;/td&gt;
&lt;td&gt;
&lt;p class=&quot;mtr-Result&quot;&gt;&lt;/p&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;input type=&quot;text&quot; name=&quot;&quot; class=&quot;prev&quot;&gt;&lt;/td&gt;
&lt;td&gt;&lt;input type=&quot;text&quot; name=&quot;&quot; class=&quot;curr&quot;&gt;&lt;/td&gt;
&lt;td&gt;
&lt;p class=&quot;mtr-Result&quot;&gt;&lt;/p&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;input type=&quot;text&quot; name=&quot;&quot; class=&quot;prev&quot;&gt;&lt;/td&gt;
&lt;td&gt;&lt;input type=&quot;text&quot; name=&quot;&quot; class=&quot;curr&quot;&gt;&lt;/td&gt;
&lt;td&gt;
&lt;p class=&quot;mtr-Result&quot;&gt;&lt;/p&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;input type=&quot;text&quot; name=&quot;&quot; class=&quot;prev&quot;&gt;&lt;/td&gt;
&lt;td&gt;&lt;input type=&quot;text&quot; name=&quot;&quot; class=&quot;curr&quot;&gt;&lt;/td&gt;
&lt;td&gt;
&lt;p class=&quot;mtr-Result&quot;&gt;&lt;/p&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;input type=&quot;text&quot; name=&quot;&quot; class=&quot;prev&quot;&gt;&lt;/td&gt;
&lt;td&gt;&lt;input type=&quot;text&quot; name=&quot;&quot; class=&quot;curr&quot;&gt;&lt;/td&gt;
&lt;td&gt;
&lt;p class=&quot;mtr-Result&quot;&gt;&lt;/p&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;/table&gt;

<!-- 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(&quot;input#colCount&quot;);
const inputRows = document.querySelector(&quot;input#rowCount&quot;);
inputCols.addEventListener(&quot;input&quot;, buildTable);
inputRows.addEventListener(&quot;input&quot;, buildTable);
buildTable();
function buildTable() {
const html = Array.from({length: inputRows.value},
_ =&gt; 
&quot;&lt;tr&gt;&quot; +
Array.from({length: inputCols.value},
_ =&gt; &quot;&lt;td&gt;&lt;input&gt;&lt;/td&gt;&quot;
).join(&quot;&quot;) +
&quot;&lt;/tr&gt;&quot;
)
.join(&quot;&quot;);
const table = document.querySelector(&quot;table&quot;);
table.innerHTML = html;
table.querySelector(&quot;input&quot;).focus();
}
document.addEventListener(&quot;keydown&quot;, ({key}) =&gt; {
const delta = { ArrowDown: 1, ArrowUp: -1 }[key];
if (!delta) {
return; // not an arrow up/down key
}
const table = document.querySelector(&quot;table&quot;);
const focused = table.querySelector(&quot;input:focus&quot;);
if (!focused) {
table.querySelector(&quot;input&quot;).focus(); // focus the first input
return;
}
// find next input with given column count
const colCount = table.querySelectorAll(&quot;tr:first-child &gt; td &gt; input&quot;).length;
const inputs = [...table.querySelectorAll(&quot;td &gt; input&quot;)];
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 &amp;&amp; delta &gt; 0) { 
idx = 0;
// first cell, go to last
} else if (idx === 0 &amp;&amp; delta &lt; 0) { 
idx = inputs.length - 1;
// last row, go to next column / first row
} else if (rowIdx === rowCount - 1 &amp;&amp; delta &gt; 0 &amp;&amp; idx) { 
idx = (idx % colCount) + 1;
// first row, go to last row / prevous column
} else if (rowIdx === 0 &amp;&amp; delta &lt; 0 &amp;&amp; idx) { 
idx = (idx % colCount) - 1 + (rowCount - 1) * colCount;
// go to next row
} else { 
idx += delta * colCount;
}
inputs[idx].focus();
});

<!-- language: lang-html -->

&lt;p&gt;
&lt;label&gt;Number of cols
&lt;input id=&quot;colCount&quot; type=&quot;number&quot; min=&quot;2&quot; max=&quot;4&quot; value=&quot;2&quot;&gt;
&lt;/label&gt;
&lt;label&gt;Number of rows
&lt;input id=&quot;rowCount&quot; type=&quot;number&quot; min=&quot;2&quot; max=&quot;10&quot; value=&quot;6&quot;&gt;
&lt;/label&gt;
&lt;/p&gt;
&lt;table&gt;
&lt;/table&gt;

<!-- end snippet -->

huangapple
  • 本文由 发表于 2023年5月30日 06:17:32
  • 转载请务必保留本文链接:https://go.coder-hub.com/76360598.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定