querySelector поиск ближайших детей - PullRequest
82 голосов
/ 26 июня 2011

У меня есть некоторая jquery-подобная функция:

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

Вопрос в том, как я могу сделать то же самое с querySelector()?

Проблема в селекторе > в querySelector() требует, чтобы родитель был явно указан.Есть ли обходной путь?

Ответы [ 10 ]

102 голосов
/ 04 сентября 2013

Хотя это не полный ответ, вы должны следить за W3C Selector API v.2 , который уже доступен в Google Chrome и Safari 7.x (как для настольных компьютеров, так и для мобильных устройств), но какнасколько я тестировал, до сих пор не существует в Firefox и IE.

function(elem) {
  return elem.querySelectorAll(':scope > someselector');
};
31 голосов
/ 26 июня 2011

Вы не можете.Нет селектора, который будет имитировать вашу начальную точку.

То, как jQuery делает это (в большей степени из-за того, что qsa ведет себя не по своему вкусу), заключается в том, что они проверяют, если elemимеет идентификатор, и если нет, они временно добавляют идентификатор, а затем создают полную строку селектора.

В основном вы должны сделать:

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

18 голосов
/ 01 августа 2013

Complete: область действия polyfill

Как avetisk имеет упомянутое Селекторы API 2 использует :scope псевдоселектор.
Чтобы это работало во всех браузерах(эта поддержка querySelector) здесь - полифилл

(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');
4 голосов
/ 18 октября 2015

Если вам известно имя тега элемента, который вы просматриваете, то вы можете использовать его в селекторе, чтобы достичь желаемого.

Например, если у вас есть <select>, который имеет <option> s и <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. = /

1 голос
/ 01 ноября 2018

Если вы хотите в конечном итоге найти прямых детей (а не, например, > div > span), вы можете попробовать Element.matches () :

const elems = Array.from(elem.children).filter(e => e.matches('.my-class'))
1 голос
/ 10 декабря 2014

Существует относительная к запросу библиотека, которая является весьма удобной заменой для query-selector .Он заполняет дочерний селектор '> *' и :scope (вкл. IE8), а также нормализует селектор :root.Также он предоставляет некоторые специальные относительные псевдо, такие как :closest, :parent, :prev, :next, на всякий случай.

1 голос
/ 29 июля 2013

Ниже приведен упрощенный универсальный метод запуска любого запроса селектора 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 голос
/ 17 июля 2012

Это сработало для меня:

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);
};

вам нужно будет передать @ эту комбинацию клавиш перед>, если вы хотите искать ближайших детей.

1 голос
/ 26 июня 2011

ИСК

Лично я бы взял ответ у Патрика Д.В. и +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/

0 голосов
/ 26 февраля 2015

проверить, есть ли у элемента id, добавить случайный идентификатор и выполнить поиск на его основе

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

сделает то же самое, что и

$("> someselector",$(elem))
...