querySelector 搜索直系子级 [重复]
Posted
技术标签:
【中文标题】querySelector 搜索直系子级 [重复]【英文标题】:querySelector search immediate children [duplicate] 【发布时间】:2011-09-22 19:43:49 【问题描述】:我有一些类似 jquery 的功能:
function(elem)
return $('> someselector', elem);
;
问题是我怎样才能对querySelector()
做同样的事情?
问题是querySelector()
中的>
选择器需要明确指定父级。有什么解决办法吗?
【问题讨论】:
【参考方案1】:虽然这不是一个完整的答案,但您应该关注W3C Selector API v.2,它已经在大多数浏览器中可用,包括桌面和移动设备,除了 IE(Edge 似乎支持):see full support list。
function(elem)
return elem.querySelectorAll(':scope > someselector');
;
【讨论】:
这是正确答案。但是,browser support is limited 如果您想使用它,您将需要一个 shim。为此,我构建了scopedQuerySelectorShim。 :scope 属性has been removed from the current specification. 其实:scope
还是指定在drafts.csswg.org/selectors-4/#the-scope-pseudo。到目前为止,仅删除了 <style scoped>
属性;目前还不清楚这是否也会导致:scope
被删除(因为<style scoped>
是:scope
的一个重要用例)。
真是惊喜:只有 Edge 不支持这个:)
到 2021 年,现在所有现代浏览器都支持此功能。【参考方案2】:
你不能。没有选择器可以模拟您的起点。
jQuery 这样做的方式(更多是因为 qsa
的行为方式不符合他们的喜好)是他们检查 elem
是否有 ID,如果没有,他们会临时添加一个 ID ,然后创建一个完整的选择器字符串。
基本上你会这样做:
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 代码,但据我所知,这基本上是他们所做的。不仅在这种情况下,而且在您从嵌套元素的上下文中运行选择器的任何情况下。
Source code for Sizzle
【讨论】:
在撰写本文时正确,但请参阅 @avetisk 的答案以获取更新的方法。【参考方案3】:完成 :scope polyfill
由于 avetisk 具有 mentioned 选择器 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');
【讨论】:
Date.now()
不支持旧版浏览器,可以替换为new Date().getTime()
【参考方案4】:
如果您想最终找到直系子代(而不是例如> div > span
),您可以尝试Element.matches():
const elem = document.body
const elems = [...elem.children].filter(e => e.matches('b'))
console.log(elems)
<a>1</a>
<b>2</b>
<b>3</b>
<b>4</b>
<s>5</s>
【讨论】:
【参考方案5】:索赔
我个人会从 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/
【讨论】:
这有几个问题。 @disfated 希望它与querySelector
一起工作,这意味着不能使用 :eq()
。即使可以,您的选择器也会将 :eq()
的元素返回到它在页面上的外观,而不是将 :eq()
返回到其父级的索引(这是您获得 idx
的位置)。
+1 关于 :eq() 和 querySelector。我应该添加上下文 $(elem).parent()。
不幸的是,这也行不通。 When the selector runs from the context of the parent, it starts with the left most child and finds all matching elements no matter how deeply nested, the continues on.所以说elem
在索引4处,但是有一个先前的兄弟有一个不同的tagName
,但它在其中嵌套了一个匹配tagName
的元素,该嵌套元素将包含在结果之前一个你的目标,再次抛出索引。 Here's an example
...无论如何,您最终要做的是问题中代码的更复杂版本,它确实有效。 $('> someselector', elem);
;o)
是的,但是您需要对单个增量进行硬编码。这需要事先了解它。如果我添加另一个类似的元素,它会再次损坏。 ;o) jsfiddle.net/Lgaw5/3【参考方案6】:
如果您知道要查看的元素的标签名称,那么您可以在选择器中使用它来实现您想要的。
例如,如果您有一个具有<option>
s 和<optgroups>
的<select>
,并且您只想要作为其直接子代的<option>
s,而不是<optgoups>
中的子代:
<select>
<option>iPhone</option>
<optgroup>
<option>Nokia</option>
<option>Blackberry</option>
</optgroup>
</select>
因此,有了对 select 元素的引用,您可以——令人惊讶地——得到它的直接子元素,如下所示:
selectElement.querySelectorAll('select > option')
它似乎可以在 Chrome、Safari 和 Firefox 中运行,但没有在 IE 中测试。 =/
【讨论】:
警告:这个答案实际上并没有限制范围。如果模式在更深的嵌套级别重复,即使它不是直接子级,它仍然会被选中。<ul id="start"> <li>A</li> <li> <ul> <li>b</li> <li>c</li> </ul> </li> </ul> var result = document.getElementById('start').querySelectorAll('ul>li');
-> 将选择所有 4 个 li 元素!
上帝禁止在同一个父级中有两个 <select>
元素。【参考方案7】:
以下是一种简化的通用方法,用于仅对直接子级运行任何 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"]');
【讨论】:
【参考方案8】:有一个 query-relative 库,它是 query-selector 的非常方便的替代品。它填充子选择器'> *'
和:scope
(包括IE8),并规范化:root
选择器。
它还提供了一些特殊的相对伪像:closest
、:parent
、:prev
、:next
,以防万一。
【讨论】:
【参考方案9】:这对我有用:
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 键。
【讨论】:
似乎与当前接受的answer 相同...顺便说一句,奇怪的“@this”语法有什么意义?为什么不用正则表达式测试“>”?【参考方案10】:检查元素是否有 id 否则添加随机 id 并根据它进行搜索
function(elem)
if(!elem.id)
elem.id = Math.random().toString(36).substr(2, 10);
return elem.querySelectorAll(elem.id + ' > someselector');
;
会做和
一样的事情$("> someselector",$(elem))
【讨论】:
以上是关于querySelector 搜索直系子级 [重复]的主要内容,如果未能解决你的问题,请参考以下文章
“document.querySelector(...)为空”错误[重复]
使用document.querySelector()[重复]