Элементы jQuery не могут выбрать parent()
Кажется, что элементы, выбранные с помощью :contains(sub)
с sub
, содержащими <
или >
, не могут добраться до их родителей.
Следующий пример должен проиллюстрировать проблему, с которой я столкнулся как в Safari, так и в Camino (Gecko on Mac):
<html>
<head>
<script type="text/javascript" src="http://code.jquery.com/jquery-1.4.2.min.js"></script>
</head>
<body>
<p><strong>bar</strong></p>
<p><strong><foo></strong></p>
<script type="text/javascript">
alert($('body strong:contains("bar")').length);
alert($('body strong:contains("bar")').parent().length);
alert($('body strong:contains("<foo>")').length);
alert($('body strong:contains("<foo>")').parent().length); // this fails
alert($('body strong').length);
alert($('body strong').parent().length); // two p elements
alert($('body strong').parent().parent().length); // one body
</script>
</body>
</html>
Выход:
1
1
1
0
2
2
1
Любые идеи, почему четвертый 0
вместо 1
, или как я могу обойти это?
Эта страница упоминает экранирование имен в селекторах, но это тоже не сработало (также я не уверен, применимо ли это).
Ответы
Ответ 1
Не знаю, что привело к ошибке contains()
, но вы можете использовать .filter()
в качестве альтернативы:
alert($('body strong').filter(function() {
return /<foo>/.test( $(this).text() );
}).parent().length);
Это возвращает 1, как ожидалось. Это уродливо, но работает.
Ответ 2
Отказ от ответственности: это не решение/обходное решение ответ Tatu для этого, это просто описание проблемы и что происходит, чтобы вызвать странное поведение для любопытных.
Корень проблемы здесь, регулярное выражение, которое jQuery использует для идентификации фрагмента HTML:
/^[^<]*(<[\w\W]+>)[^>]*$|^#([\w-]+)$/
Что соответствует вашему селектору:
body strong:contains("<foo>")
Вы можете попробовать:
alert(/^[^<]*(<[\w\W]+>)[^>]*$|^#([\w-]+)$/.test('body strong:contains("<foo>")'));
Таким образом, он считает, что это фрагмент HTML. В целом они в настоящее время эквивалентны:
$('body strong:contains("<foo>")');
$('<foo>');
Увидев второе, ясная иллюстрация, что это фрагмент документа... который не имеет родителя. Он занимает 2-ю позицию в массиве совпадений, что вы можете увидеть только <foo>
, снова попробовать:
alert(/^[^<]*(<[\w\W]+>)[^>]*$|^#([\w-]+)$/.exec('body strong:contains("<foo>")')[1]);
Это приведет к тому, что вы в конечном итоге закончите с этот путь кода в jQuery $()
, создав фрагмент.
Итак, короче да, я считаю это ошибкой jQuery.
Ответ 3
<foo>
оценивается как тег, поэтому родительский элемент не содержит ничего, кроме пустого тега, поэтому 0.
EDIT: Чтобы полностью понять, посмотрите на это: $('body strong:contains("foo")').text().length
, который издает 5. 1 из $('body strong:contains("<foo>")').length
говорит, что есть один текст node в пределах сильной длины, которая равна 1, а длина текста равна 5.
То, что становится интересным, - это конечная >
, которая не может быть выбрана корректно, поскольку кажется, что >
и >
работают из-за >
, который используется как селектор css. Итак, <foo
работает, но не <foo>
Вот скрипальная страница: http://jsfiddle.net/2XEUg/1/
Ответ 4
Это явно проблема с синтаксическим селектором jQuery. Если в селекторе присутствуют <
и >
, jQuery идентифицирует аргумент как фрагмент документа вместо селектора. Результатом является элемент с именем tagName "FOO", и те же селектора будут иметь одинаковую проблему:
$('body <foo>')
$('body strong:not(<foo>')
Единственное различие в вашем случае состоит в том, что вы использовали действительный селектор, а jQuery неправильно идентифицирует его.
Я сделал несколько попыток обходного решения, но Тату Ульманен был единственным, кто работал.
EDIT: кажется, вы также можете использовать .find():
$(document.body).find('strong:contains("<foo>")')