【问题标题】:Can I rely on the implicit creation of the `<tbody>` tag?我可以依赖 `<tbody>` 标签的隐式创建吗?
【发布时间】:2011-11-14 09:27:27
【问题描述】:
<!DOCTYPE html>
<html>
<head>
  <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
  <script src="https://ajax.googleapis.com/ajax/libs/jquery/1.6.3/jquery.min.js"></script>
  <script type="text/javascript">
    $( document ).ready( function(){
      $( "table > tr > td > input[id]" ).each( function( i, element ){ 
        alert( $( element ).attr( 'id' ) ) 
      });
    });
  </script>
</head>
<body>
  <form>
    <table>
      <tr><td>City:</td><td><input type="text" id="city" name="city" /></td></tr>
      <tr><td>state:</td><td><input type="text" id="state" name="state" /></td></tr>
    </table><br />
    <input type="submit" value="OK"/>
  </form>
</body>
</html>

当我这样写时,它不起作用,因为我的浏览器会自动创建一个&lt;tbody&gt; 标签。所以我必须写:

$( "table tr > td > input[id]" ).each( function( i, element ){ 
  alert( $( element ).attr( 'id' ) ) 
});

或:

$( "table > tbody > tr > td > input[id]" ).each( function( i, element ){ 
  alert( $( element ).attr( 'id' ) ) 
});

我可以依赖 &lt;tbody&gt; 标签的隐式创建,还是不应该指望它?

编辑:添加以解释我对 Tim Down 的回答的评论:

<!DOCTYPE html>
<html>
<head>
  <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
  <script src="https://ajax.googleapis.com/ajax/libs/jquery/1.6.3/jquery.min.js"></script>
  <script src="https://ajax.googleapis.com/ajax/libs/jqueryui/1.8.16/jquery-ui.js"></script>
  <script type="text/javascript">
    $( document ).ready( function() {
      var ids = [];
      var form = document.forms[0];
      var formEls = form.elements;
      var f_len = formEls.length;

      for ( var i = 0; i < f_len; ++i ) {
        ids.push( formEls[i].id );
      }

      var data = [ [ 'one', 'two', 'thre' ], [ 'four', 'five', 'six' ] ];
      var ids_len = ids.length;

      for ( i = 0; i < ids_len; i++ ){
        $( "#" + ids[i] ).autocomplete({
          source: data[i]
        });
      }
    });
  </script>
</head>
<body>
  <form>
    <table>
      <tr><td>A:</td><td><input type="text" id="a" name="a" /></td></tr>
      <tr><td>B:</td><td><input type="text" id="b" name="b" /></td></tr>
    </table><br />
    <input type="submit" value="OK"/>
  </form>
</body>
</html>

当我运行它时,Web 控制台会向我显示如下警告:Empty string to getElementById() is passedform.elements 返回的字符串之一为空。

【问题讨论】:

  • 您只需在表单中添加一个 id,然后循环遍历 HTMLFormElement.elements 集合,就可以省去很多麻烦。请注意,像您帖子中的那些可怕的查询非常缓慢且有问题。
  • 密切相关:stackoverflow.com/questions/938083/… 。那里的答案也会解释规范。

标签: javascript jquery html dom


【解决方案1】:

如果您试图获取包含表格的 &lt;form&gt; 元素中的所有输入,那么这是错误的方法,因为自 JavaScript 诞生以来就存在一种简单的 DOM 方法并且适用于所有曾经发布的主要可编写脚本的浏览器。表单元素有一个elements 属性,它是表单中所有表单控件的集合。您只需获取表格,您可以通过最适合您的方式进行操作:

var form = document.forms[0];
var formEls = form.elements;
for (var i = 0, len = formEls.length; i < len; ++i) {
    alert(formEls[i].id);
}

