Подтвердить что ты не робот

Могу ли я полагаться на неявное создание тега `tbody`?

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

Когда я запустил это, веб-консоль покажет мне предупреждение примерно так: Empty string to getElementById () is passed.
Одна строка из строк, возвращаемых form.elements, пуста.

4b9b3361

Ответ 1

Это не вопрос о том, как он автоматически создается или нет.

Вопрос в том, обязателен он или нет.

Согласно проекту HTML5:

Начальный тег элемента tbody может быть опущен, если первое, что внутри элемент tbody является элементом tr, и если элемент не является сразу же предшествует тета-теад или элемент tfoot, конечный тег был опущен.

Тег конца тега элемента может быть опущен, если элемент tbody сразу же следует элемент tbody или tfoot, или если нет больше содержимого в родительском элементе.

Таким образом, вы можете фактически опустить его, если ваш код удовлетворяет вышеуказанным условиям, в противном случае это необходимо.

Как указывали другие люди, даже если это необходимо, и синтаксический анализатор html не найдет его, потому что вы его не записали, он будет вставлен в DOM для вас, как указано в спецификациях html5.

Это, как правило, никогда не полагается на тех, кто создает что-то автоматически для вас! (см. ниже)

Таким образом, даже если браузер создаст его для вас, это не означает, что новые браузеры или новая версия того же браузера будут следовать одинаково, и тогда ваш код может сломаться.


Кроме того, ваш JS может быть оптимизирован.

$( document ).ready( function(){
    $( "td > input[id]" ).each( function( i, element ){ 
        alert( element.id );
    });
});
  • Всегда записывайте точки с запятой в конце инструкций. Не полагайтесь на JS-движок, пишите их для вас. (см. выше).

  • Не нужно вызывать функцию jQuery и создавать объект jQuery из элемента, чтобы вызвать метод attr() для получения идентификатора. JavaScript уже имеет способ id() для получения идентификатора.

  • Если ваша фактическая разметка похожа на ту, которую вы отправили в ответ, вы можете написать селектор jQuery следующим образом: table input[id]. Или, если у вас есть вложенные таблицы td > input[id], как рекомендовал gilly3.

Ответ 2

Я не согласен с ответом @spike, по крайней мере, если говорить об обычном разборе HTML (не используя innerHTML). Каждый tr становится потомком неявно созданного tbody, если он не является потомком другого thead, tbody или tfoot. jQuery.support.tbody предназначен для таблиц, созданных с помощью innerHTML или, возможно, для других методов DOM. Если вы опустите <tbody> в разметке, он всегда вставлен.

Элемент tbody не является необязательным, он имеет необязательный как открытый, так и закрывающий тег. Чтобы сомневаться в неявном создании tbody, возникает аналогичная ошибка, связанная с сомнением в неявном создании элемента html или body.

Чтобы доказать, что я сказал, спецификация 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" , а затем обработайте текущий токен.

Ответ 3

Вы не можете полагаться на браузер, автоматически создавая его. Спецификация HTML говорит, что она должна быть необязательной, хотя я считаю, что Firefox и IE создают ее, как вы видели. Вы можете использовать это свойство, чтобы узнать, как работает браузер (true означает, что он не будет добавлен)

jQuery.support.tbody

Проверьте этот пример в кучке браузеров: http://jsfiddle.net/CuBX9/1/

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

Ответ 4

Чтобы защитить от необязательного характера тега tbody (и, в любом случае, что браузер решит сделать с его движком выбора), вы можете записать оба выбора:

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

Но это честно немного взломать. Вам было бы лучше явно добавить элемент <tbody> и сделать с ним.

В качестве альтернативы рассмотрите, почему вы вообще используете детское комбинатор.

В вашем примере я не знаю, почему вам нужно использовать такой сложный селектор. Вы не вложенные таблицы (так что не нужно использовать дочерний комбинатор), и у вас есть только два текстовых ввода. Если все, что вы хотите, это два поля ввода текста, просто используйте $('input[type="text"]').

Ответ 5

Вы можете использовать селектор потомков вместо родительского селектора или какую-то комбинацию, если важно, чтобы вход был дочерним элементом td. Таким образом, это не имело бы значения. И наоборот, вы также можете просто вставить элементы tbody и без проблем использовать полную родительскую/дочернюю цепочку.

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

Ответ 6

Если вы пытаетесь получить все входы в элементе <form>, который содержит таблицу, это неправильный подход, поскольку существует простой подход DOM, который существует с самого начала JavaScript и работает во всех когда-либо выпущенные основные браузерные браузеры. Элемент формы имеет свойство elements, которое представляет собой набор всех элементов управления формы в форме. Все, что вам нужно, это получить форму, которую вы можете сделать в любом случае наиболее подходящим для вас:

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