Подумал я. И тут понеслось.
Началось все с задачи: необходимо сверстать обособленную страничку с функцией печати. Сама страничка была сверстана достаточно быстро, но с кнопкой инициации печати я застрял. Причиной этого ступора как раз и было отделение логики от представления. Иначе говоря мне почему-то сильно не хотелось делать так:
А хотелось сделать это красиво, в отдельном файле js. «А вдруг будет несколько кнопок на странице», — подумал я.
Любимый jQuery для такой маленькой и легкой странички подключать тоже не хотелось. И я взялся за «велосипед».
Первым делом был набросан вот такой код:
Работает он просто: при загрузке страницы, находятся все элементы на странице с классом
Хотелось улучшить привязку событий, так, чтобы они не перебивали ранее привязанные события. Для этих целей была написана функция:
Функция получает на вход три параметра: DOM элемент, тип события (
Но к этому элементу уже может быть привязано событие, поэтому функция соответствующего типа копируется у элемента и кладется в переменную
Это дало возможность добавлять события так:
И при клике на документ, в консоли появлялось:
Тут все то же самое, только уже с использованием этого «лучшего» способа привязки событий.
Оглядел эти 25 строк. «Никто же не поймет (дело в том, что многие верстальщики в компании где я работаю, ограничиваются сухой версткой, JavaScript им не интересен и даже этот код будет для них целым ребусом), надо что-то привычнее», — подумал я
Что может быть привычнее чем jQuery в эпоху вопросов:
— Это можно сделать на JavaScript?
— Нет
— А на jQuery?
И вот что из этого вышло:
Можно посмотреть тут
Подумал еще немного, оглядел 70 строк кода, здравый смысл победил, я все удалил и использовал
Не могу отнести себя к профессиональным разработчикам, скорее интересующийся вопросом. Основное же мое занятие — верстка. Возможно кому-то пост этот будет интересен, направлен он прежде всего на новичков, которые только начинают знакомится с JavaScript.
Хочу обратить внимание на то, что проверялось только в Mozilla Firefox 25.0, но в IE8-10 тоже работает, для остальных к сожалению проверить в данный момент не могу. Проверил, ошибок не выявил.
Началось все с задачи: необходимо сверстать обособленную страничку с функцией печати. Сама страничка была сверстана достаточно быстро, но с кнопкой инициации печати я застрял. Причиной этого ступора как раз и было отделение логики от представления. Иначе говоря мне почему-то сильно не хотелось делать так:
<a class="btn-print" href="javascript:window.print()">Печать</a>
А хотелось сделать это красиво, в отдельном файле js. «А вдруг будет несколько кнопок на странице», — подумал я.
Любимый jQuery для такой маленькой и легкой странички подключать тоже не хотелось. И я взялся за «велосипед».
Вариант первый. В лоб
Первым делом был набросан вот такой код:
window.onload = function() {
var elements = document.querySelectorAll('.btn-print');
for (var i = 0, len = elements.length; i < len; i++) {
elements.item(i).onclick = function() {
window.print();
return false;
}
}
}
Работает он просто: при загрузке страницы, находятся все элементы на странице с классом
btn-print (поддержка IE7 мне была ненужна, поэтому решено было использовать querySelectorAll). Далее проходим по всем этим элементам и на событие onclick вешаем функцию, где и производится вызов диалога печати. Для того чтобы не было прыжка страницы (т.е. чтобы ссылка не работала как якорь) функция возвращает false (для IE как потом выяснил не работает).«Но вдруг, кто-то еще привяжет к этим элементам событие, тот кто будет работать со страницей уже после меня», — подумал я. И эта мысль привела меня ко второму варианту:
Вариант второй. Думаем о будущем
Хотелось улучшить привязку событий, так, чтобы они не перебивали ранее привязанные события. Для этих целей была написана функция:
function bind(element, type, func) {
var events = element[type];
element[type] = function(e) {
func.call(element, e);
if (events && events.call) {
events.call(element, e);
}
}
}
Функция получает на вход три параметра: DOM элемент, тип события (
'onclick', 'onload' и т.д.) и функцию, которая добавляется к элементу — которая и будет производить обработку события.Но к этому элементу уже может быть привязано событие, поэтому функция соответствующего типа копируется у элемента и кладется в переменную
events. Далее значение этого свойства у элемента заменяется на новую функцию. Внутри нее выполняется вызов func (которая пришла в bind третим параметром) посредством call — в нее передается контекст (чтобы внутри этой функции к элементу можно было обращаться через this) и объект события (в функции он доступен первым параметром), а следом вызов того что предварительно сохранили в events (перед вызовом проверяется есть ли там что-то и является ли это что-то функцией).Это дало возможность добавлять события так:
bind(document, 'onclick', function(e) {console.log(1, this, e)});
bind(document, 'onclick', function(e) {console.log(2, this, e)});
И при клике на документ, в консоли появлялось:
В итоге:
bind(window, 'onload', function() {
var btn = document.querySelectorAll('.btn-print'),
i, len, onclick, item;
for (i = 0, len = btn.length; i < len; i++) {
item = btn.item(i);
bind(item, 'onclick', function() {
window.print();
return false;
});
}
});
Тут все то же самое, только уже с использованием этого «лучшего» способа привязки событий.
Оглядел эти 25 строк. «Никто же не поймет (дело в том, что многие верстальщики в компании где я работаю, ограничиваются сухой версткой, JavaScript им не интересен и даже этот код будет для них целым ребусом), надо что-то привычнее», — подумал я
Вариант третий. Велосипед
Что может быть привычнее чем jQuery в эпоху вопросов:
— Это можно сделать на JavaScript?
— Нет
— А на jQuery?
И вот что из этого вышло:
// использование
_(window).load(function() { //ждем загрузки
_('.btn-print').click(function() { //находим элементы, привязываем обработчик события
window.print(); //наконец-то
});
});
Код с комментами
(function(self) { // функция в которой создается "чудо-библиотека"
var _ = function(el) { //конструктор
if (this instanceof _) { // если это объект "класса" _
if (typeof el == 'string') {
//если это строка, то находим элементы и кладем в свойство el
this.el = document.querySelectorAll(el);
} else {
//если это не строка, то предполагаем что это DOM-объект и кладем в el
this.el = el;
}
return this; //возвращаем this - чтобы можно было использовать привычные цепочки вызовов
} else { //если это не объект "класса" _
return new _(el); //создаем и возвращаем объект
}
}
// т.е. в любом случае создается объект
_.each = function(el, func) { // перебор элементов, вызов для каждого func
var i, len;
if (el.length) { //если есть length - перебираем
for (i = 0, len = el.length; i < len; i++) {
func.call(el[i]);
}
} else { // если нет, то применяем как есть
func.call(el);
}
}
_.prototype.each = function(func) { // вызов func для каждого элемента из el
_.each(this.el, func);
return this; // для цепочек
}
_.prototype.bind = function(type, func) { //привязка событий
type = 'on' + type;
this.each(function() { //используем новые методы
var old = this[type];
this[type] = function(e) {
func.call(this, e);
if (old && old.call) {
old.call(this, e);
}
};
});
return this; // возвращается this для цепочек
}
_.each(['click', 'load'], function() { //создание методов click, load (можно продолжать список)
var type = this;
_.prototype[type] = function(func) {
this.bind(type, func);
}
});
self._ = _; //выбрасываем в глобальную область видимости
})(window); //передача window, так что в контексте функции self будет ссылкой на window
Можно посмотреть тут
Итог
Подумал еще немного, оглядел 70 строк кода, здравый смысл победил, я все удалил и использовал
javascript:window.print(), но это был безусловно полезный для меня опыт.Не могу отнести себя к профессиональным разработчикам, скорее интересующийся вопросом. Основное же мое занятие — верстка. Возможно кому-то пост этот будет интересен, направлен он прежде всего на новичков, которые только начинают знакомится с JavaScript.
Хочу обратить внимание на то, что проверялось только в Mozilla Firefox 25.0, но в IE8-10 тоже работает, для остальных к сожалению проверить в данный момент не могу. Проверил, ошибок не выявил.
This entry passed through the Full-Text RSS service — if this is your content and you're reading it on someone else's site, please read the FAQ at fivefilters.org/content-only/faq.php#publishers. Five Filters recommends:
- Massacres That Matter - Part 1 - 'Responsibility To Protect' In Egypt, Libya And Syria
- Massacres That Matter - Part 2 - The Media Response On Egypt, Libya And Syria
- National demonstration: No attack on Syria - Saturday 31 August, 12 noon, Temple Place, London, UK
Комментариев нет:
Отправить комментарий