Dojo Toolkit для начинающих // JavaScript
Возможно, многие уже читали статьи из серии jQuery для начинающих, да вот с некоторых пор меня заинтересовал еще один JavaScript фреймворк, и зовется он Dojo Toolkit.
В данной статье я постараюсь описать базовые возможности Dojo, так же буду проводить параллели с jQuery, так что не пугайтесь возникшему дежавю…
Как я уже когда-то говорил – учиться лучше на примерах, так что приступим…
Подключение
Ну, для начала Вам понадобится сам фреймворк, его вы сможете скачать с домашней страницы проекта, затем подключаем его одним из следующих способов:
Используя локальный файл:
<script type="text/javascript" src="js/dojo/dojo.js" djConfig="parseOnLoad:true, isDebug:true"></script>
Данная запись аналогична предыдущей:
<script type="text/javascript"> var djConfig = { isDebug:true, parseOnLoad:true }; </script> <script type="text/javascript" src="js/dojo/dojo.js"></script>
Dojo так же доступен на следующих хостах:
<!-- AOL --> <script type="text/javascript" src="http://o.aolcdn.com/dojo/1.3/dojo/dojo.xd.js"></script> <!-- Google --> <script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/dojo/1.3/dojo/dojo.xd.js"></script>
Селекторы
Перейдем к поиску элементов, для этой цели есть следующие функции:
// самый простой вариант - получить елемент по его Id var element = dojo.byId('elementId'); // так же можем выбрать несколько элементов, используя селекторы из CSS3, - возвращается объект NodeList var elements = dojo.query('.elementsClass')
Список поддерживаемых CSS селекторов можно найти в документации по функции dojo.query (docs.dojocampus.org).
События
Для работы с событиями в Dojo используются функции dojo.connect и dojo.disconnect – для добавления и удаления обработчиков соответственно, приведу простой пример:
// некая функция function update() { console.log('click!'); } // и некоторый элемент var obj = dojo.byId('someId'); // вешаем обработчик var link = dojo.connect(obj, "onclick", null, "update"); // или dojo.connect(obj, "onclick", "update"); // или используя анонимную функцию dojo.connect(obj, "onclick", function update() { console.log('click!'); }); // убираем наш обработчик dojo.disconnect(link);
Функция connect так же поддерживается NodeList’ом:
// переделаем чуть-чуть предыдущий пример dojo.query('.someClass').connect("onclick", function update() { console.log('click!'); });
Примечание: dojo одинаково понимает события click и onclick
Простые примеры
Теперь перейдем непосредственно к работе, начнем с события, которое оповестит нас о завершении строительства DOM’а:
// создаем функцию init и вызваем ее по событию OnLoad var init = function(){ console.log("DOM построен..."); }; dojo.addOnLoad(init); // и/или используем анонимную функцию dojo.addOnLoad(function(){ console.log("...спасибо"); });
Тривиальная задача – организация “зебры” из некой таблицы:
// таблица c "id=tabular_data" берем ее "tbody" // (используем селектор ">" дабы выбрать лишь нужные элементы, исключая подтаблицы) // и каждому нечетному элементу "tr" добавляем класс "odd" dojo.query("#tabular_data > tbody > tr:nth-child(odd)").addClass("odd");
Изменение атрибутов, классов и стилей объектов:
// получаем атрибут title dojo.attr("Id/Node", "title"); // title="bar" // устанавливаем атрибут title dojo.attr("Id/Node", "title", "A new Title"); // устанавливаем несколько атрибутов dojo.attr("Id/Node", { "tabindex": 2, // add to tab order "onclick": function(e) { // add a click event to this node } }); // добавляем класс anewClass dojo.addClass("Id/Node", "anewClass"); // удаляем класс anewClass dojo.removeClass("Id/Node", "anewClass"); // переключатель класса (нет - добавит, есть - удалит) dojo.toggleClass("Id/Node", "anewClass"); // работает так же и с NodeList (т.е. массивом элементов) dojo.query(".selector").toggleClass("anewClass"); // вернет объект стиля dojo.style("Id/Node"); // вернет значение opacity dojo.style("Id/Node", "opacity"); // установит значение opacity=0.5 dojo.style("Id/Node", "opacity", 0.5); // изменяем несколько свойств dojo.style("Id/Node", { "opacity": 0.5, "border": "3px solid black", "height": "300px" }); // работает так же и с NodeList (т.е. массивом элементов) dojo.query(".selector").style({ "opacity": 0.5, "border": "3px solid black", "height": "300px" });
Примечание: если какая-либо функция требует указания node в качестве параметра объекта (см. dojo.animateProperty), значит она не сможет переварить NodeList, даже если там содержится лишь один объект, конечно, это логично, но после jQuery – немного напрягает
Выдвижная панель
Начнем с простенького примера – слайд-панель, она у нас будет двигаться вверх/вниз по клику на ссылке (см. пример)
Реализуем это следующим образом, по клику на ссылку, у нас будет переключаться её класс (между “active” и “btn-slide”), а панелька с id=”panel” будет выдвигаться/прятаться. (класс “active” изменяет позицию фонового изображения, см. CSS код).
dojo.addOnLoad(function(){ dojo.query(".btn-slide").connect("onclick",function(e){ dojo.stopEvent(e); var panel = dojo.byId('panel'); if (dojo.style(panel, 'height') != 0) { dojo.anim(panel, {height:0}).play(); } else { dojo.anim(panel, {height:200}).play(); } dojo.toggleClass(this, "active"); }); });
Магические исчезновения
Этот пример покажет, как можно красиво и легко убирать растворять элементы (см. пример):
Когда мы кликаем по картинке , будет найден родительский элемент
dojo.addOnLoad(function(){ dojo.query(".pane .delete").connect("onclick",function(){ dojo.fadeOut({node:this.parentNode, duration:1000, onEnd: dojo.partial(dojo.style, this.parentNode, "display", "none")}).play(); // по завершению - прячем элемент display:none }); });
Связанная анимация #1
Теперь пример посложнее, но он поможет Вам лучше понять Dojo. Всего несколько строк кода заставят квадраты двигаться, изменять размер и прозрачность. (см. пример):
// когда прогрузилась страница (DOM готов к манипуляциям) dojo.addOnLoad(function(){ // привязываемся к событию click для элемента с class="down" dojo.query(".down").connect("onclick",function(e){ e.preventDefault(); // удаляем событие по умолчанию // бежим по всем найденым элементам с class="box" dojo.query('.box').forEach(function(el){ dojo.anim(el,{ top: dojo.style(el,'top')+160 // наращиваем позицию top на 160px , left: dojo.style(el,'left')+160 // наращиваем позицию left на 160px , width: dojo.style(el,'width')+10 // наращиваем ширину на 10px , height: dojo.style(el,'height')+10 // наращиваем высоту на 10px , opacity: dojo.style(el,'opacity')-0.2 // уменьшаем opacity на 0.2 }, 1000).play(); // запускаем анимацию, указывая время в 1000ms = 1s }); }); }); // привязываемся к событию click для элемента с class="up", далее все аналогично dojo.query(".up").connect("onclick",function(e){ e.preventDefault(); dojo.query('.box').forEach(function(el){ dojo.anim(el,{ top: dojo.style(el,'top')-160 , left: dojo.style(el,'left')-160 , width: dojo.style(el,'width')-10 , height: dojo.style(el,'height')-10 , opacity: dojo.style(el,'opacity')+0.2}, 1000).play(); }); }); }); });
Примечание: в Opera 9.63 неправильно определяется первоначальное положение элементов
Связанная анимация #2
А теперь будем анимировать каждый box по отдельности. Для движения “вниз” будем использовать dojo.fx.chain – и вся анимация будет выполняться последовательно. Для движения вверх будем использовать dojo.fx.combine – анимация будет происходить параллельно (см. пример):
dojo.require("dojo.fx"); dojo.addOnLoad(function(){ // выбираем каждый элемент по отдельности var box1 = dojo.query('.box:nth-child(1)')[0]; var box2 = dojo.query('.box:nth-child(2)')[0]; var box3 = dojo.query('.box:nth-child(3)')[0]; // вешаем обработчик на "down" dojo.query(".down").connect("onclick",function(e){ e.preventDefault(); dojo.fx.chain( [ dojo.animateProperty({node:box1,properties:{top: dojo.style(box1,'top')+160,duration:1000}}) // изменяем позицию первого квадрата ,dojo.animateProperty({node:box1,properties:{left: dojo.style(box1,'left')+160,duration:1000}}) ,dojo.animateProperty({node:box2,properties:{top: dojo.style(box2,'top')+160,duration:1000}}) // изменяем позицию второго квадрата ,dojo.animateProperty({node:box2,properties:{left: dojo.style(box2,'left')+160,duration:1000}}) ,dojo.animateProperty({node:box3,properties:{top: dojo.style(box3,'top')+160,duration:1000}}) // изменяем позицию третьего квадрата ,dojo.animateProperty({node:box3,properties:{left: dojo.style(box3,'left')+160,duration:1000}}) ] ).play(); }); // вешаем обработчик на "up" dojo.query(".up").connect("onclick",function(e){ e.preventDefault(); dojo.fx.combine( [ dojo.animateProperty({node:box1,properties:{top: dojo.style(box1,'top')-160,duration:1000}}) ,dojo.animateProperty({node:box1,properties:{left: dojo.style(box1,'left')-160,duration:1000}}) ,dojo.animateProperty({node:box2,properties:{top: dojo.style(box2,'top')-160,duration:1000}}) ,dojo.animateProperty({node:box2,properties:{left: dojo.style(box2,'left')-160,duration:1000}}) ,dojo.animateProperty({node:box3,properties:{top: dojo.style(box3,'top')-160,duration:1000}}) ,dojo.animateProperty({node:box3,properties:{left: dojo.style(box3,'left')-160,duration:1000}}) ] ).play(); }); });
Примечание: функции dojo.fx.chain и dojo.fx.combine – работают с dojo.animateProperty и не понимают dojo.anim
Гармошка #1
Пример реализации “гармошки”. (см. пример)
Теперь приступим к разбору полетов:
// подключаем dojo.fx и dojo.NodeList-fx dojo.require("dojo.fx"); dojo.require("dojo.NodeList-fx"); dojo.addOnLoad(function(){ // прячем все параграфы (можете использовать CSS, но будет не так интересно) dojo.query(".accordion div p").style({ display:'none' }); // вешаемся на событие onclick dojo.query(".accordion h3").connect("onclick",function(){ // получаем индекс текущего элемента в предке var index = dojo.query(".accordion h3").indexOf(this); // прячем все параграфы кроме текущего dojo.forEach(dojo.query(".accordion div").query("p"), function(item, idx){ if (idx != index && dojo.style(item, 'display') != 'none') { dojo.query(item).wipeOut().play(); } }); // получаем необходимый нам <p> var p = dojo.query("p", this.parentNode); // проверяем наличие класса active if (dojo.hasClass(this,'active')) { dojo.removeClass(this,'active'); // удаляем класс active p.wipeOut().play(); // прячем <p> } else { dojo.addClass(this,'active'); // добавляем класс active p.wipeIn().play(); // показываем <p> } }); });
Приведу сразу код HTML, чтобы далеко не ходить:
<div class="accordion"> <div> <h3>Question One Sample Text</h3> <p>Lorem ipsum dolor sit amet...</p> </div> <div> <h3>This is Question Two</h3> <p>Lorem ipsum dolor sit amet...</p> </div> <div> <h3>Another Questio here</h3> <p>Lorem ipsum dolor sit amet...</p> </div> </div>
Примечание: наткнулся на различное поведение селектора
:first-child
в Dojo и jQuery в приведенном примере. Dojo не находит элемент <p>, т.к. он не является first-child’ом относительно парента, jQuery же находит, т.к. он является первым потомком <p>. Кто прав я не могу сказать точно, но браузеры считают, что таки Dojo… (селектор :nth-child в Dojo так же считает вхождения потомков иначе).Еще брошу камень в огород Dojo – кода в jQuery значительно меньше, и структура документа проще (хотя, возможно, я просто не знаю, как получить в Dojo следующий элемент в доме, имея лишь текущий node).
Так же не совсем понятно, почему при переборе
dojo.query(".accordion div p").forEach(...)
элементы идут в обратном порядке (лишь в webkit’е правильно), при этомdojo.query(".accordion div").query("p").forEach(...)
работает верно во всех браузерах.
Гармошка #2
Этот пример схож с предыдущим, лишь отличается тем, что мы указываем открытую по умолчанию панельку. (см. пример)
В CSS у нас указано для всех элементов
display:none. Теперь нам необходимо открыть третью панель. Для этого мы можем написать следующий код:
dojo.addOnLoad(function(){ // выбираем третий div и добавляем к заголовку класс active dojo.query(&amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;quot;.accordion div:nth-child(3) h3&amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;quot;).addClass(&amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;quot;active&amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;quot;); // работает лишь с webkit'ом // dojo.query(&amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;quot;.accordion div:not(:nth-child(3)) p&amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;quot;).style({ display:'none' }); var els = dojo.query(&amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;quot;.accordion div p&amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;quot;); // выбираем все параграфы els.splice(2,1); // вырезаем третий (тут отсчет с нуля идет) els.style({ display:'none' }); // все остальные скрываем /* ... */ });
Примечание: Селектор вида
div:not(:nth-child(2))
заработал лишь в Safari и Chrome. Кстати, реализовал я анимацию в данном примере иначе – использовал dojo.fx.Toggler – достаточно забавная вещь, правда я так и не понял как правильно переключаться между show() и hide() (к примеру, если мне хочется создать функцию аля slideToggle в jQuery)
Анимация для события hover #1
Данный пример поможет создать Вам очень красивую анимацию для события hover (надеюсь, Вы знаете что это?), (см. пример):
Когда Вы наводите мышкой на элемент меню (mouseover), происходит поиск следующего элемента <em> и анимируются его прозрачность и расположение:
dojo.addOnLoad(function(){ // вешаемся на событие onmouseover dojo.query(&amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;quot;.menu a&amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;quot;).connect(&amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;quot;onmouseover&amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;quot;,function(){ // ищем em элемент и анимируем его var em = dojo.query('em', this.parentNode); dojo.animateProperty({ node: em[0], duration:500, properties: { opacity: { start: 0, end: 1 }, // прозрачность top: { start:-85, end:-70, unit:&amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;quot;px&amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;quot; } // располложение }, beforeBegin:function() { // перед началом анимации надо выставить правильно св-во display em.style({display:'block'}); } }).play(); }); // вешаемся на событие onmouseout dojo.query(&amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;quot;.menu a&amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;quot;).connect(&amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;quot;onmouseout&amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;quot;,function(){ var em = dojo.query('em', this.parentNode); dojo.animateProperty({ node: em[0], duration:300, properties: { opacity: { start: 1, end: 0 }, top: { start:-70, end: -85, unit:&amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;quot;px&amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;quot; } }, onEnd:function() { em.style({display:'none'}); } }).play(); }); });
Анимация для события hover #2
Данный пример чуть-чуть посложней предыдущего примера: для формирования подсказки используется атрибут title (см. пример)
Первым делом добавим тэг <em> в каждый элемент <a>. Когда произойдет событие mouseover, мы возьмем текст из атрибута “title” и вставим его в тэг <em>:
dojo.addOnLoad(function(){ dojo.query(&amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;quot;.menu2 a&amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;quot;).connect(&amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;quot;onmouseover&amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;quot;,function(){ // создаем елемент em и закидываем его в DOM var em = dojo.query(dojo.create('em', {innerHTML:dojo.attr(this, 'title')})).place(this.parentNode); // анимация dojo.animateProperty({ node: em[0], duration:500, properties: { opacity: { start: 0, end: 1 }, top: { start:-85, end:-70, unit:&amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;quot;px&amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;quot; } }, beforeBegin:function() { em.style({display:'block'}); } }).play(); }); dojo.query(&amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;quot;.menu2 a&amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;quot;).connect(&amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;quot;onmouseout&amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;quot;,function(){ var em = dojo.query('em', this.parentNode); dojo.animateProperty({ node: em[0], duration:300, properties: { opacity: { start: 1, end: 0 }, top: { start:-70, end: -85, unit:&amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;quot;px&amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;quot; } }, onEnd:function() { // удаляем элемент из DOM'a em.orphan(); } }).play(); }); });
Кликабельные блоки
Этот пример демонстрирует, как сделать кликабельным блок с текстом, а не только ссылку (см. пример):
Создадим список <ul> с классом class=”pane-list” и мы хотим сделать элементы <li> кликабельными. Для начала привяжемся к событию click для элемента “.pane-list li”; когда пользователь будет кликать по элементу списка, наша функция произведет поиск тэга <a> и сделает редирект на страницу указанную в атрибуте href.
dojo.addOnLoad(function(){ dojo.query(&amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;quot;.pane-list li&amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;quot;).connect(&amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;quot;click&amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;quot;,function(){ window.location=dojo.query(&amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;quot;a&amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;quot;, this).attr(&amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;quot;href&amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;quot;);return false; }); });
Складывающиеся панельки
Ну, а теперь чуть-чуть скомбинируем предыдущие примеры и создадим ряд складывающихся панелек (наподобие как в Gmail организован inbox). (см. пример)
- скрываем все элементы
<div class="message_body">
после первого. - скрываем все элементы
<li>
после пятого - клик по <p class=”message_head”> – вызывает метод wipeOut/wipeIn для следующего элемента <div class=”message_body”>
- клик по <a class=”collpase_all_message”> – вызывает метод wipeOut для всех <div class=”message_body”>
- клик по <a class=”show_all_message”> – скрывает элемент, и отображает <a class=”show_recent_only”>, так же вызывается метод wipeIn для всех <li> после пятого
- клик по <a class=”show_recent_only”> – скрывает элемент, и отображает <a class=”show_all_message”>, так же вызывается метод wipeOut для всех <li> после пятого
dojo.require(&amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;quot;dojo.fx&amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;quot;); dojo.require(&amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;quot;dojo.NodeList-fx&amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;quot;); dojo.addOnLoad(function(){ // hide message_body after the first one dojo.query(&amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;quot;.message_list li:not(:first-child) .message_body&amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;quot;).style({ display:'none' }); // hide message li after the 5th // dojo.query(&amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;quot;.message_list li&amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;quot;).splice(4).style({ display:'none' }); // not equal for FF and IE dojo.query(&amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;quot;.message_list li:nth-child(1n+4)&amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;quot;).style({ display:'none' }); // event on header click dojo.query(&amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;quot;.message_head&amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;quot;).connect('onclick',function(){ var body = dojo.query(&amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;quot;.message_body&amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;quot;,this.parentNode) if (dojo.style(body[0], 'display') != 'none') { body.wipeOut().play(); } else { body.wipeIn().play(); } return false; }); // collapse all messages dojo.query(&amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;quot;.collpase_all_message&amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;quot;).connect('onclick',function(e){ e.preventDefault(); dojo.query(&amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;quot;.message_body&amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;quot;).wipeOut().play(); }); // show all messages dojo.query(&amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;quot;.show_all_message&amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;quot;).connect('onclick',function(e){ e.preventDefault(); dojo.query(this).fadeOut().play(); dojo.style(this,'display','none'); dojo.query(&amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;quot;.show_recent_only&amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;quot;).style('display','block').fadeIn().play(); dojo.query(&amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;quot;.message_list li:nth-child(1n+4)&amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;quot;).wipeIn().play(); }); // hide old messages dojo.query(&amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;quot;.show_recent_only&amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;quot;).connect('onclick',function(e){ e.preventDefault(); dojo.query(this).fadeOut().play(); dojo.style(this,'display','none'); dojo.query(&amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;quot;.show_all_message&amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;quot;).style('display','block').fadeIn().play(); dojo.query(&amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;quot;.message_list li:nth-child(1n+4)&amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;quot;).wipeOut().play(); }); });
Примечание: заметил различное поведение функции dojo.NodeList.splice в различных браузерах
Имитация Backend’a WordPress’a
Я думаю многие из читателей сталкивались с админской частью wordpress’a, точнее с редактирование комментариев. Попробуем сделать что-то подобное (см. пример):
- добавим класс “alt” к каждому чётному элементу
<div class="pane">
(данный класс изменяет цвет фона элемента) - клик по <a class=”btn-delete”> инициирует появление сообщения (alert), так же происходит анимация фонового цвета и прозрачности (backgroundColor и opacity) для <div class=”pane”>
- клик по <a class=”btn-unapprove”> – вызывает анимацию фона у <div class=”pane”> (цвет изменяется на желтый и обратно) и добавляет класс “spam”
- клик по <a class=”btn-approve”> – вызывает анимацию фона у <div class=”pane”> (цвет изменяется на зеленый и обратно) и удаляет класс “spam”
- клик по <a class=”btn-spam”> – вызывает анимацию фона у <div class=”pane”> (цвет изменяется на красный), затем вызываем FadeOut(), по завершению анимации элемент удаляем из DOM’а
dojo.require('dojo.fx'); dojo.addOnLoad(function(){ // находим четные элементы dojo.query(&amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;quot;.pane:nth-child(even)&amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;quot;).addClass(&amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;quot;alt&amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;quot;); dojo.query(&amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;quot;.pane .btn-delete&amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;quot;).connect('onclick',function(e){ // удаляем стандартный обработчик события - чтобы не было перехода по ссылке e.preventDefault(); alert(&amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;quot;This comment will be deleted!&amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;quot;); // выбираем необходимый нам блок var block = this.parentNode.parentNode; // вся анимация будет происходить последовательно var anim = dojo.fx.chain([ dojo.animateProperty({ node: block, properties: { backgroundColor: &amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;quot;#fbc7c7&amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;quot; }}), dojo.fadeOut({ node: block}) ]); // по завершению анимации блок будет спрятан dojo.connect(anim, &amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;quot;onEnd&amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;quot;, function(){ dojo.style(block, {'display':'none'}); }); anim.play(); }); dojo.query(&amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;quot;.pane .btn-unapprove&amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;quot;).connect('onclick',function(e){ e.preventDefault(); var block = this.parentNode.parentNode; dojo.fx.chain([ dojo.animateProperty({ node: block, properties: { backgroundColor: &amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;quot;#fff568&amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;quot; }}), dojo.animateProperty({ node: block, properties: { backgroundColor: &amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;quot;#ffffff&amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;quot; }, onEnd:function() { dojo.addClass(block, 'spam'); }}) ]).play(); }); dojo.query(&amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;quot;.pane .btn-approve&amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;quot;).connect('onclick',function(e){ e.preventDefault(); dojo.fx.chain([ dojo.animateProperty({ node: this.parentNode.parentNode, properties: { backgroundColor: &amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;quot;#dafda5&amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;quot; }}), dojo.animateProperty({ node: this.parentNode.parentNode, properties: { backgroundColor: &amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;quot;#ffffff&amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;quot; }, onEnd:function() { dojo.removeClass(this.node, 'spam'); }}) ]).play(); }); dojo.query(&amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;quot;.pane .btn-spam&amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;quot;).connect('onclick',function(e){ e.preventDefault(); dojo.fx.chain([ dojo.animateProperty({ node: this.parentNode.parentNode, properties: { backgroundColor: &amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;quot;#fbc7c7&amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;quot; }}), dojo.fadeOut({ node: this.parentNode.parentNode, properties: { backgroundColor: &amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;quot;#ffffff&amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;quot; }, onEnd:function() { dojo.query(this.node).orphan(); }}) ]).play(); }); });
Примечение: код каждой функции немного различается, так – для разнообразия
Галерея изображений
Простейший пример реализации галереи, без перезагрузки страницы. (см. пример)
Для начала добавим тэг <em>
в заголовки <h2>
По клику на изображения в <p class=thumbs> выполняем следующие действия:
- отменяем событие по умолчанию (это переход по ссылке)
- сохраняем значение атрибута “href” в переменной “largePath”
- сохраняем значение атрибута “title” в переменной “largeAlt”
- заменяем в элементе <img id=”largeImg”> значение атрибута “scr” и “alt” значениями из переменных “largePath” и “largeAlt”
- так же присваиваем элементу “h2 em” значение из “largeAlt”
dojo.addOnLoad(function(){ dojo.query(dojo.create('em')).place(dojo.query('h2')); dojo.query(&amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;quot;.thumbs a&amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;quot;).connect(&amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;quot;onclick&amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;quot;,function(e){ e.preventDefault(); // получаем необходимые нам данные var largePath = dojo.attr(this, &amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;quot;href&amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;quot;); var largeAlt = dojo.attr(this, &amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;quot;title&amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;quot;); // заменяем картинку и alt-текст dojo.attr(&amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;quot;largeImg&amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;quot;, {src:largePath,alt:largeAlt}); em = dojo.query(&amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;quot;h2 em&amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;quot;)[0]; // изменяем описание em.innerHTML = &amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;quot; (&amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;quot; + largeAlt + &amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;quot;)&amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;quot;; }); });
Стилизируем ссылки
Большинство нормальных браузеров легко понимают когда мы хотим добиться от них стилизации ссылок для различного типа файлов, для это цели можно использовать следующее CSS правило: a[href $='.pdf'] { ... }
. Но как обычно IE6 отличается умом и сообразительностью, по этой причине будем ставить ему костыли используя Dojo. (см. пример)
Для начала добавим класс для каждой ссылки, в соответствии с типом файла.
Затем выберем все элементы <a>
которые не содержат ссылки на “http://anton.shevchuk.name” и не начинающиеся на “#” в “href”, затем добавим им класс "external"
и устанавливаем target= "_blank"
.
dojo.addOnLoad(function(){ dojo.query(&amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;quot;a[href$=pdf]&amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;quot;).addClass(&amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;quot;pdf&amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;quot;); dojo.query(&amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;quot;a[href$=zip]&amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;quot;).addClass(&amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;quot;zip&amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;quot;); dojo.query(&amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;quot;a[href$=psd]&amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;quot;).addClass(&amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;quot;psd&amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;quot;); dojo.query(&amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;quot;a:not([href*=http://anton.shevchuk.name])&amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;quot;).filter(&amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;quot;:not([href^=#])&amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;quot;) .addClass(&amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;quot;external&amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;quot;) .attr({ target: &amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;quot;_blank&amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;quot; }); });
Так же Вы можете посмотреть все примеры или скачать Dojo для начинающих.
Полезные ссылки
Приведу ссылки на полезные ресурсы по теме:
- Общий взгляд на Dojo Toolkit
- Два примера создания data – таблицы на Dojo Toolkit и JQuery. Часть 1
- Dojo Campus – много полезной информации, так же есть свой Quick Start
- Dojo Quick Start Guide – SitePen, Inc.
- Introducing The Dojo Toolkit