Цепочки вызовов функций (Chains) в MooTools 1.2
02/05/2009 21:17
Это руководство покажет, насколько мощными могут быть цепочки вызовов функций в Mootools. Цепочки облегчают последовательное выполнение стека функций.
Я размещу несколько таких коротких руководств в предстоящие недели. Каждое такое руководство будет нацелено на решение небольшой проблемы с помощью Mootools - это хороший путь для изучения возможностей фреймворка.
Немного о цепочках
Цепочки очень мощный механизм, он похож на Effect.Queue в Script.aculo.us, но его возможности в Mootools более широки. Цель этого краткого руководства состоит в том, чтобы показать вам, как использовать цепочки Mootools в условиях массового обслуживания эффектов в сочетании с другими произвольными действиями. Но так же вы увидите, что вы можете использовать цепочки и для решения других задач.
Из документации к Mootools 1.2:
Chain - специальный класс, который выполняет функции, одну за другой, причем каждая функция запускается только после завершения предыдущей. Его методы могут быть реализованы в любом классе при помощи указания Implements: Chain и, в настоящее время, эти методы реализованы в стандартных классах Fx и Request. Например, в классе Fx цепочки используются для создания сложной анимации.
Класс Chain может быть использован в качестве отдельного класса, но становится гораздо более мощным, если реализовать его интерфейс в собственных классах.
В этом руководстве я буду создавать класс, который реализует интерфейс класса Chain.
Класс Chain относится к компоненту Class.Extras, поэтому вам нужно убедиться, что вы отметите его и все его зависимости при скачивании собственной сборки Mootools.
Реализация интерфейса Chain
Прежде всего, нам нужно добавить методы и свойства класса Chain в наш класс:
var ChainExample = new Class({
Implements : Chain
});
Теперь класс ChainExample будет содержать следующие методы:
- Chain::chain() - Добавление любого количества функций в конец стека.
- Chain::callChain() - Получить функцию с вершины стека и вызвать её.
- Chain::clearChain() - Очистить стек.
Использование Chain для выполнения действий в заданном порядке
Мы реализовали интерфейс класса Chain в нашем классе ChainExample и готовы к использованию функциональности, которую он представляет.
Класс ChainExample добавит события к трём кнопкам. Когда кнопка будет нажата - появится соответствующая ей панель. Прежде, чем это произойдёт, все другие панели будут плавно исчезать. Здесь мы используем цепочки функций для того, чтобы задать нужный нам порядок действий.
Теперь код класса ChainExample будет таким:
/**
* Добавляем события к кнопкам. Нажатие кнопки приведет
* к закрытию всех панелей до того, как будет показана
* панель, соответствующая нажатой кнопке.
*/
var ChainExample = new Class({
Implements : Chain,
// Определяем ID кнопок и соответствующих им панелей.
actions : new Hash({
'button-one' : 'panel-one',
'button-two' : 'panel-two',
'button-three' : 'panel-three'
}),
// Массив, в котором будут храниться объекты эффектов к каждой панели.
effects : [],
initialize: function() {
// Добавляем событие onclick на каждую кнопку.
// Нажатие на кнопку приведет к вызову метода showPanel()
this.actions.getKeys().each(function(buttonId) {
$(buttonId).addEvent('click', this.showPanel.bindWithEvent(this));
}, this);
// Создаем объект Fx (эффект) для каждой панели.
this.actions.getValues().each(function(panelId) {
this.effects[panelId] = new Fx.Tween($(panelId), 'opacity', {
duration : 'short',
// При завершении эффекта ...
onComplete : function() {
// ... вызываем следующую функцию из цепочки
this.callChain()
}.bind(this)
});
}, this);
this.hideAll(); // Прячем все панели при инициализации
this.callChain(); // Запускаем вызов цепочки функций
},
// Скрываем все панели
hideAll: function() {
// Пробегаемся по каждой панели и последовательно:
// 1. плавно скрываем панель
// 2. устанавливаем css свойство display в none
// Заметим, что эта функция не вызывает ничего на самом деле,
// он просто добавляет действия в цепочку (Chain)
this.actions.getValues().each(function(panelId) {
this.chain(
function() { this.effects[panelId].start(0); },
function() {
$(panelId).setStyles({ 'display' : 'none' });
// Вызываем следующую функцию из цепочки
this.callChain();
}
);
}, this);
},
// При нажатии кнопки происходит плавное исчезание всех
// открытых панелей, а затем появляется панель, соответствующая нажатой кнопке.
showPanel: function(event) {
this.hideAll();
var panel = this.actions.get(event.target.get('id'));
this.chain(
function() {
$(panel).setStyles({'display': 'block', 'opacity': '0'});
// Вызываем следующую функцию из цепочки
this.callChain();
},
// Запускаем эффект (появление панели)
function() { this.effects[panel].start(1); }
);
// Запускаем вызов цепочки функций
this.callChain();
}
});
window.addEvent('domready', function() {
var myChain = new ChainExample();
});
Я опишу в деталях только код, имеющий отношение к цепочкам. Давайте посмотрим на каждую важную часть кода:
ChainExample::initialize
В конструкторе мы устанавливаем события на кнопки и создаем объекты эффектов (Fx) для панелей. Обратите внимание на onComplete. В нём мы получаем функцию из стека и запускаем её ( this.callChain() ) сразу после того, как эффект закончился.
ChainExample::hideAll
Внимательно посмотрите на этот метод. Вызов ChainExample::hideAll() на самом деле не скрывает панели. Метод добавляет в стек цепочек набор функций, которые будут скрывать и показывать панели в нужном порядке. Чтобы скрыть панели, мы должны запустить стек цепочек, используя метод this.callChain().
Заметьте, как вторая функция, переданная в стек, вызывает метод this.callChain(). Эта функция сообщает цепочке запускает слудующую функцию в цепочке.
Еще одна важная вещь, которую стоит отметить - функции внутри цепочки связываются между собой в том порядке, в котором они указаны в коде, так что у нас нет необходимости как-то явно связывать их между собой.
ChainExample::showPanel
Эта функция привязана к кнопке, при нажатии на которую должна появляться панель.
Сначала производится вызов ChainExample::hideAll(), но не производит какие-либо действия немедленно - панели скрываются только непосредственно после запуска this.callChain().
На данном этапе мы сделали всё необходимое, чтобы скрыть все панели по цепочке. Далее идет код, который занимается показом нужной панели.
После того, как мы добавили необходимые функции в цепочку, выполняется метод this.callChain() и далее, вся цепочка выполняется последовательно, благодаря тому, что в каждом звене цепочки задан собственный вызов this.callChain().
Мы создали класс, который позволяет объединить любое количество эффектов и произвольных функций и обеспечивает их выполнение в том порядке, в котором мы хотим. Таким образом, основная идея класса Chain заключается в создании стека функций и выполнии их в нужном порядке, когда это потребуется.
Демонстрация
Смотреть online-demo.
Эта статья - художественный перевод поста Дэниэла Скиннера.