С недавних пор я стал работать в сфере web разработки, и еще нахожусь в стадии падавана. Однако недавно я открыл для себя способ организации клиентского javascript кода, который может быть легко интегрирован в любой существующий проект и который легко освоить.
Этот подход называют «Модульный javascript», и под катом мы научимся его применять.
Статья названа так, потому что люди на уровне джедая уже используют более совершенные методики и думаю в комментариях поделятся ими.
Задачу я ставил себе следующую:
«Организовать весь клиентский js код удобным способом, что бы его было легко поддерживать, искать ошибки и дополнять».
Мотивацией этому стала работа с чужим сайтом, где весь js был в одном, огромном файле и попытка дополнить что-то вызывала приступ апатии.
Вся суть методики сводится к разбиению нашего приложения на модули. Я так же называю их «виджетами», потому что так проще воспринимать их суть.
Каждый виджет является обособленной сущностью. Он не знает о других виджетах и не обращается к ним на прямую. Виджет может работать только сам с собой и генерировать события, на которые могут подписываться другие виджеты.
Схематически виджет — это некая часть нашего сайта, у которой есть специфическая функциональность.
Наш тестовый сайт мы можем мысленно разбить на 3 виджета.
1. Глобальный модуль — будет отвечать за инициализацию других модулей.
2. Профиль — отобразит аватарку пользователя (привет Ричард :) ), и меню с направлениями деятельности.
3. Портфолио — отобразит примеры работ по выбранному направлению у этого юзера
А теперь создадим наши модули.
Каждый модуль будет находится в отдельном js файле.
Html разметку и CSS стили мы рассматривать не будем. Отмечу лишь, что для отображения я обычно использую шаблонизатор входящий в состав underscore.js. А стили, в основном, используются из основного css файла.
Например мы захотим добавить новый модуль, который что то делает после того, как пользователь выбрал пункт в профиле. Нам достаточно подписать этот модуль на событие 'clickItem' и выполнить нужные действия.
Мы хотим добавить всплывающее окно, появляющееся при клике на работе в портфолио? Не вопрос. В методе event модуля Portfolio добавим нечто вроде
Теперь нам нужно подписать модуль, генерирующий всплывающие окна, по всему нашему приложению — на событие 'showModal' и все.
Надеюсь этот материал будет вам полезен.
По теме так же советую почитать largescalejs.ru.
Для загрузки файлов с модулями я использую yepnope.js.
Спасибо за внимание.
Этот подход называют «Модульный javascript», и под катом мы научимся его применять.
Статья названа так, потому что люди на уровне джедая уже используют более совершенные методики и думаю в комментариях поделятся ими.
Задачу я ставил себе следующую:
«Организовать весь клиентский js код удобным способом, что бы его было легко поддерживать, искать ошибки и дополнять».
Мотивацией этому стала работа с чужим сайтом, где весь js был в одном, огромном файле и попытка дополнить что-то вызывала приступ апатии.
Вся суть методики сводится к разбиению нашего приложения на модули. Я так же называю их «виджетами», потому что так проще воспринимать их суть.
Каждый виджет является обособленной сущностью. Он не знает о других виджетах и не обращается к ним на прямую. Виджет может работать только сам с собой и генерировать события, на которые могут подписываться другие виджеты.
Схематически виджет — это некая часть нашего сайта, у которой есть специфическая функциональность.
Наш тестовый сайт мы можем мысленно разбить на 3 виджета.
1. Глобальный модуль — будет отвечать за инициализацию других модулей.
2. Профиль — отобразит аватарку пользователя (привет Ричард :) ), и меню с направлениями деятельности.
3. Портфолио — отобразит примеры работ по выбранному направлению у этого юзера
А теперь создадим наши модули.
Каждый модуль будет находится в отдельном js файле.
Html разметку и CSS стили мы рассматривать не будем. Отмечу лишь, что для отображения я обычно использую шаблонизатор входящий в состав underscore.js. А стили, в основном, используются из основного css файла.
Глобальный модуль App.js
// Модуль представляет из себя переменную, которой присвоено значение самовызывающейся анонимной функции
// Функция возвращает объект, предоставляющий публичный API для работы с модулем
var App = (function(){
//Тут можно определить приватные переменные и методы
//Например
var someArray = []; //Не будет доступен по ссылке App.someArray, не как либо еще вне объекта
//Объект, содержащий публичное API
return {
init: function(){
// Инициализация модуля. В ней мы инициализируем все остальные модули на странице
Profile.init();
Portfolio.init();
}
}
})();
//И инициализируем наш глобальный модуль
App.init();
Модуль профиля Profile.js
var Profile = (function(){
//Приватная переменная хранящая путь до сервера, предоставляющего информацию для модуля
var url = 'http://someweb.com';
//Приватная переменная хранящая корневой html элемент, в котором отрисовывается модуль
var el = '.div-profile';
return {
//Инициализация модуля
init: function(){
// Получим список пунктов меню и аватарку с сервера
var profileData = this.getData(url);
},
getData: function(url){
/*
* Тут будет код ajax запроса на сервер, который в случае успеха сохранит результат в переменную res
*/
//Отрисуем наши данные
this.render(res);
},
render: function(){
/*
* Тут будет код создания html разметки, с использованием вашего любимого шаблонизатора.
* Допустим результирующая строка будет сохранена в переменную html
*/
//Добавим полученную разметку в корневой элемент модуля.
//Для простоты представим что на проекте используется jQuery
$(el).html(html);
//И привяжем DOM события к нужным элементам модуля
this.event();
},
event: function(){
//Пусть пункты меню имеют класс .menu-item
//И содержат атрибут data-list-id
$('.menu-item').click(function(){
var id = $(this).data('list-id');
//Теперь самое важное. Генерируем событие, что пользователь кликнул пункт.
//На это событие и будут подписываться другие модули
//В триггере передадим id выбранного пункта
$(window).trigger('clickItem', {id: id});
});
}
}
})();
Модуль портфолио Portfolio.js
var Portfolio = (function(){
//Ссылка на текущий объект
$this = this;
var el = '.portfolio'
return {
init: function(){
//Повесим слушатель нашего кастомного события. В функцию обработчик передадим пришедшие данные
$(window).on('clickItem', function(e, data){
$this.getData(data.id)
});
},
getData: function(id){
/*
* Тут сделаем запрос на сервер и получим наши работы в портфолио. Пусть они так же сохраняются в res
*/
this.render(res);
},
render: function(data){
/*
* И снова отрисовываем данные удобным вам способом
*/
},
event: function(){
/*
* Навесим нужные события
*/
}
}
})();
Что это нам дает
- Код разделен по файлам. Легко найти нужное место для изменения
- Модули общаются посредством событий. Можно удалять или заменять модули другими, не трогая код остальных частей приложения
- Процесс внесения новых фич стал более удобным
Например мы захотим добавить новый модуль, который что то делает после того, как пользователь выбрал пункт в профиле. Нам достаточно подписать этот модуль на событие 'clickItem' и выполнить нужные действия.
Мы хотим добавить всплывающее окно, появляющееся при клике на работе в портфолио? Не вопрос. В методе event модуля Portfolio добавим нечто вроде
//'.portfolio-item' - класс-обертка, для каждой работы
$('.portfolio-item').click(function(){
$(window).trigger('showModal');
});
Теперь нам нужно подписать модуль, генерирующий всплывающие окна, по всему нашему приложению — на событие 'showModal' и все.
Надеюсь этот материал будет вам полезен.
По теме так же советую почитать largescalejs.ru.
Для загрузки файлов с модулями я использую yepnope.js.
Спасибо за внимание.