私はこれを行うことができます:
<div id="myDiv">
<div class="foo"></div>
</div>
myDiv = getElementById("myDiv");
myDiv.querySelectorAll("#myDiv > .foo");
つまり、クラス.foo
を持つmyDiv
要素のすべての直接の子を正常に取得できます。
問題は、myDiv
要素でクエリを実行しているため、セレクタに#myDiv
を含める必要があることです(したがって明らかに冗長です)。
#myDiv
をオフにしておくことができるはずですが、セレクタは>
で始まるため、正しい構文ではありません。
セレクタが実行されている要素の直接の子だけを取得するセレクタを記述する方法を知っている人はいますか?
良い質問。それが尋ねられたとき、「コンビネーターに根ざしたクエリ」を行うための普遍的に実装された方法( John Resigがそれらを呼んだ )は存在しませんでした。
:scope 擬似クラスが導入されました。 EdgeまたはIEの[Pre-Chrominum]バージョンでは supported ではありませんが、Safariで既に数年間サポートされています。それを使用すると、コードは次のようになります。
_let myDiv = getElementById("myDiv");
myDiv.querySelectorAll(":scope > .foo");
_
場合によっては_.querySelectorAll
_をスキップして、他の古風なDOM API機能を使用することもできます。たとえば、myDiv.querySelectorAll(":scope > *")
の代わりに、たとえば_myDiv.children
_と書くことができます。
そうでなければ、まだ_:scope
_に依存できない場合、カスタムフィルターロジックを追加せずに状況を処理する別の方法を考えることはできません(たとえば、_.parentNode === myDiv
_のmyDiv.getElementsByClassName("foo")
を見つけます)、任意のセレクター文字列を入力として、一致のリストを出力として取得したいだけのコードパスをサポートしようとしている場合、明らかに理想的ではありません。しかし、私のように「あなたが持っていたのはハンマーだけだった」と思って立ち往生したという理由だけでこの質問をした場合、otherDOMが提供するツール。
セレクタが実行されている要素の直接の子だけを取得するセレクタを記述する方法を知っている人はいますか?
現在の要素に「ルート化」されているセレクタを記述する正しい方法は、 :scope
。
var myDiv = getElementById("myDiv");
var fooEls = myDiv.querySelectorAll(":scope > .foo");
ただし、ブラウザのサポートは制限されています 使用する場合はシムが必要です。この目的で scopedQuerySelectorShim を作成しました。
Vanilla JSで記述された柔軟なメソッドを使用すると、要素の直接の子に対してのみCSSセレクタークエリを実行できます。
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");
よりグローバルなソリューションの場合:( matchesSelector shim を使用)
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
はセレクターです。完全にプロトタイプとしても使用できます。
次の解決策は、これまでに提案されたものとは異なり、私にとっては有効です。
理由は、最初に一致するすべての子を選択してから、直接の子ではない子を除外することです。同じセレクタを持つ一致する親がない場合、子は直接の子です。
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!
この状況を処理する関数を作成し、共有すると思いました。
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;
}
本質的にあなたがしていることは、ランダム文字列を生成することです(ここでのrandomString関数はインポートされたnpmモジュールですが、独自のものを作成できます)。その後、>
を自由に使用できます。
Id属性を使用していないのは、id属性が既に使用されている可能性があり、オーバーライドしたくないためです。
childNodes
を使用して要素の直接の子をすべて簡単に取得でき、querySelectorAll
を使用して特定のクラスを持つ祖先を選択できるため、取得する新しい関数を作成できると想像するのは難しくありません両方で、2つを比較します。
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");
現在のノードに一時的な属性を割り当てるだけで:scopeの互換性を拡張できることを付け加えます。
let node = [...];
let result;
node.setAttribute("foo", "");
result = window.document.querySelectorAll("[foo] > .bar");
// And, of course, you can also use other combinators.
result = window.document.querySelectorAll("[foo] + .bar");
result = window.document.querySelectorAll("[foo] ~ .bar");
node.removeAttribute("foo");