Могу ли я полагаться на неявное создание тега `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
, пуста.
Ответы
Ответ 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);
}