Элементы jQuery не могут выбрать parent()
Кажется, элементы, выбранные с помощью :contains(sub)
с sub
содержащий <
или же >
не может добраться до своих родителей.
Следующий пример должен проиллюстрировать проблему, с которой я столкнулся как в Safari, так и в Camino (Gecko на 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
или как мне это обойти?
На этой странице упоминается экранирование имен в селекторах, но это тоже не сработало (также я не уверен, применимо ли это).
4 ответа
Понятия не имею, что вызывает contains()
потерпеть неудачу, но вы можете использовать .filter()
как альтернатива:
alert($('body strong').filter(function() {
return /<foo>/.test( $(this).text() );
}).parent().length);
Это возвращает 1, как ожидалось. Это некрасиво, но работает.
Отказ от ответственности: Это не решение / обходной путь, используйте ответ Тату для этого, это просто описание проблемы и того, что происходит, чтобы вызвать странное поведение для тех, кто интересуется.
Корень проблемы здесь, регулярное выражение, которое 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.
Это явно проблема с синтаксическим анализом селектора jQuery. Если <
а также >
присутствуют в селекторе, jQuery идентифицирует аргумент как фрагмент документа вместо селектора. Результатом является элемент с tagName "FOO", и те же селекторы будут иметь ту же проблему:
$('body <foo>')
$('body strong:not(<foo>')
Единственное отличие в вашем случае состоит в том, что вы использовали правильный селектор, а jQuery неправильно его идентифицирует.
Я предпринял несколько попыток обходного решения на основе селектора, но единственный, который сработал , был Тату Ульманен.
РЕДАКТИРОВАТЬ: кажется, вы также можете использовать .find ():
$(document.body).find('strong:contains("<foo>")')
<foo>
оценивается как тег, поэтому его родитель не содержит ничего, кроме пустого тега, то есть 0.
РЕДАКТИРОВАТЬ: Чтобы полностью понять, посмотрите на это: $('body strong:contains("foo")').text().length
который дает 5. 1 из $('body strong:contains("<foo>")').length
говорит, что внутри сильного есть один текстовый узел, длина которого равна 1, а длина текста равна 5.
Самое интересное - это трейлинг >
который не может быть правильно выбран в качестве >
ни >
кажется, работает из-за >
который используется в качестве селектора CSS. Так, <foo
работает но не <foo>
Вот страница скрипки, чтобы поиграть с ней: http://jsfiddle.net/2XEUg/1/