Организация js кода для джуниоров

от автора


С недавних пор я стал работать в сфере web разработки, и еще нахожусь в стадии падавана. Однако недавно я открыл для себя способ организации клиентского javascript кода, который может быть легко интегрирован в любой существующий проект и который легко освоить.

Этот подход называют «Модульный javascript», и под катом мы научимся его применять.

image

Статья названа так, потому что люди на уровне джедая уже используют более совершенные методики и думаю в комментариях поделятся ими.

Задачу я ставил себе следующую:
«Организовать весь клиентский js код удобным способом, что бы его было легко поддерживать, искать ошибки и дополнять».

Мотивацией этому стала работа с чужим сайтом, где весь js был в одном, огромном файле и попытка дополнить что-то вызывала приступ апатии.

Вся суть методики сводится к разбиению нашего приложения на модули. Я так же называю их «виджетами», потому что так проще воспринимать их суть.

Каждый виджет является обособленной сущностью. Он не знает о других виджетах и не обращается к ним на прямую. Виджет может работать только сам с собой и генерировать события, на которые могут подписываться другие виджеты.

Схематически виджет — это некая часть нашего сайта, у которой есть специфическая функциональность.

image

Наш тестовый сайт мы можем мысленно разбить на 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/


Комментарии

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *