Чуть больше года назад мне на глаза попался один сайт. На первый взгляд он не чем не отличался от сотни подобных сайтов, но мой коллега заметил множественное обновление мелких модулей при клике на функциональных элементах. Дальнейшим открытием было то, что он работает без перегрузок. На сегодняшний день у каждого из нас это не вызовет большого впечатления, но данный сайт работает уже больше 5 лет.
После двухдневного анализа сайта мы нашли ответ на вопрос — «Как он работает? ». Центром данного сайта был файл с названием msajax.js, что побудило нас к поискам в интернете. Информации оказалось мало, но достаточно для начала экспериментов.
Данная библиотека предоставляет набор классов для создания небольших элементов, из которых потом можно собрать полноценный сайт.
Для ее подключения достаточно добавить на страницу ScriptManager и у него прописать ScriptReference для всех наших файлов.
Приступим к созданию небольшого элемента.
Type.registerNamespace('MyNamespace');
// ctor
MyNamespace.Widget = function (element, someData) {
var t = this;
t.template = "<span><label></label></span>";
if (!element) {
element = $(t.template);
}
MyNamespace.Widget.initializeBase(t, [element]);
};
//methods
MyNamespace.Widget.prototype = {
initialize: function () {
var t = this;
MyNamespace.Widget.callBaseMethod(t, 'initialize');
},
dispose: function () {
var t = this;
MyNamespace.Widget.callBaseMethod(t, 'dispose');
},
someMethod: function(){
var t = this;
}
};
MyNamespace.Widget.registerClass('MyNamespace.Widget', Sys.UI.Control);
Наш элемент состоит из конструктора и набора методов. Конструктор вызывается при попытке создать экземпляр элемента и всегда первым параметром принимает element, это элемент DOM, в котором он будет отображаться. Дальше вызывается инициализация базового класса. В данном случае это Sys.UI.Control, который мы указали при вызове registerClass. Данный метод третьим параметром может принимать интерфейс, но об этом в следующий раз, если кому-то будет интересен данный пост.
В наборе методов всегда присутствуют два метода initialize и dispose по названию понятно чем они занимаются и описывать их не вижу смысла, могу сказать что я как правило в initialize создаю обработчики событий и заполняю нужные мне элементы, а в dispose описываю логику удаления элемента из DOM и отписку от различных событий. Так же мы можем описать различные свои методы которые будут доступны через созданный экземпляр. Передать element можно при помощи метода $get, который принимает имя атрибута id html элемета.
Global.widget = new MyNamespace.Widget($get("ID"));
Global.widget.initialize();
Самым большим плюсом я считаю метод get_element() класса Sys.UI.Control, он позволяет нам работать с нашим элементом как с отдельной сущностью:
initialize: function () {
var t = this;
...
$("label",t.get_element()).html("Hello word!");
}
Мы работаем не со всей DOM, а с ее небольшой частью, что влияет только положительно на скорость работы сайта.
В данной библиотеке есть еще один замечательный класс Sys.EventHandlerList, который можно использовать как хранилище для функций обратного вызова.
BaseControl = function (element) {
var t = this;
BaseControl.initializeBase(t, [element]);
t.handlers = new Sys.EventHandlerList();
};
BaseControl.prototype = {
initialize: function () {
var t = this;
BaseControl.callBaseMethod(t, "initialize");
},
dispose: function () {
var t = this;
t.handlers = null;
BaseControl.callBaseMethod(t, "dispose");
},
addEventHandler: function (name, h) {
var t = this;
t.handlers.addHandler(name, h);
},
removeEventHandler: function (name, h) {
var t = this;
if (t.handlers) {
t.handlers.removeHandler(name, h);
}
},
raiseEventHandler: function (name, args) {
var t = this;
var h = t.handlers.getHandler(name);
if (h) h(args);
}
};
BaseControl.registerClass("BaseControl", Sys.UI.Control);
Наследуясь от этого класса мы позволяем своему элементу сообщать всем подписчикам об изменении своего состояния. Подписчики вызывая метод addEventHandler подписываются на интересующее их событие, передавая его имя. Тут есть небольшие трудности, нельзя просто передать ссылку на метод, необходимо создать делегат используя Function.createDelegate и передавать его. Если этого не делать у нас все элементы данного класса получат сообщение об изменении состояния объекта, а мы не преследуем такой цели. И последнее, данные делегаты нужно удалять, или Вы будете наблюдать на своем сайте непонятное поведение элементов.
Используя данную библиотеку моей командой был реализован сайт с очень богатым функционалом, и мы получили очень приличные результаты.
Автор: al_x