나는 이것을 할 수있다 :
<div id="myDiv">
<div class="foo"></div>
</div>
myDiv = getElementById("myDiv");
myDiv.querySelectorAll("#myDiv > .foo");
즉, myDiv
class 가있는 요소 의 모든 직계 자식을 성공적으로 검색 할 수 있습니다 .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
있고 선택자는 있습니다. 프로토 타입으로도 사용할 수 있습니다.
답변
다음 솔루션은 지금까지 제안 된 솔루션과 다르며 저에게 효과적입니다.
이유는 일치하는 모든 하위 항목을 먼저 선택한 다음 직계 하위 항목이 아닌 항목을 필터링하는 것입니다. 동일한 선택자를 가진 일치하는 상위가없는 경우 하위는 직계 하위입니다.
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
있으므로 둘 다 가져 와서 둘을 비교하는 새로운 함수를 만들 수 있다고 상상하기 어렵지 않습니다.
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가 아닌 Nodes의 배열을 반환합니다.
용법
document.getElementById("myDiv").queryDirectChildren(".foo");
