JQuery: тонкая разница между .has() и: has()

При использовании с селектором дочерних элементов > два варианта jQuery "имеют" ведут себя по-разному.

Возьмите этот HTML:

<div>
  <span>Text</span>
</div>

Сейчас:

$("div:has(>span)");

вернет его, а:

$("div").has(">span");

не будет. Это ошибка или функция? Сравните здесь: http://jsfiddle.net/aC9dP/


EDIT: Это может быть ошибка или, по крайней мере, недокументированное непоследовательное поведение.

В любом случае, я думаю, было бы полезно, чтобы дочерний селектор последовательно работал как унарный оператор. Это позволяет вам делать что-то, что в противном случае потребовало бы специальной функции фильтра - оно позволяет вам напрямую выбирать элементы с определенными дочерними элементами:

$("ul:has(>li.active)").show();     // works
$("ul").has(">li.active)").show();  // doesn't work, but IMHO it should

в отличие от:

$("ul").filter(function () {
  return $(this).children("li.active").length > 0;
}).show();

Я открыл билет jQuery (7205) для этого.

Ответ 1

Это происходит потому, что селектор sizzle смотрит на все Div, у которых есть дочерние элементы в примере: есть. Но в примере .has, он передает все DIV в .has(), который затем ищет что-то, что не должно быть автономным выбором. ( "Имеет детей ничего" ).

В основном: has() является частью выбора, но .has() получает эти div и затем повторно выбирает из них.

В идеале вы не используете такие селектора. Вхождение > в селектор, вероятно, является ошибкой, поскольку она семантически неловко. Примечание: дочерний оператор не должен быть автономным.

Sizzle vs target.sizzle:

Я всегда говорю о v1.4.2 версии разработки jQuery.

.has (строка 3748 из jQuery)

Описание. Уменьшите набор согласованных элементов до тех, у которых есть потомок, который соответствует элементу селектора или DOM.

код:

    var targets = jQuery( target );
    return this.filter(function() {
        for ( var i = 0, l = targets.length; i < l; i++ ) {
            if ( jQuery.contains( this, targets[i] ) ) { //Calls line 3642
                return true;
            }
        }
    });

Строка 3642 относится к плагину 2008 compareDocumentPosition, но важный бит здесь заключается в том, что теперь мы просто запускаем два jquery-запроса здесь, где первый выбирает $("DIV"), а следующий выбирает $(">span") (который возвращает null), тогда мы проверяем наличие дочерних элементов.

: имеет (строка 3129 из jQuery)

Описание: выбирает элементы , которые содержат по крайней мере один элемент, который соответствует указанному селектору.

Код:

return !!Sizzle( match[3], elem ).length;

Это два разных инструмента, которые используют sizzle 100%, и .has использует цели, переданные ему.

Примечание: если вы считаете, что это ошибка, зайдите в биг-код.

Ответ 2

Я думаю, вы, возможно, наткнулись на подлинную ошибку. Проблема может заключаться в том, как вы используете дочерний селектор. Как указал пользователь257493, он не предназначен для использования сам по себе (или, по крайней мере, я не вижу примеров этого в документации.

Проверьте это. Если вы добавите * перед селектором дочерних элементов в .has(), неожиданно он работает: http://jsfiddle.net/Ender/FjgZn/

Но если вы делаете то же самое в селекторе :has(), он перестает работать! Глянь сюда: http://jsfiddle.net/Ender/FjgZn/

Кажется, что определенная разница в том, как эти два реализованы.