Model-View-Controller для JavaScript

Приветствую Вас дорогие читатели! Для тех из вас, кто знаком с RubyOnRail, CodeIgniter, CakePHP, парадигма Model, View, Controller не является новинкой. Шаблон MVC позволяет разделить данные, представление и обработку действий пользователя на три отдельных компонента: модель (Model) для предоставления данных, представление (View) для отображения информации и контроллер (Controller) для интерпретации данных, введенных пользователем.

Если для таких языков программирования, как PHP, Ruby, Python, существует множество фреймворков, использующих MVC, то для JavaScript это пока диковинка. Совсем недавно появился именно такой фреймворк для JavaScript - JavaScriptMVC

JavascriptMVC

Разработка фреймворка пока еще в стадии “альфа”, но тем не менее, он уже сейчас обладает внушительными возможностями. Есть большой набор дополнительных плагинов для использования AJAX, тестирования, добавления объекта History, работы с массивами, строками и много другое. Также, что немаловажно, возможно использование JavascriptMVC с другими библиотеками - jQuery, Prototype и др.

Я решил попробовать библиотеку в действии и создать простое приложение. Вот что у меня получилось: demo.

Теперь шаг за шагом о том, как я сделал его.

Шаг 1: установка

Скачайте дистрибутив и распакуйте его локально или на веб сервер.

Шаг 2: HTML

Создадим пустой HTML документ, в который добавим скрипт include.js с двумя параметрами - именем приложения и параметром, определяющим режим разработки: development, production, test, compress. Тип development удобен при разработке и отладке приложения, test при тестировании (автоматически появится pop-up окно с тестами), compress автоматически сожмет все скрипты, production - режим “готового” приложения.

  1. <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
  2. <html lang="en">
  3.   <head></head>
  4.   <body>
  5.      <script type='text/javascript' src='jmvc/include.js?helloworld,development'></script>
  6.   </body>
  7. </html>


Шаг 3: создание приложения.

В параметре include.js мы указали название приложения - helloworld. Это значит, что скрипт include будет искать файл приложения helloworld.js в папке apps. Создадим его, и добавим туда несколько строк:

  1. // подключаем плагины view и controller
  2. include.plugins('controller');
  3. include.plugins('view');
  4. include.plugins('model');

  5. // подключаем контроллеры
  6. include.controllers('main');
  7. include.controllers('hello');
  8. include.models('hello');

Здесь мы подключаем плагины view, controller и model, а затем подключаем контроллеры main и hello, которые будут управлять всеми событиями на странице. Контроллер main (MainController) - это специальный тип контроллера, который позволяет добавлять обработчики событий к объектам window и document. В последней строке мы добавляем модель hello, которая нужна для получения данных от сервера.


Шаг 4: Создание контроллеров.

Контроллеры создаем в папке controllers, обязательно указывая для них постфикс _controllers.js. В файл main_controller.js пишем следующее:

  1. Controller('main',{
  2.  // обработчик события onload для объекта window
  3.  load: function(){

  4.        var data = {
  5.                header : new View({url: 'header.ejs'}).render({title:'My MVC page'}),
  6.                footer : new View({url: 'footer.ejs'}).render({copyright:'Some rights reserved. My copyright notice'}),
  7.                sidebar : new View({url: 'sidebar.ejs'}).render({aList : [{linkTitle:'Link1',linkHref:'#1'}, {linkTitle:'Link2',linkHref:'#2'}, {linkTitle:'Link3',linkHref:'#3'}]})
  8.        }
  9.        document.body.innerHTML = new View({url: 'layout.ejs'}).render(data);
  10.  }
  11. });

