Самый близкий селектор соответствия предков с использованием встроенного DOM? - программирование
Подтвердить что ты не робот

Самый близкий селектор соответствия предков с использованием встроенного DOM?

Кто-нибудь работает над эквивалентом jQuery.closest() в DOM api?

Похоже, Селектор уровня 2-го уровня добавляет matches(), эквивалентный jQuery.is(), поэтому родной ближайший должен быть намного проще писать. Добавляет ли closest() в селектора?

4b9b3361

Ответ 1

Element.closest()

его поддержка

Реализация такой функции с Element.matches() кажется не оптимальной с точки зрения производительности, потому что явно match() будет вызывать запрос querySelectorAll() каждый раз, когда вы тестируете родителя, а для задания достаточно одного вызова.

Здесь a polyfill для ближайшего() на MDN. Обратите внимание на один вызов querySelectorAll()

if (window.Element && !Element.prototype.closest) {
  Element.prototype.closest = 
  function(s) {
      var matches = (this.document || this.ownerDocument).querySelectorAll(s),
          i,
          el = this;
      do {
          i = matches.length;
          while (--i >= 0 && matches.item(i) !== el) {};
      } while ((i < 0) && (el = el.parentElement)); 
      return el;
  };
}

Но имейте в виду, что функция, реализованная таким образом, не будет работать должным образом на unattached tree (отсоединен от root.documentElement root)

//Element.prototype.closestTest = function(s){...as seen above...};

var detachedRoot = document.createElement("footer");
var child = detachedRoot.appendChild(document.createElement("div"));
detachedRoot.parentElement; //null

child.closestTest("footer"); //null

document.documentElement.append(detachedRoot);
child.closestTest("footer"); //<footer>   

Хотя ближайший(), который реализован в Firefox 51.0.1, кажется, отлично работает с отдельным деревом

document.documentElement.removeChild(detachedRoot);
child.closestTest("footer"); //null
child.closest("footer"); //<footer>

Ответ 2

Создание ответа Алнитака. Здесь реализация рабочего тока с matchesSelector, которая теперь находится matches в спецификации DOM.

// get nearest parent element matching selector
function closest(el, selector) {
    var matchesSelector = el.matches || el.webkitMatchesSelector || el.mozMatchesSelector || el.msMatchesSelector;

    while (el) {
        if (matchesSelector.call(el, selector)) {
            break;
        }
        el = el.parentElement;
    }
    return el;
}

Поддержка браузера велика: http://caniuse.com/matchesselector

Ответ 4

Похоже, это должно быть довольно легко, учитывая matches, хотя это пока еще не поддерживается:

function closest(elem, selector) {
    while (elem) {
        if (elem.matches(selector)) {
            return elem;
        } else {
            elem = elem.parentElement;
        }
    }
    return null;
}

Проблема в том, что функция matches не поддерживается должным образом. Поскольку он по-прежнему является относительно новым API, он доступен как webkitMatchesSelector в Chrome и Safari и mozMatchesSelector в Firefox.

Ответ 5

Используя element.closest(), мы можем найти ближайший селектор соответствия предков. Этот метод принимает список селекторов как параметр и возвращает ближайшего предка. Согласно Rob Комментарий, этот API будет доступен из хрома 41 и FF 35.

Как объясняется в спецификациях Whata, https://dom.spec.whatwg.org/#dom-element-closest

Пример. В приведенном ниже HTML будет отображаться предупреждающее сообщение "true"

<html>
    <body>
        <foo>
            <bar>
                <a id="a">
                    <b id="b">
                        <c id="c"></c>
                    </b>
                </a>
            </bar>
         </foo>
    <script>
        var a = document.getElementById('a');
        var b = document.getElementById('b');
        var c = document.getElementById('c');
        alert(c.closest("a, b")==b);
    </script>
    </body>
</html>

Ответ 6

Небольшая рекурсия сделает трюк.

// get nearest parent element matching selector
var closest = (function() {
    var matchesSelector = el.matches || el.webkitMatchesSelector || el.mozMatchesSelector || el.msMatchesSelector;

    return function closest(el, selector) {
        return !el ? null :
        matchesSelector.call(el, selector) ? el : closest(el.parentElement, selector);
    };
})();