querySelector搜索直接子节点

dis*_*ted 82 javascript css-selectors selectors-api

我有一些类似jquery的功能:

function(elem) {
    return $('> someselector', elem);
};
Run Code Online (Sandbox Code Playgroud)

问题是我怎么能这样做querySelector()

问题是>选择器querySelector()要求明确指定父级.有没有解决方法?

ave*_*isk 106

虽然这不是一个完整的答案,但你应该关注W3C Selector API v.2,它已经在谷歌Chrome和Safari 7.x(桌面和移动设备)中提供,但据我测试,仍然没有在Firefox和IE中.

function(elem) {
  return elem.querySelectorAll(':scope > someselector');
};
Run Code Online (Sandbox Code Playgroud)

  • 这是正确的答案.但是,[浏览器支持有限](https://developer.mozilla.org/en-US/docs/Web/CSS/:scope#Browser_compatibility)如果你想使用它,你需要一个垫片.为此,我构建了[scopedQuerySelectorShim](https://github.com/lazd/scopedQuerySelectorShim). (12认同)
  • 实际上,`:scope`仍然在https://drafts.c​​sswg.org/selectors-4/#the-scope-pseudo中指定.到目前为止,只有`<style scoped>`属性被删除了; 目前还不清楚这是否也会导致`:scope`被删除(因为`<style scoped>`是`:scope`的一个重要用例). (6认同)
  • 到 2021 年,所有现代浏览器均支持此功能。 (4认同)
  • :scope属性[已从当前规范中删除](https://github.com/whatwg/html/issues/552). (3认同)
  • 真是令人惊讶:只有 Edge 不支持此功能:) (2认同)

use*_*716 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 = '';
}
Run Code Online (Sandbox Code Playgroud)

这当然不是jQuery代码,但从我记忆中,它基本上就是他们所做的.不只是在这种情况下,而是在您从嵌套元素的上下文中运行选择器的任何情况下.

Sizzle的源代码

  • 在撰写本文时正确,但请参阅 @avetisk 的答案以获取更新的方法。 (2认同)

dis*_*ted 19

完成:范围polyfill

正如avetisk已经提到的选择器API 2使用: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);
Run Code Online (Sandbox Code Playgroud)

用法

node.querySelector(':scope > someselector');
node.querySelectorAll(':scope > someselector');
Run Code Online (Sandbox Code Playgroud)

由于历史原因,我以前的解决方案

基于所有答案

// 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);
    }
};
Run Code Online (Sandbox Code Playgroud)

用法

elem.find('> a');
Run Code Online (Sandbox Code Playgroud)


tuo*_*alo 8

如果你想最终找到直接的孩子(而不是 eg > div > span),你可以尝试Element.matches()

const elem = document.body
const elems = [...elem.children].filter(e => e.matches('b'))

console.log(elems)
Run Code Online (Sandbox Code Playgroud)
<a>1</a>
<b>2</b>
<b>3</b>
<b>4</b>
<s>5</s>
Run Code Online (Sandbox Code Playgroud)


Lia*_*eng 6

宣称

我个人会从 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];
    }
}
Run Code Online (Sandbox Code Playgroud)

http://jsfiddle.net/Lgaw5/8/


Vla*_*IGA 5

如果您知道要查看的元素的标签名称,那么您可以在选择器中使用它来实现您想要的。

例如,如果你有一个<select><option>S和<optgroups>,你只希望<option>这是其直接的孩子,而不是里面的那些小号<optgoups>

<select>
  <option>iPhone</option>
  <optgroup>
    <option>Nokia</option>
    <option>Blackberry</option>
  </optgroup>
</select>
Run Code Online (Sandbox Code Playgroud)

所以,有了对 select 元素的引用,你可以——令人惊讶地——像这样获得它的直接子元素:

selectElement.querySelectorAll('select > option')
Run Code Online (Sandbox Code Playgroud)

它似乎适用于 Chrome、Safari 和 Firefox,但未在 IE 中进行测试。=/

  • 警告:这个答案实际上并不限制范围。如果模式在更深的嵌套级别重复,即使它不是直接子级,它仍然会被选中。`&lt;ul id="start"&gt; &lt;li&gt;A&lt;/li&gt; &lt;li&gt; &lt;ul&gt; &lt;li&gt;b&lt;/li&gt; &lt;li&gt;c&lt;/li&gt; &lt;/ul&gt; &lt;/li&gt; &lt;/ul &gt; var result = document.getElementById('start').querySelectorAll('ul&gt;li');` -&gt; 所有 4 个 li 元素将被选中! (9认同)