Можливо, багато хто вже читали статті з серії jQuery для початківців, так ось з деяких пір мене зацікавив ще один JavaScript фреймворк, і зветься він Dojo Toolkit.
У цій статті я постараюся описати базові можливості Dojo, так само буду проводити паралелі з jQuery, так що не лякайтеся виникло дежавю…
Як я вже колись казав – краще вчитися на прикладах, так що приступимо…
Підключення
Ну, для початку Вам знадобиться сам фреймворк, його ви зможете завантажити з домашньої сторінки проекту, потім підключаємо його одним з наступних способів:
Використовуючи локальний файл:
Дана запис аналогічна попередньої:
var djConfig = {
isDebug:true,
parseOnLoad:true
};
Dojo так само доступний на наступних машин:
Селектори
Перейдемо до пошуку елементів, для цієї мети є наступні функції:
// найпростіший варіант – отримати елемент за його 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 to event 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”);
});
});
Магічні зникнення
Цей приклад покаже, як можна красиво і легко прибирати розчиняти елементи (див. приклад):
Коли ми клікаємо по картинці , буде знайдено батьківський елемент
і його прозорість буде повільно змінюватися від opacity= 1.0 до opacity=0 – для цього скористаємося функцією dojo.fadeOut:
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,’непрозорість’)-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,’непрозорість’)+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();
}
});
// отримуємо необхідний нам
var p = dojo.query(“p”, this.parentNode);
// перевіряємо наявність класу active
if (dojo.hasClass(this,’active’)) {
dojo.removeClass(this,’active’); // видаляємо клас active
p.wipeOut().play(); // ховаємо
} else {
dojo.addClass(this,’active’); // додаємо клас active
p.wipeIn().play(); // показуємо
}
});
});
Наведу відразу код HTML, щоб далеко не ходити:
Question One Sample Text
Lorem ipsum dolor sit amet…
This Question is Two
Lorem ipsum dolor sit amet…
Another Questio here
Lorem ipsum dolor sit amet…
Примітка: натрапив на різну поведінку селектора :first-child в Додзьо і jQuery у наведеному прикладі. Dojo не знаходить елемент
, т. к. він не є first-child’ом щодо парента, jQuery ж знаходить, оскільки він є першим нащадком
. Хто правий я не можу сказати точно, але браузери вважають, що таки 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(“.accordion div:nth-child(3) h3”).addClass(“active”);
// працює лише з webkit’ом
// dojo.query(“.accordion div:not(:nth-child(3)) p”).style({ display:’none’ });
var els = dojo.query(“.accordion div p”); // вибираємо всі параграфи
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), відбувається пошук наступного елемента і анімуються його прозорість і розташування:
dojo.addOnLoad(function(){
// вешаемся на подія onmouseover
dojo.query(“.menu a”).connect(“onmouseover”,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:”px” } // располложение
},
beforeBegin:function() { // перед початком анімації треба виставити правильно св-во display
em.style({display:’block’});
}
}).play();
});
// вешаемся на подію onmouseout
dojo.query(“.menu a”).connect(“onmouseout”,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:”px” }
},
onEnd:function() {
em.style({display:’none’});
}
}).play();
});
});
Анімація для події hover #2
Даний приклад трохи складніше попереднього прикладу: для формування підказки використовується атрибут title (див. приклад)
Першим ділом додамо тег в кожен елемент . Коли відбудеться подія mouseover, ми візьмемо текст з атрибуту “title” та вставити його в тег :
dojo.addOnLoad(function(){
dojo.query(“.menu2 a”).connect(“onmouseover”,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:”px” }
},
beforeBegin:function() {
em.style({display:’block’});
}
}).play();
});
dojo.query(“.menu2 a”).connect(“onmouseout”,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:”px” }
},
onEnd:function() {
// видаляємо елемент з DOM’a
em.orphan();
}
}).play();
});
});
Клікабельні блоки
Цей приклад демонструє, як зробити кликабельним блок з текстом, а не тільки посилання (див. приклад):
Створимо список
- з класом class=”pane-list” і ми хочемо зробити елементи
- клікабельними. Для початку прикуємося до події click для елемента “.pane-list li”; коли користувач буде клікати по елементу списку, наша функція зробить пошук тега і зробить редирект на сторінку зазначену в атрибуті href.
dojo.addOnLoad(function(){
dojo.query(“.pane-list li”).connect(“click”,function(){
window.location=dojo.query(“a”, this).attr(“href”);return false;
});
});Складаються панельки
Ну, а тепер трохи комбінуємо попередні приклади і створимо ряд складаються панельок (на зразок як в Gmail організований inbox). (див. приклад)
- покриваємо всі елементи
після першого. - покриваємо всі елементи
- після п’ятого
- клік по
– викликає метод wipeOut/wipeIn для наступного елемента
- клік по – викликає метод wipeOut для всіх
- клік по – приховує елемент, і відображає , так само викликається метод wipeIn для всіх
- після п’ятого
- клік по – приховує елемент, і відображає , так само викликається метод wipeOut для всіх
- після п’ятого
dojo.require(“dojo.fx”);
dojo.require(“dojo.NodeList-fx”);
dojo.addOnLoad(function(){
// hide message_body after the first one
dojo.query(“.message_list li:not(:first-child) .message_body”).style({ display:’none’ });
// hide message li after the 5th
// dojo.query(“.message_list li”).splice(4).style({ display:’none’ }); // not equal for FF and IE
dojo.query(“.message_list li:nth-child(1n+4)”).style({ display:’none’ });
// event header on click
dojo.query(“.message_head”).connect(‘onclick’,function(){
var body = dojo.query(“.message_body”,this.parentNode)
if (dojo.style(body[0], ‘display’) != ‘none’) {
body.wipeOut().play();
} else {
body.wipeIn().play();
}
return false;
});
// collapse all messages
dojo.query(“.collpase_all_message”).connect(‘onclick’,function(e){
e.preventDefault();
dojo.query(“.message_body”).wipeOut().play();
});
// show all messages
dojo.query(“.show_all_message”).connect(‘onclick’,function(e){
e.preventDefault();
dojo.query(this).fadeOut().play();
dojo.style(this,’display’,’none’);
dojo.query(“.show_recent_only”).style(‘display’,’block’).fadeIn().play();
dojo.query(“.message_list li:nth-child(1n+4)”).wipeIn().play();
});
// hide old messages
dojo.query(“.show_recent_only”).connect(‘onclick’,function(e){
e.preventDefault();
dojo.query(this).fadeOut().play();
dojo.style(this,’display’,’none’);
dojo.query(“.show_all_message”).style(‘display’,’block’).fadeIn().play();
dojo.query(“.message_list li:nth-child(1n+4)”).wipeOut().play();
});
});Примітка: помітив різну поведінку функції dojo.NodeList.splice в різних браузерах
Імітація Backend’a wordpress’a
Я думаю багато хто з читачів стикалися з адмінської частиною wordpress’a, точніше з редагування коментарів. Спробуємо зробити щось подібне (див. приклад):
- додамо клас “alt” до кожного елементу парним
(даний клас змінює колір фону елемента) - клік по ініціює появу повідомлення (alert), так само відбувається анімація фонового кольору і прозорості (backgroundColor і opacity) для
- клік по – викликає анімацію фону у
(колір змінюється на жовтий і назад) і додає клас “spam” - клік по – викликає анімацію фону у
(колір змінюється на зелений і назад) і видаляє клас “spam” - клік по – викликає анімацію фону у
(колір змінюється на червоний), потім викликаємо FadeOut(), по завершенню анімації елемент видаляємо з DOM’а
dojo.require(‘dojo.fx’);
dojo.addOnLoad(function(){
// знаходимо парні елементи
dojo.query(“.pane:nth-child(even)”).addClass(“alt”);
dojo.query(“.pane .btn-delete”).connect(‘onclick’,function(e){
// видаляємо стандартний обробник події – щоб не було переходу за посиланням
e.preventDefault();
alert(“This comment will be deleted!”);
// вибираємо необхідний нам блок
var block = this.parentNode.parentNode;
// вся анімація буде відбуватися послідовно
var anim = dojo.fx.chain([
dojo.animateProperty({ node: block, properties: { backgroundColor: “#fbc7c7” }}),
dojo.fadeOut({ node: block})
]);
// по завершенню анімації блок захований
dojo.connect(анім, “onEnd”, function(){
dojo.style(block, {‘display’:’none’});
});
anim.play();
});
dojo.query(“.pane .btn-unapprove”).connect(‘onclick’,function(e){
e.preventDefault();
var block = this.parentNode.parentNode;
dojo.fx.chain([
dojo.animateProperty({ node: block, properties: { backgroundColor: “#fff568” }}),
dojo.animateProperty({ node: block, properties: { backgroundColor: “#ffffff” }, onEnd:function() {
dojo.addClass(block, ‘spam’);
}})
]).play();
});
dojo.query(“.pane .btn-approve”).connect(‘onclick’,function(e){
e.preventDefault();
dojo.fx.chain([
dojo.animateProperty({ node: this.parentNode.parentNode, properties: { backgroundColor: “#dafda5” }}),
dojo.animateProperty({ node: this.parentNode.parentNode, properties: { backgroundColor: “#ffffff” }, onEnd:function() {
dojo.removeClass(this.node, ‘spam’);
}})
]).play();
});
dojo.query(“.pane .btn-spam”).connect(‘onclick’,function(e){
e.preventDefault();
dojo.fx.chain([
dojo.animateProperty({ node: this.parentNode.parentNode, properties: { backgroundColor: “#fbc7c7” }}),
dojo.fadeOut({ node: this.parentNode.parentNode, properties: { backgroundColor: “#ffffff” }, onEnd:function() {
dojo.query(this.node).orphan();
}})
]).play();
});
});Примітка: код кожної функції трохи різниться, так – для різноманітності
Галерея зображень
Найпростіший приклад реалізації галереї, без перезавантаження сторінки. (див. приклад)
Для початку додамо тег в заголовки
По кліку на зображення
виконуємо наступні дії:
- скасовуємо подія (це перехід за посиланням)
- зберігаємо значення атрибута href у змінній “largePath”
- зберігаємо значення атрибута “title” змінної “largeAlt”
- замінюємо в елементі
значення атрибута “scr” і “alt” значеннями змінних “largePath” і “largeAlt”
- так само присвоюємо елементу “h2 em” значення “largeAlt”
dojo.addOnLoad(function(){
dojo.query(dojo.create(’em’)).place(dojo.query(‘h2’));
dojo.query(“.thumbs a”).connect(“onclick”,function(e){
e.preventDefault();
// отримуємо необхідні нам дані
var largePath = dojo.attr(this, “href”);
var largeAlt = dojo.attr(this, “title”);
// замінюємо картинку і alt-текст
dojo.attr(“largeImg”, {src:largePath,alt:largeAlt});
em = dojo.query(“h2 em”)[0];
// змінюємо опис
em.innerHTML = ” (” + largeAlt + “)”;
});
});Стилизируем посилання
Більшість нормальних браузерів легко розуміють коли ми хочемо домогтися від них стилізації посилань для різного типу файлів, для цього можна використовувати наступне правило CSS: a[href $=’.pdf’] { … }. Але як зазвичай IE6 відрізняється розумом і кмітливістю, з цієї причини будемо ставити йому милиці використовуючи Dojo. (див. приклад)
Для початку додамо клас для кожного посилання, у відповідності з типом файлу.
Потім виберемо всі елементи які не містять посилання на “http://anton.shevchuk.name” і не починаються на ” # ” “href”, потім додамо їм клас “external” і встановлюємо target= “_blank”.dojo.addOnLoad(function(){
dojo.query(“a[href$=pdf]”).addClass (pdf);
dojo.query(“a[href$=zip]”).addClass(“zip”);
dojo.query(“a[href$=psd]”).addClass(“psd”);
dojo.query(“a:not([href*=http://anton.shevchuk.name])”).filter(“:not([href^=#])”)
.addClass(“external”)
.attr({ target: “_blank” });
});Так само Ви можете подивитися усі приклади або завантажити Dojo для початківців.
Корисні посилання
Наведу посилання на корисні ресурси по темі:
- Загальний погляд на Dojo Toolkit
- Два приклади створення data – таблиці на Dojo Toolkit і JQuery. Частина 1
- Dojo Campus – багато корисної інформації, так само є свій Quick Start
- Dojo Quick Start Guide – SitePen, Inc.
- Introducing The Dojo Toolkit
- покриваємо всі елементи