Dojo — это модульная библиотека JavaScript. Разработана для простоты и ускорения в построении сайтов с использованием интерактивных систем и AJAX технологий. Разработка данной библиотеки берет свое начало с 2004 года. С версии 1.0. С выходом версии 1.6 dojo начало использоваться в Zend Framework.
Внутренние классы Dojo
Помимо гибкого расширения в разработке и написание собственных объектов, Dojo предлагает к использованию уже большой комплект собственных написанных объектов. В него входит коллекция инпутов, с валидациями и всплывающими окнами, чекбоксы и радио батоны, выпадающие списки и различными возможностями, а также модули для работы с графикой, построение диаграмм, модули грид, локальные хранилища данных, модули для работы с AJAX и еще многое другое.
В версиях 1.10 была выпущенна поддержка работы с мобильными устройствами.
Также библиотека Dojo поддерживает работу с браузерами:
Поддержка в операционных системах
Dojo и Dijit UI Framework.
Без сомнения, самым большим преимуществом Dojo Toolkit перед другими JavaScript фреймворками является его Dijit UI фреймворк.
Это беспрецедентный набор лэйаутов, форм и других инструментов:
По мимо выше перечисленных пунктов dojo предлагают пользователям прямо из коробки 5 тем для начальной разработки и построения интерфейсов. Имена шаблонов стиля:
Также, исходя из этих шаблонов возможно написать свой шаблон стилей, который будет подчеркивать индивидуальность.
Модульность и расширяемость
Клиентский JavaScript код, как и любой код, склонен расти в размерах. Модульность является тем ключем, который делает наш код легко поддерживаемым и производительным. Dojo Toolkit является ярким примером фреймворка, использующего модули. Он использует dojo.require для того, чтобы динамически подтягивать только те ресурсы, которые нужны странице в данный момент.
Dojo использует асинхронный загрузчик, который мастерски загружает все ресурсы асинхронно и намного быстрее, чем в начальных версиях 1.0 — 1.3.
Пример кода:
// Функция require сообщает загрузчику, что необходимы модули из первого массива
// Если модуль из списка уже был загружен, то он будет взят из кэша
require(
// Массив модулей требующих загрузки [“dojo/on”, “dojo/touch”, “dijit/form/Button”, “dojo/domReady!”],
// Функция, которая будет вызвана после загрузки всех модулей,
// с объектами модулей переданными ей в качестве аргументов.
// Модули должны быть перечислены в том же порядке, что и в массиве требований
function(on, touch, Button) {
// Здесь выполняем нужные нам действия с загруженными модулями.
});
В дальнейшем будет приведен пример – написание собственного модуля системного окна уведомления пользователей.
В то время, как JavaScript не предоставляет настоящей системы классов, Dojo Toolkit предоставляет классоподобный паттерн наследования, основанный на использовании dojo/declare. Declare реализован во фреймворке так, что позволяет разработчикам:
Одной из самых негативных сторон в разработке модулей есть непонимание проблем в возникающих ошибках при удалениях и созданиях новых объектов, так как система оповещения об ошибках с описанием в dojo отсутствует.
Система классов Dojo использует прототипное наследование. Использование dojo/declare невероятно просто:
Пример кода:
define([
“dojo/_base/declare”, // базовые классы для расширения
“dijit/_WidgetBase”,
“dijit/_TemplatedMixin”,
‘dijit/_AttachMixin’,
‘dijit/_WidgetsInTemplateMixin’,
“dojo/_base/fx”,
“dojo/_base/lang”,
“dojo/text!./templates/template1.html”, // путь к используемому шаблону
“dojo/dom-style”, // внутренние классы для работы с структурой DOM
“dojo/on”,
“dojo/mouse”,
“dojo/dom-construct”,
//подключаемые классы из предоставленых библиотекой dojo компонентов.
“dijit/form/Button”
], function(declare, _WidgetBase, _TemplatedMixin, _AttachMixin, _WidgetsInTemplateMixin, baseFx, lang, template, domStyle, on, mouse, require, domConstruct, Button){
return declare([_WidgetBase, _TemplatedMixin, _AttachMixin, _WidgetsInTemplateMixin], {
templateString: template,
description: “”,
alertType: “”,
baseClass: “systemAlert”,
answer: null,
}
});
});
Класс Dojo поддерживает подключение уже готовых встроенных классов, или уже написаных рание. Что позволяет расширять функциональность и дополнять новыми возможностями.
Каждый класс поддерживает создание своего используемого шаблона на основе вертки HTML. Что является еще одним плюсом, так как шаблон можно в любой момент изменить или перестроить под собственные нужды. Тем самым позволяет отделять верстку от создаваемой функциональности.
Пример шаблона:
<div>
<h3 data-dojo-attach-point=”Nodetitle” class=”${baseClass}title” ></h3>
<div class=”${baseClass}description”>
<img class=”${baseClass}image” src=”” data-dojo-attach-point=”Nodemessageimage”>
<p data-dojo-attach-point=”Nodedescription” class=”alertdescription”>${description}</p>
<div class=”${baseClass}buttonpanel”>
<button data-dojo-type=”dijit.form.Button” data-dojo-attach-point=”buttonOk” label=”Ок” data-dojo-attach-event=”click:ok” ></button>
<button data-dojo-type=”dijit.form.Button” data-dojo-attach-point=”Cancel” label=”Відмінити” data-dojo-attach-event=”click: cancel”></button>
</div>
</div>
</div>
Главным и решающим моментом в создание шаблона является нахождения всего тела шаблона в одном теге. Все внутренные переменные в шаблоне объявляються в формате ${baseClass}. Доступ к определенным узлам в шаблоне фиксинуеться внутринными переменными типа data-dojo-attach-point = «имя переменной». Для того, чтобы прикрепить к определенному тегу событие, используют внутреннюю переменную data-dojo-attach-event=” «название события»: «Имя функции» “. Где имя функции описываеться в теле класса:
data-dojo-attach-event=”click: cancel”
Использование стандартных модулей, а также модулей, написанных в ходе разработки, возможна двумя разными способами. Первый из них является инициализацией объекта через JavaScript:
<script>
require([“mywidjet/systemAlert”,
function(systemAlert){
dojo.byId(“IdName”).appendChild(new systemAlert({}).domNode);
});
</script>
и другой способ, который возможен в виде описания модуля HTML разметкой. Но при этом следует иницализировать стандартный объект dojo.parser, которой распознает в структуре HTML ключевые слова, по которым может создать готовый объект dojo.
<div id=”IdName” data-dojo-type=”mywidjet/systemAlert”></div>
При таком объявлении в параметры тега можно вписывать все нужные значения для работы вашего объекта.
Пример описание инпута с валидацией и текстовым сообщением при не коректном вводе данных.
<script>
require([“dojo/parser”, “dijit/form/ValidationTextBox”]);
</script>
<label for=”phone”>Phone number, no spaces:</label>
<input type=”text” name=”phone” id=”phone” value=”someTestString” required=”true”
data-dojo-type=”dijit/form/ValidationTextBox”
data-dojo-props=”regExp:'[\\w]+’, invalidMessage:’Invalid Non-Space Text.'” />
От теории к практике
Данный пример заключается в написании собственного виджета, расширяемого элементами dijit Ui framework`a, с использованием call-back функций, привязкой событий к виджету и работу с внутренними переменными, а также доступ к ним.
Начнем с самого простого и построим дерево каталогов, в котором будем хранить *.js с нашими виджетами, каталог с шаблонами, каталог с изображениями, каталог для файла с стилями.
Тематика нашего виджета будет предельно простой, это будет окно уведомления пользователя, которое будет в себе вмещать изображение, описание, название (шапку).
Функциональность виджета будет реагировать на нажатия кнопок. Их будет две: для окна, которое будет опрашивать пользователя, и одна кнопка для простого окна уведомления, после которого системное окно будет удаляться.
Начнем с создания каркаса виджета, в него входит создание шаблона, привязку шаблона к виджету, объявление базовых класcов dojo, которые будут расширять наш виджет стандартными функциями, которые присутствуют во всех виджетах dojo.
Пример кода виджета «systemAlert»:
define([
“dojo/_base/declare”,
“dijit/_WidgetBase”,
“dijit/_TemplatedMixin”,
“dojo/text!./templates/template1.html”,
“dojo/dom-style”,
“dojo/_base/fx”,
“dojo/_base/lang”,
“dojo/on”,
“dojo/mouse”,
“require”,
“dojo/dom-construct”,
‘dijit/_AttachMixin’,
‘dijit/_WidgetsInTemplateMixin’,
“dijit/form/Button”
], function(declare, _WidgetBase, _TemplatedMixin, template, domStyle, baseFx, lang, on, mouse, require, domConstruct, _AttachMixin, _WidgetsInTemplateMixin, Button){
return declare(“mywidjet/systemAlert”, [_WidgetBase, _TemplatedMixin, _AttachMixin, _WidgetsInTemplateMixin], {
templateString: template
}
});
});
Выше указанная конструкция служит для построения виджета и привязки шаблона по указанному адресу. Все подключаемые классы в блоке «define» должны быть последовательно объявлены в функцию, которая передастся вторым параметром.
Шаблон, который привязан к виджету:
<div>
<h3 data-dojo-attach-point=”Nodetitle” class=”${baseClass}title” ></h3>
<div class=”${baseClass}description”>
<img class=”${baseClass}image” src=”” data-dojo-attach-point=”Nodemessageimage”>
<p data-dojo-attach-point=”Nodedescription” class=”alertdescription”>${description}</p>
<div class=”${baseClass}buttonpanel”>
<button data-dojo-type=”dijit.form.Button” data-dojo-attach-point=”buttonOk” label=”Ок” data-dojo-attach-event=”click:ok” ></button>
<button data-dojo-type=”dijit.form.Button” data-dojo-attach-point=”Cancel” label=”Відмінити” data-dojo-attach-event=”click: cancel”></button>
</div>
</div>
</div>
Данная конструкция может быть уже инициализирована и работать. Но без всякой функциональности.
Для примера я приведу следущий код, который заставит виджет показаться на экран =)
<!DOCTYPE HTML>
<html>
<head>
<meta charset=”utf-8″>
<title>Тег DIV</title>
<script type=”text/javascript” src=”js/dojo-release/dojo/dojo.js” djConfig=”parseOnLoad:true, isDebug:true”></script>
<link rel=”StyleSheet” type=”text/css” href=”/js/dojo-release/dijit/themes/claro/claro.css”>
<link rel=”StyleSheet” type=”text/css” href=”/js/dojo-release/mywidjet/css/systemAlert.css”>
</head>
<body class=”claro”>
<div data-dojo-type=”mywidjet/systemAlert” alertType=”question” description=”Тут написаное описание вопроса?”></div>
</body></html>
<script>
require([“dojo/parser”], function(parser){ parser.parse(); });</script>
И получаем картинку нашего уже полуработающего виджета.
И для того, чтобы показать еще второй способ вызвать виджет, опишу кусочек куда:
<script>
require([“mywidjet/systemAlert”],
function(systemAlert){
dojo.byId(“1234”).appendChild(new systemAlert({
‘alertType’ : ‘question’,
‘description’: “Тут написаное описание вопроса?”
}).domNode);
});
});
</script>
При выше указаном объявлении мы получим такой же результат, как и в первом случае.
Теперь, когда мы уже описали шаблон и базовый виджет, можно приступить к описанию его функциональности.
Пример кода функционала виджета:
templateString: template, // данная переменная является базовой она отвечает за привязку шаблона к виджету и расширяет параметры виджета, объявленными переменными в шаблоне.
Description: “”, // переменная, которая отвечает на описание, которое будет находиться в виджете.
AlertType: “”, // Отвечает за тип увидомления. Типы виджета описаны в функции PostCreate.
baseClass: “systemAlert”, // базовый класс виджета для применения стиля
answer: null, // call-back функция для получения ответа от пользователя
ok: function() // функция, которая вызывается при нажатии на кнопку «OK»
{
if(typeof(this.answer) == “function”) //call-back функция, которая отвечает за ответ пользователя.
this.answer(true);
},
cancel: function(){ // функция, которая вызывается при нажатии на кнопку «Відміна»
if(typeof(this.answer) == “function”)
this.answer(false);
},
constructor: function (args){ // базовая функция. Являеться точкой начала создания виджета
if(args){
lang.mixin(this,args);
}
},
// базовая функция, которая выполняется после функции констракт и выводит инициализированый объект в HTML разметку.
postCreate: function() {
switch(this.alertType) // обращение к переменой в теле виджета.
{
case “informing”: {
this.Nodetitle.innerHTML = “Інформування”; // переменная, которая подтягивается с шаблона виджета.
this.Nodemessageimage.src = require.toUrl(“./image/informing.png”);
domStyle.set(this._startupWidgets[1].domNode, “display”, “none”); /* this._startupWidgets[1] this is button cancel*/
break;
}
case “error”: {
this.Nodetitle.innerHTML = “Помилка”;
this.Nodemessageimage.src = require.toUrl(“./image/error.png”);
domStyle.set(this._startupWidgets[1].domNode, “display”, “none”); /* this._startupWidgets[1] this is button cancel*/
break;
}
case “success”: {
this.Nodetitle.innerHTML = “Успішно”;
this.Nodemessageimage.src = require.toUrl(“./image/success.png”);
domStyle.set(this._startupWidgets[1].domNode, “display”, “none”); /* this._startupWidgets[1] this is button cancel*/
break;
}
case “question”: {
this.Nodetitle.innerHTML = “Видійсно хочете виконати данну операцію?”;
this.Nodemessageimage.src = require.toUrl(“./image/question.png”);
break;
}
case “warning”: {
this.Nodetitle.innerHTML = “Попередження”;
this.Nodemessageimage.src = require.toUrl(“./image/warning.png”);
domStyle.set(this._startupWidgets[1].domNode, “display”, “none”); /* this._startupWidgets[1] this is button cancel*/
break;
}
default: break;
}
Данный пример направлен на поверхносное ознакомление с структурой работы dojo library и построение собсвенных виджетов и их работа.
Неужели сложно было код засунуть в code?!
Крутанская статья, но советую всю массу кода отформатировать, а то ведь совсем не читается, в оберните.
Спасибо за статью, хотя если честно сомневаюсь, что она будет полезной большинству пользователей ресурса. По-хорошему советую написать на хабр в песочницу, там больше людей оценит, тем более что копирайтерская часть статьи сделана “вытяжками” из вышеупомянутого.