【讨论】:

  • 这样写for (var i = 0; i &lt; formEls.length; ++i) {慢吗?
  • 这样,如果我处理来自data.push( formEls[i].id)data(而不是使用alert(formEls[i].id) 发出警报),我会得到一个空字符串和警告。
  • @sid_com: 只访问一次elements 集合的length 属性并将其存储在一个变量中可能比每次迭代都访问它稍微快一些,但这将是一个微小的收益普通脚本的上下文。不过,我不明白您在第二条评论中所说的内容。你能详细说明一下吗?
  • 在我的问题中添加了一个示例。
  • @sid_com:可能问题是elements 集合还包含提交按钮,它没有ID。您可以按类型过滤元素:if (formEls[i].type == "text") {...}
【解决方案2】:

这不是依赖它是否自动创建的问题。

问题是它是否是强制性的。

根据 HTML5 草案:

如果里面的第一件事,可以省略 tbody 元素的开始标签 tbody 元素是 tr 元素,如果该元素不是 紧随其后的是一个 tbody thead 或 tfoot 元素,其结束标签 已省略。

如果 tbody 元素是 紧跟一个 tbody 或 tfoot 元素,或者如果没有 父元素中的更多内容。

所以如果你的代码满足以上条件,其实可以省略,否则需要。

正如其他人指出的那样,即使需要它,并且 html 解析器不会找到它,因为您没有编写它,它会为您插入到 DOM 中,如 html5 规范中所述。

这就是说,根据经验,永远不要依赖任何人为您自动创建东西!(见下文)

因此,即使浏览器会为您创建它,这并不意味着较新的浏览器或同一浏览器的新版本将遵循相同的方式,并且您的代码可能会被破坏。


另外,你的 JS 可以优化。

$( document ).ready( function(){
    $( "td > input[id]" ).each( function( i, element ){ 
        alert( element.id );
    });
});
  1. 始终在语句末尾写分号。 不要依赖 JS 引擎为你编写它们!!!(见上文)。

  2. 无需调用jQuery函数并从元素中创建一个jQuery对象,只需调用attr()方法获取id即可。 JavaScript 已经有 id() 方法来检索 id。

  3. 如果您的实际标记与您在答案中发布的标记一样,您可以这样编写 jQuery 选择器:table input[id]。或者,如果您有嵌套表 td &gt; input[id] 就像 gilly3 建议的那样。

【讨论】:

  • 关于第 3 点 - 考虑嵌套表。当然,在发布的示例中也将选择嵌套表,但实际代码可能在表上具有更强的选择器。如果嵌套表无关紧要,您可能需要td &gt; input[id] 以确保输入没有嵌套在 div 中或包含在 th 中。
  • @gilly3:没错,这就是为什么我没有在我发布的代码中写修改,而只是暗示,因为这取决于具体情况。
  • Re 你的主要答案 - 你的论点的症结在于什么是有效的 HTML,但 jQuery 作用于 DOM,而不是标记。该文档似乎表明,如果缺少&lt;tbody&gt;,则应隐式创建一个。请参阅 Duri 的回答。
  • tbody 标签可以在源代码中省略(与 html 标签一样),但解析算法确保它是在 DOM 中创建的(参见duri's answer)。所以你的答案是不正确的,因为 jQuery 选择器作用于 DOM,而不是源。
  • 谢谢,现在更清楚了,您确实在回答 other,但非常相关的问题:“是否需要 tbody 标签?”和“依靠它的隐式创造是个好主意吗?”
【解决方案3】:

为了防止 tbody 标记的可选特性(以及浏览器决定对其选择器引擎进行的任何扩展),您可以写出两个选择器:

$('table > tbody > tr > td, table > tr > td').find('input[type="text"]')

但老实说,这有点小题大做。您最好明确添加 &lt;tbody&gt; 元素并完成它。

或者,考虑一下你为什么要使用子组合器。

在您的示例中,我不知道您为什么需要使用如此复杂的选择器。您不是嵌套表(因此无需使用子组合器),并且您只有两个文本输入。如果您只需要两个文本输入字段,只需使用$('input[type="text"]')

【讨论】:

  • 这确实是不必要的并且容易出错。请看tvanfosson的回答。
  • 我理解 tvanfosson 的回答,但这并不能解释为什么您似乎认为我的回答容易出错。
  • @feeela 这种方法比 tvanfossons 的方法更不容易出错。通过使用后代选择器而不是子选择器,您还可以匹配当前表内的表的&lt;td&gt; 元素。
【解决方案4】:

我不同意@spike 的回答,至少如果我们谈论普通的HTML 解析(不使用innerHTML)。每个tr 都成为隐式创建的tbody 的子代,除非它已经是另一个theadtbodytfoot 的子代。 jQuery.support.tbody 用于使用 innerHTML 或可能其他 DOM 方法创建的表。如果您在标记中省略 &lt;tbody&gt;,则始终插入。

tbody 元素不是可选的,它只有可选的开始和结束标记。怀疑隐式创建 tbody 与怀疑隐式创建 htmlbody 元素的错误类似。

为了证明我所说的,HTML4 规范禁止将任何&lt;tr&gt; 元素作为&lt;table&gt;s 的直接子元素:

<!ELEMENT TABLE - -
 (CAPTION?, (COL*|COLGROUP*), THEAD?, TFOOT?, TBODY+)>

HTML5 规范规定 &lt;tr&gt; 在某些情况下可以是 &lt;table&gt; 的子代,但这仅适用于 DOM,不适用于标记解析:

8.2.5.4.9 “in table”插入模式

...

标签名称为以下之一的开始标签:“td”、“th”、“tr”

就好像已经看到了一个标记名为“tbody”的开始标记标记,然后重新处理当前标记。

【讨论】:

  • "tbody 元素不是可选的" 嗯,是的。至少规范中不需要它,因为一个表可能有tr作为孩子,没有包装tbody。 (HTML4·;HTML5)
  • @feeela 这仅适用于 DOM,不适用于 HTML 解析。我已经编辑了我的答案并引用了规范的相关部分。 OP的问题显然与标记解析有关。
  • 这是一个有趣的观点,我很想看到一些关于它的文档。 DOM 是否总是对应​​于 HTML?也就是说,是否意味着省略一个可选的 HTML 元素只是让浏览器自动创建 DOM 元素的快捷语法?
  • 哇,您在我完成输入之前就解决了我的评论。做得很好!这意味着正确答案是肯定的,您可以依靠浏览器为您创建一个&lt;tbody&gt;
  • @gilly3 是的,如果是&lt;tbody&gt;,您可以。但是,至少在一种情况下依赖隐式创建开始或结束标签是不安全的:&lt;p&gt; 元素具有可选的结束标签,而 HTML4 和 HTML5 规范指定了隐式关闭 &lt;p&gt; 的元素列表;其中一个元素是&lt;table&gt;。这意味着&lt;p&gt;&lt;table&gt;&lt;/table&gt; 应该表示&lt;p&gt;&lt;/p&gt;&lt;table&gt;&lt;/table&gt;,并且表格应该匹配CSS 选择器p + table。但是,至少在 Firefox 的 quirks 模式(不是标准模式)中,行为完全相反,并且 table 匹配 p &gt; table 选择器。
【解决方案5】:

您不能依赖浏览器自动创建它。 HTML 规范说它应该是可选的,尽管我相信 Firefox 和 IE 如您所见创建它。您可以使用此属性来了解浏览器的行为方式(true 表示不会添加)

jQuery.support.tbody

在一堆浏览器中查看这个示例: http://jsfiddle.net/CuBX9/1/

http://api.jquery.com/jQuery.support/

【讨论】:

    【解决方案6】:

    您可以只使用descendant selector 而不是父选择器,或者如果输入是td 的子元素很重要,则可以使用某种组合。这样就无所谓了。相反,您也可以只放入 tbody 元素并使用完整的父/子链而无需担心。

    $('table td > input[id]') 
    

    【讨论】:

      猜你喜欢
      • 2012-01-09
      • 1970-01-01
      • 1970-01-01
      • 2011-01-23
      • 1970-01-01
      • 1970-01-01
      • 2012-08-05
      • 1970-01-01
      • 2010-12-15
      相关资源
      最近更新 更多