QuerySelector поиск немедленных детей
У меня есть функция jquery-like:
function(elem) {
return $('> someselector', elem);
};
Вопрос в том, как я могу сделать то же самое с querySelector()
?
Задача >
selector в querySelector()
требует, чтобы родительский указатель явно указывался. Есть ли способ обхода?
Ответы
Ответ 1
Завершить: область polyfill
Поскольку avetisk имеет упомянутый, в селекторах API 2 используется псевдо-селектор :scope
.
Чтобы сделать эту работу во всех браузерах (поддерживающих querySelector
), вот polyfill
(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, '$1#' + 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, '$1#' + this.id + ' >');
var result = document.querySelectorAll(selector);
if (removeId) {
this.id = null;
}
return result;
} else {
return this.querySelectorAll(selector);
}
};
Использование
elem.find('> a');
Ответ 2
Хотя это не полный ответ, вы должны следить за W3C Selector API v.2, который уже доступен в Google Chrome и Safari 7.x( как на рабочем столе, так и на мобильных устройствах), но, насколько я тестировал, до сих пор не существует в Firefox и IE.
function(elem) {
return elem.querySelectorAll(':scope > someselector');
};
Ответ 3
Вы не можете. Нет селектора, который будет имитировать вашу отправную точку.
Способ 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, но из того, что я помню, это в основном то, что они делают. Не только в этой ситуации, но и в любой ситуации, когда вы используете селектор из контекста вложенного элемента.
Исходный код для Sizzle
Ответ 4
Если вы знаете имя тега элемента, который вы просматриваете, вы можете использовать его в селекторе для достижения желаемого.
Например, если у вас есть <select>
с <option>
и <optgroups>
, и вы хотите, чтобы <option>
были его непосредственными дочерними, а не те, что внутри <optgoups>
:
<select>
<option>iPhone</option>
<optgroup>
<option>Nokia</option>
<option>Blackberry</option>
</optgroup>
</select>
Итак, имея ссылку на элемент select, вы можете - удивительно - получить своих непосредственных детей следующим образом:
selectElement.querySelectorAll('select > option')
Он работает в браузере Chrome, Safari и Firefox, но не тестировался в IE. =/
Ответ 5
Это сработало для меня:
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 перед > , когда вы хотите найти немедленных детей.
Ответ 6
Ниже приведен упрощенный общий метод для запуска любого селекторного запроса 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"]');
Ответ 7
Theres a query-relative lib, что довольно удобно для селектора запросов. Он полирует дочерний селектор '> *'
и :scope
(включая IE8), а также нормализует селектор :root
.
Также он предоставляет некоторые специальные относительные псевдоподы, такие как :closest
, :parent
, :prev
, :next
, на всякий случай.
Ответ 8
ИСК
Лично я бы взял ответ от patrick 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];
}
}
см. http://jsfiddle.net/Lgaw5/8/
Ответ 9
проверить, имеет ли элемент id еще добавить случайный идентификатор и выполнить поиск по нему
function(elem) {
if(!elem.id)
elem.id = Math.random().toString(36).substr(2, 10);
return elem.querySelectorAll(elem.id + ' > someselector');
};
будет делать то же, что и
$("> someselector",$(elem))