javascript if 语句中的迭代

javascript iteration within if statement

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

现在,根据另一个 SO 问题的反馈,我尝试通过遍历 table 中所有 td 的数组(所有注释掉的代码)来实现检查,以查看是否 onclick,任何单元格已经分别将 bgcolor 设置为 green/red 如果为真,请将 bgcolor 设置为 empty/blank 以允许新单元格选择获得 bgcolor ,因此应该始终只有 1 个绿色块和 1 个红色块.有人可以向我解释一下我是如何实现循环并检查错误并且没有得到预期结果的。

数组循环在不属于现有代码的情况下有效 here -jsfiddle。但是当我将它添加到需要它的代码中时,它不起作用。

HTML

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

如果您调用 .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"
}

这将使所有背景变为绿色。现在您将不得不修改您的代码,但这就是它的工作原理。更多信息在这里:https://developer.mozilla.org/en-US/docs/Web/API/HTMLCollection

您真正想要做的是用 class 而不是 style 来处理这个问题。原因是您可以使用 getElementsByClassName 轻松提取所有具有特定 class 的元素(注意: 在 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;
}

使用这种方法,在单击时,您要做的第一件事是找到所有具有 class firstClicksecondClick 的元素(基于值click) 并删除 class。因为应该只有一个,最多,这使得一个非常短的循环要经过(但如果以某种方式发生的话,也会从多个元素中删除 class)。

编辑:

所以,你不会在你的代码中注意到它,因为你永远不会有超过两个 classes 中的每一个的实例,但是,作为 somethingthere 指出,我们正在处理 DOM 元素的实时 collection,因此,当您从元素中删除 classes(您从中删除它们的元素, 落在 collection.

之外

例如,在第三次单击 table 时,collection 中将有一个元素由 document.getElementsByClassName(currClass); = HTMLCollection[td.firstClick] 返回(在安慰)。但是,一旦您从元素中删除 class,它就不再符合条件,因此 collection 变为空(即 HTMLCollection[])。

因此,虽然它适用于您的情况(因为它在 i = 1 停止,因为那仍然是 "not less than" collection 的新长度(现在为 0)。

然而,在其他情况下,情况可能并非如此。 . .例如,如果返回了 2 个元素,在第一个元素的 class 被移除后,i 将变为 1,但长度也会下降到 1,循环将停止,而不处理第二个元素。

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

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

。 . .这些行:

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

这样,class 删除的元素始终是 collection 中的第一个元素,并且 while 循环检查以确保在collection,然后尝试删除 class。

所以,长话短说,在处理 HTML Collection 时,正如 somethinghere 指出的那样,您正在处理一个实时 [= DOM 个元素的 79=],因此,如果您进行的更改会影响包含在 Collection 中的单个元素,它 更新 Collection 因此,您需要能够在您的代码中考虑到这一点。