在此JSFiddle中(问题代码已注释掉),空单元格中的第一次单击会在隐藏输入中设置值,并将单元格的bgcolor设置为绿色。单击第二个空表格单元格设置另一个隐藏输入的值,并将第二个单元格bgcolor更改为红色。
现在,基于来自另一个SO问题的反馈,我试图通过循环遍历表中所有td的数组(所有注释掉的代码)来检查是否onclick,任何单元格已经将bgcolor设置为分别为绿色/红色,如果为真,则将bgcolor设置为空/空白以允许新单元格选择获取bgcolor,因此应始终只有1个绿色块和1个红色块。有人可以向我解释我是如何实现循环并检查错误而没有得到预期的结果。
当不是现有代码的一部分时,数组循环工作here -jsfiddle。但是当我将它添加到需要它的代码时,它不起作用。
HTLM
<div id="starget"></div>
<div id="etarget"></div>
<table width="100%" id="test">
<thead>
<tr>
<th>Tech</th>
<th>0800</th>
<th>0900</th>
<th>1000</th>
<th>1100</th>
<th>1200</th>
</tr>
</thead>
<tr>
<td>Bill</td>
<td>XXX</td>
<td onclick="res(0900,this);"></td>
<td>XXX</td>
<td>XXX</td>
<td onclick="res(1200,this);"></td>
</tr>
</table>
SCRIPT
var x = 0;
var click = 0;
/* tdElements = document.getElementsByTagName("td"); */
/* I have tried the tdelements array inside and outside of the function */
function res(zz,el) {
if (click == 0) {
/* for(var key in tdElements) {
if (tdElements[key].style.backgroundColor=="green") {
tdElements[key].style.backgroundColor="";
}
} */
document.getElementById('starget').innerHTML=zz;
click = 1;
el.style.backgroundColor='green';
}
else {
/* for(var key in tdElements) {
if (tdElements[key].style.backgroundColor=="red") {
tdElements[key].style.backgroundColor="";
}
} */
document.getElementById('etarget').innerHTML=zz;
click = 0;
el.style.backgroundColor='red';
}
}
答案 0 :(得分:2)
如果您致电.getElementsByTagName
,则无法取回array
!您将返回 live HTMLCollection
元素,其中包含使用for.. in
循环时无法忽略的其他项目。如果你的for
包含HTMLCollection
你可以使用的length
,/* HTMLCollections come with a length attribute we can use
* as every item is numbered, but in a object-style key-value pair */
for(var i = 0; i < tdElements.length; i++){
/* This was tripping up your code - the `item` function to fetch an
* element at the index defined in the HTMLCollection*/
tdElements.item(i).style.backgroundColor = "green"
}
循环会派上用场![/ p>
{{1}}
这会将所有背景变为绿色。现在你必须修改你的代码,但这就是它的工作原理。更多信息:https://developer.mozilla.org/en-US/docs/Web/API/HTMLCollection
答案 1 :(得分:0)
您真正想要做的是使用class
处理此问题,而不是style
。原因是您可以使用getElementsByClassName
(IE 9及更高版本中的注意:)轻松提取具有特定类的所有元素。
在不偏离您的方法的情况下(我确实让它更有效率:)),您的代码需要更改为:
<强> CSS:强>
.firstClick {background-color: green;}
.secondClick {background-color: red;}
<强>脚本:强>
var click = 0;
function res(zz,el) {
var currentlyClickedEls, currClass, divTarget;
if (click === 0) {
currClass = "firstClick";
divTarget = "starget";
click = 1;
}
else {
currClass = "secondClick";
divTarget = "etarget";
click = 0;
}
// get all the elements with the appropriate class
currentlyClickedEls = document.getElementsByClassName(currClass);
// remove that class from those elements
while (currentlyClickedEls.length > 0) {
currentlyClickedEls[0].className = "";
}
// add the class to the clicked element
el.className = currClass;
document.getElementById(divTarget).innerHTML = zz;
}
使用这种方法,在点击时,您要做的第一件事就是找到包含类firstClick
或secondClick
的所有元素(基于click
的值)并删除该类。因为只有一个,最多只能使一个非常短的循环通过(但也会从多个元素中删除该类,如果以某种方式发生)。
修改强>
所以,你不会在你的代码中注意到它,因为你不会拥有这两个类中每个类的多个实例,但是,因为某些东西指向out,我们正在处理DOM元素的LIVE集合,因此,当您从元素中删除类时(从中删除它们的元素,不属于集合。
例如,在第三次单击表时,document.getElementsByClassName(currClass);
= HTMLCollection[td.firstClick]
(在控制台中)将返回集合中的一个元素。但是,一旦您从元素中删除了该类,它就不再符合条件,因此集合变为空(即HTMLCollection[]
)。
所以,虽然它适用于你的情况(因为它在i = 1
停止,因为它仍然是&#34;不小于&#34;集合的新长度(现在为0)。
但是,在其他情况下,情况可能并非如此。 。 。例如,如果返回了2个元素,则在第一个元素被删除后,i
将更改为1,但长度也将减少到1并且循环将停止,而不处理第二个元素。 / p>
因此,确实需要更改方法以正确处理该行为。我通过改变这些方式来做到这一点:
for (i = 0; i < currentlyClickedEls.length; i++) {
currentlyClickedEls[i].className = "";
。 。 。这些行:
while (currentlyClickedEls.length > 0) {
currentlyClickedEls[0].className = "";
这样,删除它的类的元素始终是集合中的第一个元素,while
循环检查以确保集合中有一个元素,然后才会尝试删除班级。
所以,很长一段时间,简而言之,在处理HTML集合时,正如某事指出的那样,您正在处理DOM元素的实时集合,因此,如果您进行的更改会影响该集合中包含单个元素,将相应地更新集合,您需要能够在代码中对其进行说明。