Programing

querySelectorAll을 사용하여 직계 자식 검색

lottogame 2020. 9. 9. 18:57
반응형

querySelectorAll을 사용하여 직계 자식 검색


나는 이것을 할 수있다 :

<div id="myDiv">
   <div class="foo"></div>
</div>
myDiv = getElementById("myDiv");
myDiv.querySelectorAll("#myDiv > .foo");

즉, myDivclass 가있는 요소 의 모든 직계 자식을 성공적으로 검색 할 수 있습니다 .foo.

문제는 요소 #myDiv에 대한 쿼리를 실행하고 있기 때문에 선택자 에을 포함해야한다는 myDiv점입니다 (분명히 중복 됨).

나는 #myDiv꺼둘 수 있어야 하지만 선택자는 >.

누구든지 선택기가 실행되는 요소의 직접 자식을 얻는 선택자를 작성하는 방법을 알고 있습니까?


좋은 질문. 요청을 받았을 당시 "결합 자 기반 쿼리"( John Resig가 호출 한 쿼리)를 수행하는 보편적으로 구현 된 방법 은 존재하지 않았습니다.

이제 : scope 의사 클래스가 도입되었습니다. 그것은되지 지원 에지 또는 IE의 [중고 Chrominum] 버전에 있지만, 이미 몇 년 동안 사파리에서 지원하고있다. 이를 사용하면 코드가 다음과 같이 될 수 있습니다.

let myDiv = getElementById("myDiv");
myDiv.querySelectorAll(":scope > .foo");

어떤 경우에는 .querySelectorAll다른 좋은 구식 DOM API 기능을 건너 뛰고 사용할 수도 있습니다. 예를 들어, 대신에 myDiv.querySelectorAll(":scope > *")를 쓸 수 있습니다 myDiv.children.

그렇지 않으면 아직 의존 할 수 :scope없다면 더 많은 사용자 정의 필터 논리 (예 : find myDiv.getElementsByClassName("foo")who .parentNode === myDiv) 를 추가하지 않고 상황을 처리하는 다른 방법을 생각할 수 없으며 실제로 하나의 코드 경로를 지원하려는 경우 이상적이지 않습니다. 임의의 선택기 문자열을 입력으로 사용하고 일치 목록을 출력으로 사용하려고합니다! 나처럼 당신이 붙어 생각을 가지고 있기 때문에 단순히이 질문을 결국하지만 다양한있다 잊지 마세요 "당신이 가진 모든 망치이었다" 다른 DOM을 제공 너무 도구.


누구든지 선택기가 실행되는 요소의 직접 자식을 얻는 선택자를 작성하는 방법을 알고 있습니까?

현재 요소에 "루팅 된"선택기를 작성하는 올바른 방법은를 사용하는 것 :scope입니다.

var myDiv = getElementById("myDiv");
var fooEls = myDiv.querySelectorAll(":scope > .foo");

그러나 브라우저 지원은 제한적 이며 사용하려면 shim이 필요합니다. 이 목적으로 scopedQuerySelectorShim만들었 습니다 .


다음은 바닐라 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");

보다 "글로벌"솔루션 : ( matchsSelector 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있고 선택자는 있습니다. 프로토 타입으로도 사용할 수 있습니다.


이 상황을 처리하는 함수를 만들었고 공유 할 것이라고 생각했습니다.

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;
}

In essence what you are doing is generating a random-string (randomString function here is an imported npm module, but you can make your own.) then using that random string to guarantee that you get the element you are expecting in the selector. Then you are free to use the > after that.

The reason I am not using the id attribute is that the id attribute may already be used and I don't want to override that.


The following solution is different to the ones proposed so far, and works for me.

The rationale is that you select all matching children first, and then filter out the ones which are not direct children. A child is a direct child if it does not have a matching parent with the same selector.

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!


Well we can easily get all the direct children of an element using childNodes and we can select ancestors with a specific class with querySelectorAll, so it's not hard to imagine we could create a new function that gets both and compares the two.

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;
}

Note: This will return an Array of Nodes, not a NodeList.

Usage

 document.getElementById("myDiv").queryDirectChildren(".foo");

I would like to add that you can extend the compatibility of :scope by just assigning a temporary attribute to the current node.

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");

I am just doing this without even trying it. Would this work?

myDiv = getElementById("myDiv");
myDiv.querySelectorAll(this.id + " > .foo");

Give it a try, maybe it works maybe not. Apolovies, but I am not on a computer now to try it (responding from my iPhone).


I'd have gone with

var myFoo = document.querySelectorAll("#myDiv > .foo");
var myDiv = myFoo.parentNode;

참고URL : https://stackoverflow.com/questions/3680876/using-queryselectorall-to-retrieve-direct-children

반응형