Полностью избегая jQuery, сегодня я решил попробовать сделать что-то вроде:
$('#myDiv').hide();
И цель будет состоять в том, чтобы применить .style.display = 'none'
к #myDiv
.
Итак, мы узнаем, что следующий селектор немного похож на jQuery:
var $ = s => document.querySelectorAll.bind(document)(s).length > 1 ?
document.querySelectorAll.bind(document)(s) : document.querySelector.bind(document)(s);
Просто будьте осторожны при его использовании, потому что он может возвращать несколько элементов, из которых вам может понадобиться использовать синтаксис .forEach(function(el,i){el.doSomething();});
.
Итак, я попытался создать простую функцию $(...).hide()
, например:
$.__proto__.hide = function(){this.forEach(function(el,i){el.style.display='none';});};
К сожалению, __proto__
теперь устарела, и даже если вы проигнорируете это, вышеизложенное не будет работать, если вы не сделаете что-то вроде этого:
$('#myDIV').__proto__.hide = function(){this.forEach(function(el,i){el.style.display='none';});};
Каков метод расширения моего объекта $
с помощью функции .hide()
с использованием простого ванильного Javascript?
Смотрите здесь: youmightnotneedjquery.com
В основном у вас есть два варианта:
Используйте свой собственный объект, как это делает jQuery, или
Расширьте встроенный прототип.
Расширяйте каждый отдельный объект результата по мере его возврата; см. ответ 3limin4t0r
Я бы, вероятно, использовал подход № 1, возможно, расширив Array
(или используя массив через композицию).
Вы, кажется, предпочитаете подход № 2. Обычно это не рекомендуется, потому что, как только вы начнете комбинировать сценарии из разных мест, вы столкнетесь с потенциальными конфликтами. Но в приложении (а не в библиотеке) это не обязательно неразумно.
В вашем случае, если ваша функция $
возвращает результат querySelectorAll
, она возвращает NodeList
, и вы можете расширить NodeList.prototype
. При расширении прототипа всегда используйте Object.defineProperty
(или аналогичный) для определения неперечислимого свойства. Например:
Object.defineProperty(NodeList.prototype, "hide", {
value() {
this.forEach(/*...*/);
return this;
},
writable: true,
configurable: true
});
Живой пример:
Object.defineProperty(NodeList.prototype, "hide", {
value() {
// This isn't a great "hide", it's just for
// the purposes of showing the plumbing
this.forEach(el => el.style.display = "none");
return this;
},
writable: true,
configurable: true
});
const $ = selector => document.querySelectorAll(selector);
setTimeout(() => {
$(".a").hide();
console.info("Hid .a elements");
}, 800);
<div class = "a">a</div>
<div class = "b">b</div>
<div class = "c">c</div>
К сожалению,
__proto__
больше не поддерживается.
Это правда, но Object.getPrototypeOf
не является, просто свойством доступа __proto__
(оно было добавлено в спецификацию только для обратной совместимости).
Основная проблема здесь в том, что вы напрямую возвращаете результат querySelector
или querySelectorAll
. Вы можете обернуть его в свой собственный класс, который вы можете легко расширить с помощью методов.
class ElementsHelper {
constructor(elements) {
this.elements = elements;
}
// helper to simplify iterating `this.elements` and returning `this`
forEach(fn) {
this.elements.forEach(fn);
return this;
}
hide() {
return this.forEach(element => element.style.display = "none");
}
click(fn) {
return this.forEach(element => element.addEventListener("click", fn));
}
}
function $(selector) {
return new ElementsHelper(document.querySelectorAll(selector));
}
С вышеизложенным теперь вы можете сделать:
$('#myDiv').hide();
Не могу поверить, что я исключил этот вариант из своего списка. :-) Это была очень длинная неделя.
Есть множество хороших статей, которые можно найти в Интернете по запросу «как написать свой собственный jquery» или что-то в этом роде. Этот, кажется, хорошо охватывает основы: gomakethings.com/…