querySelector 직계 자식 검색


96

jquery와 같은 기능이 있습니다.

function(elem) {
    return $('> someselector', elem);
};

문제는 어떻게 똑같이 할 수 querySelector()있습니까?

문제는 >선택기에서 querySelector()부모를 명시 적으로 지정해야한다는 것입니다. 해결 방법이 있습니까?


내가 당신을 위해 잘 작동 할 수 대답을 추가, 알려주세요)
— csuwldcat

답변:


119

완전한 답은 아니지만 대부분의 브라우저, 즉 IE (Edge가 지원하는 것 같음)를 제외한 대부분의 브라우저에서 이미 사용 가능한 W3C Selector API v.2 를 주시해야 합니다 . 전체 지원 목록 참조 .

function(elem) {
  return elem.querySelectorAll(':scope > someselector');
};

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


6
사실, :scope여전히 drafts.csswg.org/selectors-4/#the-scope-pseudo에 지정되어 있습니다 . 지금까지 <style scoped>제거 된 것은 속성 뿐입니다 . :scope( <style scoped>의 중요한 사용 사례 였으므로 :scope) 제거로 이어질지 여부는 불분명합니다 .
— John Mellor

1
놀라운 일 : Edge 만 지원하지 않습니다.
— Xenos

31

당신은 할 수 없습니다. 시작점을 시뮬레이트하는 선택기가 없습니다.

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 코드가 아니지만, 내가 기억하는 것은 기본적으로 그들이하는 일입니다. 이 상황뿐만 아니라 중첩 된 요소의 컨텍스트에서 선택기를 실행하는 모든 상황에서.

Sizzle의 소스 코드


1
작성 당시에는 정정하지만 업데이트 된 방법은 @avetisk의 답변을 참조하십시오.
— lazd

23

완료 : 범위 폴리 필

으로 avetisk가 있다 언급 선택자 API를이 개 용도 :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

찾고있는 요소의 태그 이름을 알고있는 경우 선택기에서이를 사용하여 원하는 것을 얻을 수 있습니다.

예를 들어 당신이있는 경우 <select>가 그 <option>들과 <optgroups>, 그리고 당신은 단지 원하는 <option>그 직접적인 아이, 내부가 아닌 것들들 <optgoups>:

<select>
  <option>iPhone</option>
  <optgroup>
    <option>Nokia</option>
    <option>Blackberry</option>
  </optgroup>
</select>

따라서 select 요소에 대한 참조가 있으면 놀랍게도 다음과 같이 직계 자식을 가져올 수 있습니다.

selectElement.querySelectorAll('select > option')

Chrome, Safari 및 Firefox에서 작동하는 것처럼 보이지만 IE에서는 테스트하지 않았습니다. = /


8
경고 :이 답변은 실제로 범위를 제한하지 않습니다. 패턴이 더 깊은 중첩 수준으로 반복되면 직계 자식이 아니더라도 여전히 선택됩니다. <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 요소가 모두 선택됩니다!
— Risord

1
하나님은 <select>같은 부모 에 두 가지 요소가있는 것을 금하셨습니다 .
— Tomáš Zato-Monica 복원


2

청구

개인적으로 나는 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/ 참조


1
몇 가지 문제가 있습니다. @disfated 작업하기를 원하는 querySelector어떤 수단 :eq()을 사용할 수 없습니다. 가능하더라도 선택기는 :eq()페이지에 표시 되는 요소를 반환 :eq()하지만 부모의 색인 (를 가져 오는 위치 idx) 이 아닙니다 .
— user113716

: eq () 및 querySelector에 대한 +1. 그리고 컨텍스트 $ (elem) .parent ()를 추가해야합니다.
— Liangliang Zheng 2011-06-26

불행히도 그것도 작동하지 않습니다. 선택기가 부모의 컨텍스트에서 실행되면 가장 왼쪽에있는 자식부터 시작하여 얼마나 깊게 중첩 되든 일치하는 모든 요소를 ​​찾습니다. 따라서 elem색인 4에 있지만 다른을 가진 이전 형제가 tagName있지만 일치하는 요소가 내부에 중첩되어 있습니다. tagName해당 중첩 요소는 대상이되는 요소 이전에 결과에 포함되고 다시 버립니다. 색인. 다음은 예입니다
— user113716

... 어쨌든, 당신이 궁극적으로하는 것은 문제의 코드의 더 복잡한 버전입니다. $('> someselector', elem);; O)
— user113716

예,하지만 그 단일 증분을 하드 코딩해야했습니다. 그것은 그것에 대한 사전 지식이 필요합니다. 다른 유사한 요소를 추가하면 다시 깨집니다. ; o) jsfiddle.net/Lgaw5/3
— user113716

1

그것은 나를 위해 일했습니다.

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 키 워크를 전달해야합니다.


currenty 받아 들여진 대답 과 같은 것 같습니다 ... Btw, 이상한 "@this"구문의 요점은 무엇입니까? regexp로 ">"를 테스트하지 않는 이유는 무엇입니까?
— -08-01 08:52에 disfated

1

다음은 직계 하위 항목에 대해서만 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"]');

1

query-selector 를 매우 편리하게 대체 할 수 있는 query-relative lib가 있습니다. 자식 선택자 와 (IE8 포함)을 폴리 필하고 선택자를 정규화 합니다. 또한 그것은 같은 특별한 상대 pseudos을 제공 , , , , 단지의 경우.'> *':scope:root:closest:parent:prev:next


0

요소에 ID가 있는지 확인하고 그렇지 않으면 임의의 ID를 추가하고이를 기반으로 검색합니다.

function(elem) {
      if(!elem.id)
          elem.id = Math.random().toString(36).substr(2, 10);
      return elem.querySelectorAll(elem.id + ' > someselector');
    };

같은 일을 할 것입니다

$("> someselector",$(elem))
당사 사이트를 사용함과 동시에 당사의 쿠키 정책과 개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.