【问题标题】:Strange FOR loop behaviour in JavascriptJavascript 中奇怪的 FOR 循环行为
【发布时间】:2014-03-15 18:41:58
【问题描述】:

我正在尝试生成一个包含 3 行和 3 个单元格的表格 例如

<table>
<tr>
   <td> 00 </td>    <td> 01 </td>    <td> 02 </td>
</tr>
<tr>
   <td> 10 </td>    <td> 11 </td>    <td> 12 </td>
</tr>
<tr>
   <td> 20 </td>    <td> 21 </td>    <td> 22 </td>
</tr>
</table>

我用来执行此操作的 Javascript 是:

tab = document.getElementById('tab');
for(i=0; i<3; i++)
{ 
 tab.innerHTML += '<tr>';

  for(j=0; j<3; j++) 
  {
   tab.innerHTML += '<td id="'+i+''+j+'">'+i+''+j+'</td>'; 
  }

 tab.innerHTML += '</tr>';
}

HTML 是:

<table id="tab">
</table>

但是,当我运行代码时,所有表格元素都位于第一列,因此我得到的不是 3x3 表格,而是 1x9 表格。

有人知道我做错了什么吗?

【问题讨论】:

  • tab = document.getElementById('tab');这不存在..
  • 当您将 tr/tds 保存到变量并仅写入 tab 一次时会发生同样的事情吗?
  • @Pogrindis getElementById() 是一个函数...
  • 但是tab的id元素在调用时不存在。

标签: javascript loops for-loop html-table


【解决方案1】:

选项 #1

您应该为此任务使用辅助字符串变量:

var tab = document.getElementById('tab'),
    str = '';

for (var i = 0; i < 3; i++) {
    str += '<tr>';

    for (var j = 0; j < 3; j++) {
        str += '<td id="' + i + '' + j + '">' + i + '' + j + '</td>';
    }

    str += '</tr>';
}

tab.innerHTML = str;

演示:http://jsfiddle.net/hrrKg/

选项 #2

我也建议使用表格 API

var tab = document.getElementById('tab');

for (var i = 0; i < 3; i++) {
    var row = tab.insertRow(i);
    for (var j = 0; j < 3; j++) {
        var cell = row.insertCell(j);
        cell.id = i + '' + j;
        cell.innerHTML = i + '' + j;
    }
}

演示:http://jsfiddle.net/hrrKg/1/


基本上为什么会发生。每当您设置以下内容时:

tab.innerHTML += '<tr>'

表格内容变为无效的 HTML,因此浏览器会自动对其进行修复,使其看起来像一些东西:

<tbody><tr></tr></tbody>

更多的循环使它更加混乱,因此产生了结果。

也可以看看 cookie monster 的回答,因为它对我来说更全面。

【讨论】:

  • 钻石啊,它有效。你知道为什么你必须这样做吗?还是只是其中之一?
  • 当你设置 innerHTML 属性时,浏览器会解析它并创建一个对象的 DOM 树集。您不能像普通字符串一样将 innerHTML 可靠地连接起来。
【解决方案2】:

您将 DOM 视为您编写的 HTML。

当你这样做时

.innerHTML += "<tr>"

..你正在创建一个完整的 &lt;tr&gt;&lt;/tr&gt; 元素。 DOM 中没有“半个元素”这样的东西。


然后在那之后,当你 += &lt;td&gt; 元素时,它们现在会你刚刚创建的 &lt;tr&gt; 之后进行,这是无效的,所以浏览器会尽可能地纠正它可以的。

// This is going after the <tr></tr>
tab.innerHTML += '<td id="'+i+''+j+'">'+i+''+j+'</td>'; 

最后,当你这样做时

.innerHTML += "</tr>"

您只是添加了无效的 HTML,因此它可能会被忽略。


此外,.innerHTML += "...content..." 的使用非常糟糕。它首先将之前的 DOM 节点序列化为 HTML,销毁这些 DOM 节点,将新的 HTML 添加到刚刚序列化的内容中,然后解析该 HTML 以创建 (并重新创建) 节点。

因此,每次迭代,您都在销毁和重新创建您在该点之前的所有迭代中创建的所有内容。这种破坏效率极低,而且是不必要的。相反,构建整个字符串,然后使用.insertAdjacentHTML()

tab = document.getElementById('tab');

