Кто-нибудь работает над эквивалентом jQuery.closest() в DOM api?
Похоже, Селектор уровня 2-го уровня добавляет matches()
, эквивалентный jQuery.is(), поэтому родной ближайший должен быть намного проще писать. Добавляет ли closest()
в селектора?
Кто-нибудь работает над эквивалентом jQuery.closest() в DOM api?
Похоже, Селектор уровня 2-го уровня добавляет matches()
, эквивалентный jQuery.is(), поэтому родной ближайший должен быть намного проще писать. Добавляет ли 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>
Создание ответа Алнитака. Здесь реализация рабочего тока с 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
Кажется, что Chrome 40 принесет собственный element.closest()
метод (http://blog.chromium.org/2014/12/chrome-40-beta-powerful-offline-and.html), указанный здесь: https://dom.spec.whatwg.org/#dom-element-closest
Похоже, это должно быть довольно легко, учитывая 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.
Используя 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>
Небольшая рекурсия сделает трюк.
// 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);
};
})();