Здесь мы инициализируем новый контроллер и функцию load, которая будет выполняться при загрузке страницы. В файл hello_controller.js пишем следующее:

  1. Controller('links',{
  2.  // обработчик события onclick для элементов с атрибутом class="link"
  3.  click: function(params){
  4.          var href = params.element.getAttribute('href');
  5.          var id = href.replace(/^.*#/,'');
  6.          Hello.find(id, null, find_callback);
  7.          params.event.preventDefault();
  8.  }
  9. });

  10. // обрабатываем полученный от сервера результат
  11. function find_callback(post){
  12.        var elem = document.getElementById("content");
  13.        elem.innerHTML = '<h2>' + post.postTitle + '</h2>';
  14.        elem.innerHTML += '<p>' + post.postBody + '</p>';
  15. }

В этом контроллере функция click будет выполняться для элементов с атрибутом class=”link”. Здесь следует упомянуть о правилах именования элементов, определяющих порядок присвоения контроллеров к элементам HTML:

  1. Если имя контроллера в множественном числе (множественное число в английском языке обозначается суффиксом -s в конце), например ‘employees’, то он соответствует всем элементам с именем класса в единственном числе, т.е. ‘employee’.
  2. Если имя контроллера в единственном числе, например ‘item’, то он соответствует элементам с ID, равным имени контроллера, т.е. ‘item’.

Что касается аргумента params, то это объект, который включает в себя переменные event (объект “событие”), element (ссылка на элемент, который вызвал событие) и action (например “click” - тип события). Далее я использую функцию preventDefault() объект event чтобы предотвратить действие ссылки по умолчанию (объект event кроссбраузерный, поэтому это будет работать и в IE).


Шаг 5: создание шаблонов (View)

Шаблоны подключаются примерно следующим образом:

  1. var myView = new View({url: 'file_name.ejs'});

Здесь параметр url указывает имя файла шаблона, который должен находиться в папке view. Для отображения шаблона (или обработки его содержимого) используется функция render(), в которую нужно передать объект с переменными шаблона. Пример:

  1. var myView = new View({url: 'file_name.ejs'});
  2. var someHTML = myView.render( { 'name' : 'value', 'nick' : 'dima' } );

В нашем примере я подключил черыре разных шаблона в контроллер main:

  1.        var data = {
  2.                header : new View({url: 'header.ejs'}).render({title:'My MVC page'}),
  3.                footer : new View({url: 'footer.ejs'}).render({copyright:'Some rights reserved. My copyright notice'}),
  4.                sidebar : new View({url: 'sidebar.ejs'}).render({aList : [{linkTitle:'Link1',linkHref:'#1'}, {linkTitle:'Link2',linkHref:'#2'}, {linkTitle:'Link3',linkHref:'#3'}]})
  5.        }
  6.        document.body.innerHTML = new View({url: 'layout.ejs'}).render(data);

Самый главный шаблон здесь - layout.ejs, который определяет основную структуру документа, содержимое остальных трех передается в layout.ejs в качестве переменных шаблона. Содержимое этого шаблона запишем следующим образом:

  1. <%= header %>

  2. <div id="page">
  3.        <%= sidebar %>
  4.        <div id="content">
  5.        <h4>Page content</h4>
  6.        <p>Some text</p>
  7.        </div>
  8.        <div class="clr"></div>
  9. </div>

  10. <%= footer %>

Как видите это просто HTML с добавлением переменных шаблона в тэгах <%= … %>. Если у нас в шаблоне, к примеру есть переменная <%= header %>, а в функцию render() был передан объект data, то переменная шаблона header будет заменена на содержимое переменной data.header.

Теперь создаем остальные шаблоны.

header.ejs - “шапка” страницы:

  1. <div id="header">
  2.        <h4 id="hello"><%= title %></h4>
  3. </div>

sidebar.ejs - сайдбар:

  1. <div id="sidebar">
  2. <ul>
  3.    <% for(var i=0; i<aList.length; i++) { %>
  4.        <li>
  5.            <a href='<%= aList[i].linkHref %>' class="link">
  6.                <%= aList[i].linkTitle %>
  7.            </a>
  8.        </li>
  9.    <% } %>
  10. </ul>
  11. </div>

В этом шаблоне помимо обычных тэгов, используются тэги без знака “равно” <% … %>. Они не возвращают результат, а их содержимое просто выполняется интерпретатором. Я использую их здесь для организации цикла.

footer.ejs - “подвал” страницы:

  1. <div id="footer"><%= copyright %></div>

  2. </body>
  3. </html>


Шаг 6: создание моделей (Model)

В серверных приложениях MVC, таких как Ruby On Rails, Codeigniter и др., модели выполняют роль связующего звена между контроллерами и базой данных. В JavascriptMVC для этой цели используются асинхронные запросы к серверу при помощи библиотеки Jester, которая имитирует ActiveResource в приложениях Rails.

  1. Model('hello', {
  2.        format: 'json',
  3.        prefix: 'jmvc/resource',
  4.        urls : { list: "/get.php", show: "/get.php?id=:id", create: "/create.php", update: "/update.php?id=:id" }
  5. },
  6.  null,
  7.  null
  8. );

Здесь мы просто создаем объект класса Model. Для его создания я использовал только два параметра - имя модели и опции. В опциях указаны формат сообщений (json или xml), prefix - путь к файлам обработчикам (в данном примере путь будет /jmvc/resource) и urls - файлы, которые будут возвращать результат при выборке данных (get.php) создании (create.php) и обновлении (update.php).

Для работы с данными в классе Model есть функции find() для выборки данных, create() - для добавления данных в БД, update() для обновления данных в БД и прочее.

В данном примере я использую только функцию find() для получения записи (смотрите выше в контроллере links).

  1. Hello.find(id, null, find_callback);

Здесь id - это параметр, который будет подставлен в URL (выше мы указали для запроса show: “get.php?id=:id”, т.е. если id=3, то получим запрос get.php?id=3). Последний параметр это callback для обработки полученных результатов.

На этом всё. Смотрите демо, если нужно скачивайте пример. Только устанавливать надо на веб сервер чтобы увидеть в работе работу модели.

До встречи!


Автор: http://www.jstoolbox.com/



Опубликовал admin
2 Июн, Понедельник 2008г.



Программирование для чайников.