var html = ""
for(i=0; i<3; i++)
{ 
 html += '<tr>';

  for(j=0; j<3; j++) 
  {
   html += '<td id="'+i+''+j+'">'+i+''+j+'</td>'; 
  }

 html += '</tr>';
}

tab.insertAdjacentHTML("beforeend", html);

【讨论】:

  • 嗯。真的很翔实。谢谢 :) 如果你能提供引用,那就太棒了。
  • 所以将整个 tr/td 写入一个单独的变量并且只将其写入选项卡一次应该是解决方案吗?
  • 所以每次设置 innerHTML 时,浏览器都会渲染它?所以 OP 以&lt;tr&gt;&lt;/tr&gt;&lt;td&gt;01&lt;/td&gt;&lt;/tr&gt; 结尾?我需要记住这一点!哈哈
  • @thefourtheye:我真的没有什么可引用的。 .innerHTML 基本上就像页面加载时一样解析 HTML。所以如果它得到的输入是&lt;tr&gt;,它不知道会有更多的输入,所以它会尽可能地渲染它。由于&lt;tr&gt; 元素不需要结束标签,它只是将其关闭。
  • @RonnyLindner:主要是。另一个问题是将+=.innerHTML 一起使用,这是一种非常具有破坏性的方法。我已经用使用 .insertAdjacentHTML() 的解决方案更新了我的答案。
【解决方案3】:

替代string:

tab = document.getElementById('tab');
for(i=0; i<3; i++)
{ 
 var tr = document.createElement("tr");

  for(j=0; j<3; j++) 
  {
    var td = document.createElement("td");
    td.id = i+''+j;
    td.innerHTML= i+''+j
    tr.appendChild(td); 
  }

 tab.appendChild(tr);
}

FIDDLE

【讨论】:

    【解决方案4】:

    您添加一次&lt;tr&gt; 的问题本身就是无效的 HTML 并被自动删除。你可以这样做:

    tab = document.getElementById('tab');
    for(i=0; i<3; i++)
    { 
     var html = '<tr>';
    
      for(j=0; j<3; j++) 
      {
       html += '<td id="'+i+''+j+'">'+i+''+j+'</td>'; 
      }
    
     tab.innerHTML += html + '</tr>';
    }
    

    【讨论】:

    • OP 正在使用 += 所以这不会发生。
    • 代码是+=而不是=,这不应该删除内容
    • 如果是这种情况,我不会得到任何输出,但是当我运行我得到的代码时,我会得到:00 01 02 10 11 12 20 21 22
    • 问题你不能只添加“”它需要是完整的html标签:“ ”
    • @PetarVasilev,是的,我在 dfsq 的回答中看到了这一点.. 甚至不知道发生了什么事哈!我通常使用 createElement,所以以前从未尝试过。每天学习新东西...
    【解决方案5】:

    我做了一些小的调整,让它在 fiddler 中工作:

    tab = document.getElementById('tab');
    
    var result = "<tbody>";
    for(i=0; i<3; i++)
    { 
     result += '<tr>';
    
      for(j=0; j<3; j++) 
      {
       result += '<td id="'+i+''+j+'">'+i+''+j+'</td>'; 
      }
    
     result += '</tr>'; 
    }
    result += "</tbody>";
    
    console.log(result)
    tab.innerHTML = result;
    

    【讨论】:

      【解决方案6】:

      与 MamaWalter 的回答一样,这是一种使用 DOM 节点而不是字符串连接的替代功能方法:

      var tab = document.getElementById('tab');
      
      var bind = Function.prototype.bind,
          $tr = bind.call(Document.prototype.createElement, document, "tr"),
          $td = bind.call(Document.prototype.createElement, document, "td"),
          $text = bind.call(Document.prototype.createTextNode, document),
          appender = function(parent, child) {
            parent.appendChild(child);
            return parent;
          },
          wrapWith = function(fn, child) { return appender(fn(), child); },
          wrapWithTd = wrapWith.bind(undefined, $td);
      
      var outer = [1,2,3], inner = [1,2,3];
      
      outer.map(function(row) {
        function createCellContents(col) {
          return $text(row+ '' + col);
        }
      
        return inner
          .map(createCellContents)
          .map(wrapWithTd)
          .reduce(appender, $tr());
      }).reduce(appender, tab);
      

      jsbin 供参考。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2019-02-11
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多