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.