Рассмотрим на задаче и её реализации: Есть x элементов, по клику на элемент он должен поменять состояние. Кликов на элементе может быть, и чаще всего будет, не одни.
Вёрстка.
Элементов много — нахождение по классу.
<body> <div class="testDiv"></div> <div class="testDiv"></div> <div class="testDiv"></div> <div class="testDiv"></div> <div class="testDiv"></div> <div class="testDiv"></div> <div class="testDiv"></div> <div class="testDiv"></div> <div class="testDiv"></div> <div class="testDiv"></div> <div class="testDiv"></div> <div class="testDiv"></div> <div class="testDiv"></div> <div class="testDiv"></div> <div class="testDiv"></div> <div class="testDiv"></div> <div class="testDiv"></div> <div class="testDiv"></div> </body>
// бесспорно ок.
JS.
Найти по классу, повесить клик, обработать клик, отмечен — снять, не отмечен — отметить
jQ
подключили jQ
Решение Задачи
$(function(){ $('.testDiv').on('click', function(){ var vedroCache = $(this); if (vedroCache.hasClass('isActiveTestDiv')){ vedroCache.removeClass('isActiveTestDiv'); } else{ vedroCache.addClass('isActiveTestDiv'); } }); });
JS
Вместо jq
//писать ≈2—3ч в с чаем и твиттером в выходные (function(u){ var J = {}, W = window, D = document, intCache; W.J = J; // search elements if ('getElementsByClassName' in document){ J.$c = function(className, from){ return (from || D).getElementsByClassName(className); } } else{ J.$c = function(className, from){ var cache = (from || D).getElementsByTagName('*'), result = [], i = cache.length, j = -1; for (; i-- ;){ if (cache[i].className.indexOf(className) !== -1){ result[j += 1](cache[i]); } } return result; } } // events if ('addEventListener' in W){ J.eventAdd = function(object, eventName, callback){ object.addEventListener(eventName, callback); }; J.eventDel = function(object, eventName, callback){ object.removeEventListener(eventName, callback); }; } else{ var ieFixEventsNameObjectsCallbacks = [], ieFixEventsObjectsAndCallbacksLength = 0, ieFixEventsHandlers = {}, fixEvent = function(e){ e.preventDefault = function(){ e.returnValue = false; }; e.stopPropagation = function(){ e.cancelBubble = true; }; e.target= e.srcElement; return e; }, ieAddFixEvent = function(object, eventName, callback){ function fix(){ callback.call(object, fixEvent(W.event)); } intCache = ieFixEventsObjectsAndCallbacksLength; ieFixEventsNameObjectsCallbacks[ieFixEventsObjectsAndCallbacksLength] = eventName; ieFixEventsObjectsAndCallbacksLength += 1; intCache += ieFixEventsObjectsAndCallbacksLength; ieFixEventsNameObjectsCallbacks[ieFixEventsObjectsAndCallbacksLength] = callback; ieFixEventsObjectsAndCallbacksLength += 1; intCache += ieFixEventsObjectsAndCallbacksLength; ieFixEventsNameObjectsCallbacks[ieFixEventsObjectsAndCallbacksLength] = object; ieFixEventsObjectsAndCallbacksLength += 1; ieFixEventsHandlers[intCache] = fix; object.attachEvent('on' + eventName, fix); }, ieRemoveFixEvent = function(object, eventName, callback){ for (var i = ieFixEventsObjectsAndCallbacksLength; i-- ;){ if ((ieFixEventsNameObjectsCallbacks[i] === object) && (ieFixEventsNameObjectsCallbacks[i - 1] === callback) && (ieFixEventsNameObjectsCallbacks[i - 2] === eventName)){ ieFixEventsNameObjectsCallbacks[i] = ieFixEventsNameObjectsCallbacks[i - 1] = ieFixEventsNameObjectsCallbacks[i - 2] = u; i = i * 3 - 3; break; } i -= 2; } if (i !== -1){ object.detachEvent('on' + eventName, ieFixEventsHandlers[i]); ieFixEventsHandlers[i] = u; } }; J.eventAdd = function(object, eventName, callback, isNotNeedFix){ if (isNotNeedFix === true){ object.attachEvent('on' + eventName, callback); } else{ ieAddFixEvent(object, eventName, callback); } }; J.eventDel = function(object, eventName, callback, isNotNeedFix){ if (isNotNeedFix === true){ object.detachEvent('on' + eventName, callback); } else{ ieRemoveFixEvent(object, eventName, callback); } }; } // classes J.classHas = function(object, className){ return object.className.indexOf(className) !== -1; //да без регулярок* }; J.classAdd = function(object, className){ if (!J.classHas(object, className)){ object.className += ' ' + className; } }; J.classDel = function(object, className){ if (J.classHas(object, className)){ object.className = object.className.replace(className, ''); //да без регулярок* } }; //*проектирование уникальных классов для DOM элементов вьюшек — простая стандартизируемая (автоматизируемая) задача! // fast bad ready J.ready = function(callback){ var callbacks = [callback]; function ready(){ var iMax = callbacks.length, i = 0; J.eventDel(D, 'DOMContentLoaded', ready); J.eventDel(W, 'load', ready, true); for (;i < iMax; i += 1){ callbacks[i].call(J); } ready = callbacks = null; J.ready = function(callback){ callback.call(J); } } if ('addEventListener' in W){ J.eventAdd(D, 'DOMContentLoaded', ready); } J.eventAdd(W, 'load', ready, true); J.ready = function(callback){ callbacks.push(callback); } }; }());
Решение задачи
J.ready(function(){ var J = this, elems = J.$c('testDiv'), i = elems.length; function clickListener(){ J[J.classHas(this, 'isActiveTestDiv') ? 'classDel' : 'classAdd'](this, 'isActiveTestDiv'); } for (;i--;){ J.eventAdd(elems[i], 'click', clickListener); } });
До объяснений проблем ведра хотелось бы заметмть, инит решения при 350 дивах и следующей эмуляции console.time
if (!('console' in window) || !('time' in console)){ (function(w){ var times = {}, C; if (!('console' in w)){ w.console = C = {}; C.log = function(data){ alert(data); } } else{ C = w.console; } C.time = function(name){ times[name] = new Date().getTime(); }; C.timeEnd = function(name){ if (name in times){ return new Date().getTime() - times[name]; } }; }(window)); }
на машинке
и в фоксе 18.0.1
jQ ≈16ms
J ≈2ms
А в чём разница?
По мимо кучи кода, основная разница в подходах.
Подход «ведро»
Концепт — осознать, применить, т.е.
$(/*всё что угодно*/)./*сделай с ним что то*/
Мы можем менять jq на любые другие штуки, но концепт остаётся один и тот же.
Есть функция готовая ко всему (ведро), которая возвращает результат своей обработки в своей оболочке с набором действий.
В следствии чего
//мы должны надеятся на то, что ведро нас поймёт $('.testDiv').on('click', function(){ var vedroCache = $(this); // и во многих элементарных случая мы должны обрабатывать через ведро каждый раз if (vedroCache.hasClass('isActiveTestDiv')){ vedroCache.removeClass('isActiveTestDiv'); } else{ vedroCache.addClass('isActiveTestDiv'); } }); console.log(console.timeEnd('divs'));
Подход «не ведро» (набор решений)
/*название решения*/(/*параметры задачи :)*/)
Считаю правильным, если решение валится от неправильных параметров.
J.ready(function(){ var J = this, elems = J.$c('testDiv'), //найти по классу i = elems.length; function clickListener(){ J[J.classHas(this, 'isActiveTestDiv') ? 'classDel' : 'classAdd'](this, 'isActiveTestDiv'); //нет поставить, есть убрать } for (;i--;){ J.eventAdd(elems[i], 'click', clickListener); //повесить событие на конкретный элемент } });
Развивать тему по поводу контроля конкретных решений можно очень долго.
Вывод следующий: нужно максимально понимать и контролировать то что у вас происходит, не отдавая всё на откуп общепринятого ведра.
ссылка на оригинал статьи http://habrahabr.ru/post/166877/
Добавить комментарий