我可以依赖隐式创建标签吗?

时间:2011-09-10 14:04:57

标签: javascript jquery html dom

<!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>

当我以这种方式编写时,它不起作用,因为我的浏览器会自动创建<tbody>标记。所以我要写:

$( "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' ) ) 
});

我可以依赖<tbody>标签的隐式创建,还是我不应该依赖它?

编辑:添加以解释我对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 passed. form.elements返回的其中一个字符串为空。

6 个答案:

答案 0 :(得分:7)

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

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

根据HTML5草案:

  

如果内部的第一件事,可以省略tbody元素的开始标记   tbody元素是一个tr元素,如果元素不是   紧接着是一个tbody thead,或者是tfoot元素的结尾标记   已被省略。

     

如果tbody元素是,则可以省略tbody元素的结束标记   紧接着是tbody或tfoot元素,或者如果没有   父元素中的更多内容。

因此,如果您的代码符合上述条件,您实际上可以省略它,否则需要它。

正如其他人所指出的那样,即使它是需要的,并且html解析器因为你没有写它而找不到它,它也将被插入到DOM中,如html5规范中所述。 / p>

据说,根据经验,永远不会依赖任何人为您自动创作的东西!(见下文)

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


此外,您的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]。或者,如果你有像gilly3建议的嵌套表td > input[id]

答案 1 :(得分:4)

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

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

为了证明我所说的内容,HTML4规范禁止任何<tr>元素作为<table> s的直接子元素:

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

HTML5规范说<tr>在某些情况下可能是<table>的子项,但是这只适用于DOM,而不是标记解析:

  

8.2.5.4.9“在表格中”插入模式

     

...

     

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

     

表示好像已经看到标签名为“tbody”的开始标记令牌,然后重新处理当前令牌。

答案 2 :(得分:3)

您不能依赖浏览器自动创建它。 HTML规范说它应该是可选的,但我相信Firefox和IE会像你看到的那样创建它。您可以使用此属性来了解浏览器的行为(true表示不会添加)

jQuery.support.tbody

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

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

答案 3 :(得分:3)

为了防御tbody标签的可选性质(以及浏览器决定使用其选择器引擎进行扩展),您可以编写两个选择器:

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

但老实说这有点像黑客。你最好明确地添加<tbody>元素并完成它。

或者,考虑一下你为什么甚至使用儿童组合器。

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

答案 4 :(得分:1)

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

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

答案 5 :(得分:1)

如果你试图掌握包含表格的<form>元素中的所有输入,这是错误的方法,因为自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);
}