JavaScript 在我添加一个中断后销毁所有 children?

JavaScript destroys all children after I append a break?

我正在创建一个脚本,该脚本接受两个输入维度、宽度和高度,并创建一个缩放网格,该网格表示具有给定尺寸的框中可以容纳多少块,函数如下:

function makeRow() {
        for (var i = 1; i <= blocksTall; i++) {
            var mb = document.createElement("div");
            mb.setAttribute("class", "matrix-block mb-off");
            mb.setAttribute("onClick", "select_mb('" + j + "," + i + "');");
            placeBlocks.appendChild(mb);
            if (i = blocksWide) {
                placeBlocks.appendChild('br');
            }
        }
    }

这个函数可以很好地显示块的第一行,然后在该行完成渲染后插入一个 break 标记,这正是我想要做的。问题是我需要再生成 17 行,具有相同数量的块,每个块都在前一行下面,所以我的第一个想法是,我将在第一个 for 循环周围再包装一个 for 循环,因为有一个 break在那里,它将在前一行下方呈现新行:

for (var j = 1; j <= blocksTall; j++) { // Vertical for loop.

    for (var i = 1; i <= blocksWide; i++) { // Horizontal for loop.
        var mb = document.createElement("div");
        //mb.setAttribute("id", "matblock-" + i + "-" + j);
        mb.setAttribute("class", "matrix-block mb-off");
        mb.setAttribute("onClick", "select_mb('" + i + "," + j + "');");
        placeBlocks.appendChild(mb);
    }

    if (j = blocksWide) {
        placeBlocks.appendChild(brk);
    }

}

其中 blocksWide = 17。Here is a fiddle 包含完整的脚本。当我在控制台中记录 j 的值时,它实际上会递增(这告诉我 for 循环正在运行)。似乎正在发生的事情是由于某种原因渲染该行,然后在其顶部渲染新行(似乎不太可能,因为 break 标记在每行完成后渲染)或者由于某种原因 [=每次新的 "horizontal" for 循环是 运行.

时,27=] 都会被销毁

有谁知道为什么会发生这种情况,以及如何正确地将每一行附加到最后一行下面,以便生成块网格而不是仅仅一行?

在此先致谢,非常感谢任何帮助。

所以,我对你脚本的某些方面有点困惑,但我认为你有两个主要问题。

首先,您只调用 document.createElement("br") 一次,这意味着您只创建一个换行符;并且单个换行符只能出现在 DOM 中的一处。这个:

        placeBlocks.appendChild(brk);

从 DOM 中的当前位置删除 brk,然后将其放在 placeBlocks 的末尾。您应该将其更改为:

        placeBlocks.appendChild(document.createElement("br"));

其次,我认为if (j = blocksWide) {没有道理。请注意,它等同于:

j = blocksWide;
if (blocksWide != 0) {

这意味着它通过操纵 j 的值来干扰您的 for 循环。我认为该问题的解决方法是简单地删除整个 if-check,并无条件地执行其主体。

我真的不明白你想用余数运算符和除法做什么,但是 blocksWide 解析为无穷大导致无限循环,而 blocksHigh 只是 17。所有full 之外的其他变量未被使用。


您实际上不需要两个循环,尽管这样做是可以的。如果你只想使用一个循环,你基本上只需要知道 i 是否是 dispW 的倍数。

所以你用 i 除以 dispW 然后你想知道它是否是一个整数,要找到这个你使用 1 的余数运算符,如果它解析为 0 是整数。看起来像这样...

if ((i / dispW) % 1 === 0) 
    // if ( dispW=3 && ( i=3 || i=6 || i=9 || ... ) ) true;

这个循环看起来像

totalWidth = dispW * dispH; // total number of blocks
for (var i = 1; i <= totalWidth; i++) {
    // do stuff;
    if((i / dispW) % 1 === 0) {
        // insert new line break;
    }
}

您用于 select 积木的方法是一种迂回的方法。首先你不应该使用内联 javascript,其次你不应该使用 javascript 将内联 javascript 嵌入动态创建的元素中。请改用 element.onclick = function;

注意函数后面没有大括号。这是因为您实际上传递的是函数引用而不是函数的返回值。

element.onclick 将事件对象传递给函数引用。您可以使用它来 select 像这样被点击的块。

for ( ... ) {
    ...
    var element = document.createElement('div');
    element.onclick = myFunction;
    ...
}

function myFunction(e) {
    var clicked = e.target // this is the element that was clicked on
}

另外,您在循环之外创建了一个 <br> 元素。因为 appendChild 移动元素而不创建元素,所以它只会继续移动换行符直到循环结束。它应该是这样的。

placeBox.appendChild(document.createElement('br')) 
    // append a newly created line break;

那么即使所有逻辑都按预期工作并且您每次都创建一个新的换行符,浮动块意味着没有换行符,而是使用 display: inline-block;

所以最后你得到的是...

(Full difference)

window.onload = function () {
    renderGrid();
};
function renderGrid() {
    var blocksTall = document.getElementById('height-in').value;
    var blocksWide = document.getElementById('width-in').value;
    var blocksTotal = blocksWide * blocksTall;
    var placeBlocks = document.getElementById('matrix-shell');
    while (placeBlocks.firstChild) {
        placeBlocks.firstChild.remove();
    }
    console.log(blocksWide + "/" + blocksTall);
    for (var i = 1; i <= blocksTotal; i++) {
        var mb = document.createElement("div");
        mb.className = 'matrix-block mb-off';
        mb.onclick = select_mb;
        placeBlocks.appendChild(mb);
        if (((i / blocksWide) % 1) === 0) {
            var brk = document.createElement("br");
            placeBlocks.appendChild(brk);
        }
    }
}
function select_mb(e) {
    var cur_mb = e.target;
    if (cur_mb.className == "matrix-block mb-off") {
        // Turn cell on.
        cur_mb.style.backgroundColor = "#00FF00";
        cur_mb.className = "matrix-block mb-on";
    } else {
        //Turn cell off.
        cur_mb.style.backgroundColor = "#000";
        cur_mb.className = "matrix-block mb-off";
    }
}
.matrix-block {
    height: 10px;
    width: 10px;
    border: 1px solid #fff;
    display: inline-block;
    background-color: black;
}
.mb-off {
    background-color: black;
}
#matrix-shell {
    font-size: 0;
    display: inline-block;
    border: 1px solid red;
    white-space: nowrap;}
<table>
    <tr>
        <td>Width:</td>
        <td>
            <input id="width-in" name="width-in" type="text" />
        </td>
    </tr>
    <tr>
        <td>Height:</td>
        <td>
            <input id="height-in" name="height-in" type="text" />
        </td>
    </tr>
    <tr>
        <td colspan="2">
            <button onClick="renderGrid()">Compute</button>
        </td>
    </tr>
</table>
<br/>
<div id="matrix-shell"></div>