С недавних пор я стал работать в сфере web разработки, и еще нахожусь в стадии падавана. Однако недавно я открыл для себя способ организации клиентского javascript кода, который может быть легко интегрирован в любой существующий проект и который легко освоить.
Этот подход называют «Модульный 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.
Спасибо за внимание.
ссылка на оригинал статьи http://habrahabr.ru/post/218485/
Добавить комментарий