使用querySelectorAll来检索直接的孩子
我能够做到这一点:
<div id="myDiv"> <div class="foo"></div> </div>
myDiv = getElementById("myDiv"); myDiv.querySelectorAll("#myDiv > .foo");
也就是说,我可以成功检索具有class .foo
的myDiv
元素的所有直接子元素。
问题是,我不得不在select器中包含#myDiv
,因为我在myDiv
元素上运行查询(所以显然是多余的)。
我应该能够closures#myDiv
,但是select器不是合法的语法,因为它以>
开头。
有谁知道如何编写一个select器,它只是select器运行的元素的直接子元素?
好问题,但是正如你所看到的那样, John Resig给他们命名的时候没有办法做“组合根源查询”。
但是,在某些情况下,您可以跳过.querySelectorAll
并使用其他良好的老式DOM APIfunction。 例如,不用不支持的myDiv.querySelectorAll("> *")
你可以写myDiv.children
。
不幸的是,我不能想办法处理你的情况,而不添加更多的自定义filter逻辑(例如,find其.parentNode === myDiv
)的myDiv.getElementsByClassName("foo")
,如果你想支持,显然不理想一个代码path,真的只是想把一个任意的select器string作为input和匹配列表作为输出! 但是如果像我这样的话,最终只是因为思考“所有的东西都是一把锤子”而提出这个问题,不要忘了DOM还提供了其他各种工具。
有谁知道如何编写一个select器,它只是select器运行的元素的直接子元素?
编写“根”到当前元素的select器的正确方法是使用:scope
。
var myDiv = getElementById("myDiv"); var fooEls = myDiv.querySelectorAll(":scope > .foo");
但是, 浏览器支持是有限的 ,如果你想使用它,你将需要一个垫片。 我为此构build了scopedQuerySelectorShim 。
注意 :: :scope
伪类已被弃用。 但是,它仍然在querySelector
/ querySelectorAll
受支持。
这里有一个灵活的方法,用vanilla JS编写,它允许你只在一个元素的直接子元素上运行一个CSSselect器查询:
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; }
如果你确定这个元素是唯一的(例如你的ID):
myDiv.parentElement.querySelectorAll("#myDiv > .foo");
对于更“全球化”的解决scheme:(使用matchesSelector填充 )
function getDirectChildren(elm, sel){ var ret = [], i = 0, l = elm.childNodes.length; for (var i; i < l; ++i){ if (elm.childNodes[i].matchesSelector(sel)){ ret.push(elm.childNodes[i]); } } return ret; }
elm
是你的父元素, sel
是你的select器。 完全可以用作原型。
我创build了一个函数来处理这种情况,以为我会分享它。
getDirectDecendent(elem, selector, all){ const tempID = randomString(10) //use your randomString function here. elem.dataset.tempid = tempID; let returnObj; if(all) returnObj = elem.parentElement.querySelectorAll(`[data-tempid="${tempID}"] > ${selector}`); else returnObj = elem.parentElement.querySelector(`[data-tempid="${tempID}"] > ${selector}`); elem.dataset.tempid = ''; return returnObj; }
实质上,你正在做的是生成一个随机string(randomString函数,这里是一个导入的npm模块,但是你可以自己创build),然后使用这个随机string来保证你在select器中获得期望的元素。 那么你可以自由使用>
之后。
我不使用id属性的原因是id属性可能已经被使用,我不想重写。
那么我们可以很容易地使用childNodes
获取一个元素的所有直接子元素,并且我们可以使用querySelectorAll
select具有特定类的祖先,所以我们不难想象我们可以创build一个新的函数来获取并比较这两个元素。
HTMLElement.prototype.queryDirectChildren = function(selector){ var direct = [].slice.call(this.directNodes || []); // Cast to Array var queried = [].slice.call(this.querySelectorAll(selector) || []); // Cast to Array var both = []; // I choose to loop through the direct children because it is guaranteed to be smaller for(var i=0; i<direct.length; i++){ if(queried.indexOf(direct[i])){ both.push(direct[i]); } } return both; }
注意:这将返回一个节点数组,而不是一个NodeList。
用法
document.getElementById("myDiv").queryDirectChildren(".foo");
以下解决scheme与迄今为止提出的解决scheme不同,并且适用于我。
理由是你首先select所有匹配的孩子,然后过滤掉那些不是直接孩子的孩子。 一个孩子是一个直接的孩子,如果它没有一个匹配的父母与同一个select器。
function queryDirectChildren(parent, selector) { const nodes = parent.querySelectorAll(selector); const filteredNodes = [].slice.call(nodes).filter(n => n.parentNode.closest(selector) === parent.closest(selector) ); return filteredNodes; }
HTH!
我只是这样做,甚至没有尝试。 这会工作吗?
myDiv = getElementById("myDiv"); myDiv.querySelectorAll(this.id + " > .foo");
试一试,也许它的作品可能不是。 Apolovies,但我现在不在电脑上试试(从我的iPhone响应)。
我已经走了
var myFoo = document.querySelectorAll("#myDiv > .foo"); var myDiv = myFoo.parentNode;