在此JSFiddle(问题代码已注释掉)中,第一次单击将其设置为隐藏输入中的值,并将该单元格的bgcolor设置为绿色。单击第二个空表单元格将设置另一个隐藏输入的值,并将第二个单元格bgcolor更改为红色。

现在,基于来自另一个SO问题的反馈,我试图通过遍历表中所有td的数组(所有已注释掉的代码)来执行检查,以查看是否onclick,任何单元格已将bgcolor设置为绿色/红色如果分别为true,则将bgcolor设置为empty / blank,以允许NEW单元格选择获得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>


脚本

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';
    }
}

最佳答案

您真正想做的是使用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;
}


使用这种方法,单击时,要做的第一件事就是找到所有类为firstClicksecondClick(基于click的值)的元素,然后删除该类。由于最多只应该有一个,所以这将导致非常短的循环(但是如果发生某种情况,也将从多个元素中删除该类)。

编辑:

因此,您不会在代码中注意到它,因为两个类的每个实例都不会有一个以上的实例,但是,正如所指出的那样,我们正在处理DOM元素的LIVE集合,因此,当您从元素中删除类时(从中删除它们的元素会从集合中掉出来。

例如,在表的第三次单击上,集合中将有一个元素由document.getElementsByClassName(currClass); = HTMLCollection[td.firstClick]返回(在控制台中)。但是,一旦您从元素中删除了该类,该类将不再符合条件,因此该集合将变为空(即HTMLCollection[])。

因此,尽管它适用于您的情况(因为它在i = 1上停止,因为它仍然“不少于”集合的新长度(现在为0))。

但是,在其他情况下,情况可能并非如此。 。 。例如,如果返回了2个元素,则在删除第一个元素的类后,i会更改为1,但长度也将降至1,并且循环将停止,而不处理第二个元素。

因此,确实需要更改方法以正确处理该行为。我通过更改以下行来做到这一点:

    for (i = 0; i < currentlyClickedEls.length; i++) {
        currentlyClickedEls[i].className = "";


。 。 。这些行:

    while (currentlyClickedEls.length > 0) {
        currentlyClickedEls[0].className = "";


这样,已删除其类的元素始终是集合中的第一个元素,并且while循环在尝试删除该类之前检查以确保集合中仍然存在一个元素。

因此,长话短说,在处理HTML集合时,正如此处所指出的,您正在处理的是DOM元素的实时集合,因此,如果进行更改会影响该集合中包含的单个元素,则它将相应地更新集合,您需要能够在代码中说明这一点。

10-08 02:42