querySelector поиск непосредственных детей
у меня есть некоторые jquery-подобные функции:
function(elem) {
return $('> someselector', elem);
};
вопрос как я могу сделать то же самое с querySelector()
?
проблема >
селектор в querySelector()
требует, чтобы родитель был явно указан. Есть ли обходной путь?
9 ответов:
хотя это не полный ответ, вы должны следить за W3C Selector API V. 2 который уже доступен в Google Chrome и Safari 7.x (как настольный, так и мобильный), но, насколько я проверил, все еще нет в Firefox и IE.
function(elem) { return elem.querySelectorAll(':scope > someselector'); };
вы не можете. Нет селектор, который будет имитировать вашу отправную точку.
как jQuery это делает (больше из-за того, что
qsa
ведет себя так, что это им не по душе), это то, что они проверяют, чтобы увидеть, еслиelem
имеет идентификатор, а если нет, они временно добавляют идентификатор, а затем создают полную строку селектора.В основном вы бы сделали:
var sel = '> someselector'; var hadId = true; if( !elem.id ) { hadID = false; elem.id = 'some_unique_value'; } sel = '#' + elem.id + sel; var result = document.querySelectorAll( sel ); if( !hadId ) { elem.id = ''; }
Это, конечно, не код jQuery, но из того, что я помню, это в основном то, что они делают. Не только в этом ситуация, но в любой ситуации, когда вы запускаете селектор из контекста вложенного элемента.
Complete: scope polyfill
как avetisk и указано селекторы API 2 использует
:scope
псевдо-селектор.
Чтобы сделать эту работу во всех браузерах (которые поддерживаютquerySelector
) вот полифилл(function(doc, proto) { try { // check if browser supports :scope natively doc.querySelector(':scope body'); } catch (err) { // polyfill native methods if it doesn't ['querySelector', 'querySelectorAll'].forEach(function(method) { var nativ = proto[method]; proto[method] = function(selectors) { if (/(^|,)\s*:scope/.test(selectors)) { // only if selectors contains :scope var id = this.id; // remember current element id this.id = 'ID_' + Date.now(); // assign new unique id selectors = selectors.replace(/((^|,)\s*):scope/g, '#' + this.id); // replace :scope with #ID var result = doc[method](selectors); this.id = id; // restore previous id return result; } else { return nativ.call(this, selectors); // use native code for other selectors } } }); } })(window.document, Element.prototype);
использование
node.querySelector(':scope > someselector'); node.querySelectorAll(':scope > someselector');
по историческим причинам, мое предыдущее решение
на основе всех ответов
// Caution! Prototype extending Node.prototype.find = function(selector) { if (/(^\s*|,\s*)>/.test(selector)) { if (!this.id) { this.id = 'ID_' + new Date().getTime(); var removeId = true; } selector = selector.replace(/(^\s*|,\s*)>/g, '#' + this.id + ' >'); var result = document.querySelectorAll(selector); if (removeId) { this.id = null; } return result; } else { return this.querySelectorAll(selector); } };
использование
elem.find('> a');
если вы знаете имя тега элемента, который вы ищете, то вы можете использовать его в селектор, чтобы достичь того, чего вы хотите.
например, если у вас есть
<select>
и<option>
s и<optgroups>
, и вы только хотите<option>
это его непосредственные дети, а не те, что внутри<optgoups>
:<select> <option>iPhone</option> <optgroup> <option>Nokia</option> <option>Blackberry</option> </optgroup> </select>
Итак, имея ссылку на элемент select, вы можете-удивительно-получить его непосредственных детей следующим образом:
selectElement.querySelectorAll('select > option')
это, кажется, работает в Chrome, Safari и Firefox, но не тестировался в IEs. = /
претензии
лично я бы взял ответ от Патрика dw, и +1 его ответ, мой ответ для поиска альтернативного решения. Я не думаю, что это заслуживает понижения.
вот моя попытка :
function q(elem){ var nodes = elem.querySelectorAll('someSeletor'); console.log(nodes); for(var i = 0; i < nodes.length; i++){ if(nodes[i].parentNode === elem) return nodes[i]; } }
это сработало для меня:
Node.prototype.search = function(selector) { if (selector.indexOf('@this') != -1) { if (!this.id) this.id = "ID" + new Date().getTime(); while (selector.indexOf('@this') != -1) selector = selector.replace('@this', '#' + this.id); return document.querySelectorAll(selector); } else return this.querySelectorAll(selector); };
вам нужно будет передать @this keywork перед > , когда вы хотите искать непосредственных детей.
ниже приведен упрощенный, общий метод для выполнения любого запроса селектора CSS только над прямыми дочерними элементами - он также учитывает комбинированные запросы, такие как
"foo[bar], baz.boo"
:var count = 0; function queryChildren(element, selector) { var id = element.id, guid = element.id = id || 'query_children_' + count++, attr = '#' + guid + ' > ', selector = attr + (selector + '').replace(',', ',' + attr, 'g'); var result = element.parentNode.querySelectorAll(selector); if (!id) element.removeAttribute('id'); return result; } *** Example Use *** queryChildren(someElement, '.foo, .bar[xyz="123"]');
здесь query-relative lib, который является довольно удобной заменой для query-selector. Это полифилл детский селектор
'> *'
и:scope
(inc. IE8), а также нормализует:root
селектор. Также он предоставляет некоторые специальные относительные псевдонимы, такие как:closest
,:parent
,:prev
,:next
на всякий случай.
проверьте, если элемент имеет идентификатор еще добавить случайный идентификатор и сделать поиск на его основе
function(elem) { if(!elem.id) elem.id = Math.random().toString(36).substr(2, 10); return elem.querySelectorAll(elem.id + ' > someselector'); };
будет делать то же самое как
$("> someselector",$(elem))