120

我有一些类似 jquery 的功能:

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

问题是我该如何做同样的事情querySelector()

问题是>选择器querySelector()需要明确指定父级。有什么解决方法吗?

4

10 回答 10

162

虽然这不是一个完整的答案,但您应该留意W3C Selector API v.2,它已经在大多数浏览器中可用,包括桌面和移动设备,除了 IE(Edge 似乎支持):请参阅完整支持列表

function(elem) {
  return elem.querySelectorAll(':scope > someselector');
};
于 2013-09-04T07:23:07.797 回答
35

你不能。没有选择器可以模拟您的起点。

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 代码,但据我所知,这基本上是他们所做的。不仅在这种情况下,而且在您从嵌套元素的上下文中运行选择器的任何情况下。

嘶嘶声的源代码

于 2011-06-26T01:43:46.293 回答
27

完成 :scope polyfill

正如avetisk提到的Selectors 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);

用法

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');
于 2013-08-01T09:12:55.720 回答
8

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

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

console.log(elems)
<a>1</a>
<b>2</b>
<b>3</b>
<b>4</b>
<s>5</s>

于 2018-11-01T12:38:17.977 回答
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];
    }
}

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

于 2011-06-26T02:27:54.467 回答
5

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

例如,如果您有一个<select>具有<option>s 和的 a <optgroups>,并且您只想要作为<option>其直接子级的 s,而不是内部的那些<optgoups>

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

因此,有了对 select 元素的引用,您可以——令人惊讶地——得到它的直接子元素,如下所示:

selectElement.querySelectorAll('select > option')

它似乎在 Chrome、Safari 和 Firefox 中工作,但没有在 IE 中测试。=/

于 2015-10-18T17:17:19.593 回答
2

以下是一种简化的通用方法,用于仅对直接子级运行任何 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"]');
于 2013-07-29T18:36:55.150 回答
2

有一个相对于查询的库,它是查询选择器的非常方便的替代品。它填充子选择器'> *':scope(包括 IE8),以及规范化:root选择器。它还提供了一些特殊的相对伪,例如:closest, :parent, :prev, :next, 以防万一。

于 2014-12-09T23:10:26.017 回答
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 键。

于 2012-07-16T20:34:28.860 回答
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))
于 2015-02-26T20:20:10.860 回答