querySelectorAll на практике
Метод element.querySelectorAll("css query") был введен в браузеры уже достаточно давно, но, честно говоря, я не встречал особо статей про него.
Что ж, исправим эту ситуацию.
Наверняка, Вы знакомы с jQuery. И наверняка знаете про функцию $ , возвращающую элементы, соответствующие css-селектору (в ранних версиях можно было еще использовать XPath, но потом от него отказались).
Так вот, querySelectorAll делает то же самое, но нативными средствами браузера.
Этот метод есть у всех элементов и документа. В случае, если метод вызывается у элемента, поиск по селетору производится среди всех элементов, вложенных в него.
Тектовые ноды, комментарии, CDATA-секции выбрать этим методом нельзя, только элементы.
Поддерживается всеми современными браузерами, Internet Explorer — начиная с версии 8.
Так вот, querySelector почти то же самое, что и querySelectorAll , но возвращает только один (первый попавшийся) элемент, либо Null.
qSA — родной метод браузера, и работает быстрее. По крайней мере в Опере на тестовом образце document.querySelectorAll() показал в среднем 9 мс против 43 мс $() . Причем, скорость очень мало уменьшается от ширины и глубины DOM-дерева.
Как ни парадоксально, в той же Опере .querySelectorAll("div") и .querySelectorAll(".my") работает примерно вдвое быстрее, чем .getElementsByTagName("div") и .getElementsByClassName("my") соответственно.
qSA имеет доступ к таким псевдоклассам, как :focus и :hover
Итак, а с чем же его можно есть?
Если Вы осуществляете траверс по селектору без использования :animated и других специфичных для jQ псевдоклассов, можно использовать
$(document.querySelectorAll("#myDiv p"))
вместо
$("#myDiv p")
На обертывание staticNodeList в объект jQuery, конечно, уйдет какое-то время, но, в целом, такой код выполнится быстрее.
При помощи qSA можно достаточно просто определить, наведен ли курсор на элемент.
Пример (Opera, Safari, Chrome):
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
<head>
<title></title>
<meta http-equiv="Content-Type" content="text/html;charset=UTF-8" />
<style type="text/css">
.samplediv {
border: dashed red 1px;
margin: 30px;
}
.samplediv #hovered {display: none}
.samplediv:hover #hovered {display: inline}
.samplediv:hover #nothovered {display: none}
</style>
</head>
<body>
<div class="samplediv" id="test">
<p>Javascript: <span id="status">I am not hovered</span></p>
<p>Css: <span id="nothovered">I am not hovered</span><span id="hovered">I am hovered</span></p>
</div>
<script type="text/javascript">
function isHovered(o){return (o.parentNode && o.parentNode.querySelector(":hover") == o);}
document.getElementById("test").addEventListener('mouseover', function(){
if (isHovered(this)) document.getElementById("status").innerHTML = "I am hovered";
}, false);
document.getElementById("test").addEventListener('mouseout', function(){
if (!isHovered(this)) document.getElementById("status").innerHTML = "I am not hovered";
}, false);
</script>
</body>
</html>
В Firefox 3.6 статус так и останется залипшим на «hovered». Это связано с тем, что в этом замечательном браузере на момент mouseout css-стиль еще не обновился. При этом на mouseover работает отлично. Т.е, выходит, что Firefox обновляет css между mouseout и mouseover . По-моему, это нелогично и неправильно. Разработчики Firefox, поправьте это, пожалуйста!
Но вернемся к функции isHovered() . Работает она на одном достаточно простом предположении: если у родителя элемента есть элементы, на которые наведен курсор, и один из этих элементов (нулевой в массиве, траверс начинается с непсредственных детей) — сам исходный элемент, то на исходный элемент наведен курсор.
У documentElement родитель — document , соответственно, код тоже работает. У document же родителя нет, но и hover для него бессмысленнен.
Как Вы уже, наверное, догадались, таким же нехитрым способом можно определить, а какой же инпут имеет фокус сразу при загрузке страницы.
document.querySelector(":focus")
Как видите, метод достаточно мощный и быстрый. Не без острых краев и пока не универсальный, но все-таки
Само собой, это не единственные применения, просто think portals CSS.
И, просто прошу, если что-то можно сделать на «голом» CSS, не стоит вообще делать это яваскриптом.
P.S: Давненько я уже ничего не писал. В следующий раз, скорее всего, напишу про CSS3 animation, и когда ее следует использовать вместо $(…).animate(…)
|
Почему Sizzle не использует querySelectorAll для ускорения части своих выборок? Или проверка на валидность селектора слишком трудозатратна и сведет выгоду на нет?
Оказывается, использует. Но с кучей проверок. Универсальность же!
http://code.jquery.com/jquery-1.4.2.js — вот тут можно поискать по тексту «querySelector»
Я догадывался еще с тех пор, как впервые услышал про qsa. Резиг не мог упустить такой шанс. Не сказал бы, что проверок много: фильтруется quirks mode Safari и еще какая-то фигня с XML/non-XML.
Правда, непонятно как фильтруются чисто jQuery-вские селекторы, которых qsa не понимает. Думаю, они отфильтровываются еще до Сиззла.
Если в querySelector передать неподдерживаемый селектор, то он выбросит exception. Вот тут на этом и сыграли.
IE, как водится, в роли ложки дегтя.
Слишком много оговорок, чтобы на него расчитывать. При том, что последние jQuery таки научили с его помощью оптимизировать производительность, если он доступен, а jQuery будет работать и без него. Но за статью, конечно же, спасибо!
я думаю querySelectorAll быстрее getElements* потому что последние возвращают "живые" коллекции. в этом и загвоздка для производительности видимо
querySelectorAll также возвращает "живые" коллекции
Что удивляет, так это дифицит информации по этому методу. Огромное колличество мусора в сети, а это единственная статься на русском, где вообще затрагиваются эти методы.
Roksa pl wloclawek
Roksa pl podobne strony
Отправить комментарий
Приветствуются комментарии:Для остальных вопросов и обсуждений есть форум.