Модульность в JavaScript

23 Сен
2011

Хочу поделиться своим опытом в написании модульного JS. Еще недавно обычно написаны скрипты выглядели аккуратно и упорядоченно, но сейчас в сравнение с модульным разбивкой по файлам это просто ужасно и очень неудобно. Постараюсь показать эту всю красоту на примере модуля «navigation» (AJAX навигация по сайту). Хочу также заметить, что это упрощенный, но не менее действенная система модулей которые уже когда-то предлагали на Блоге, чем и выгодна для применения даже в небольших проектах.

Код состоит из трех основных частей:

  • Ядро
  • Песочница
  • Модули

Чтобы уменьшить связь между объектами кода будем использовать асинхронную связь (для простоты будем пользоваться функциями jquery — bind и trigger).
Пишем ядро вместе с песочницей ( ‘/scripts/core/core.js’ )

Кусок кода для будущего унаследование псевдоклассов:
Function.prototype.extend = function (superClass) {
  var Inheritance = function () { };
  Inheritance.prototype = superClass.prototype;
  this.prototype = new Inheritance();
  this.prototype.constructor = this;
  this.superClass = superClass;
}

Далее основная функция js-приложения, где модули регистрируются:
window.App = function ( data ) {
  switch (data.header) {
    case "attach":
      var library = {
        name: data.body.name,
        body: new data.body.module()
      };
      window.module_list[ library.name ] = library;
      library.body.main( );
      break;
    case "destroy":
      break;
}

(потом сюда можно добавить динамическую загрузку модулей, их выгрузки и возможно еще что-то )
Теперь по песочнице:

она у нас играет роль соединений двух структур — ядра с модулем. И должен иметь такие методы как запрос переменной в ядра, запрос на выполнение какой то функции в другом модуле или ядре.
window.Sandbox = {
  get: function ( data ) {
    var responce = [];
    var w = window;
    var d = document;
    if (data)
      for (var i = 0; i-data.length<=0; i++) {
        try { var d = data[i].split("|")[0]; } catch(e) { var d = data[i]; }
        switch (d) {
          case "window.location.hash": responce.push( w.location.hash ); break;
          case "$": responce.push( $( '#' + data[i].split('|')[1] ) ); break;
        }
      }
    return responce;
  },
  call: function( data ) {
    var library = {
      f_name: data.body.f_name,
      params: data.body.params,
      sandbox: function( e ) { data.body.sandbox( e ); }
    };

    switch ( library.f_name ) {
      case ("search"):
        $( '#search_page #search_t' ).attr( 'value', library.params.q );
        $( window ).trigger({
          type: "search_request",        
          query: library.params.q
        });
        break;
    }
  }
}

Нужно также добавить кроме обычного способа еще асинхронный через hook-и на определенные event `s.
Ну и под конец инициализация:
window.Module = {
  init: function() {},
  render: function() {}
}

!function () {

  window.module_list = [];
  
  $( window ).bind('core_request', window.App );
  
  $( document ).ready( init );
  
  function init() {
     /* ... */
  }
  
} ();

Модуль ( '/scripts/modules/naviagation/mod.js' )

!function() {

// INIT and configure module and additional parts
  var current_hash = '';
  var location = '';
  
// RENDERING DOM of a page, when data is loaded (rebuilds the page)
  var render = function( result ) {
    if ( location===1 ) {
      $( '#content #bg1 #plus #page' ).animate({'opacity':'0'}, 300, function() {
        $( '#content' ).animate( {'height':'600px'}, 200 );
        $( '#content #bg1 #plus #page' ).html( result );
        $( '#content #bg1 #plus #page' ).animate({'opacity':'1'}, 300);
      });
    }
  }

// Library construction
  var Lib = function() {
    this.main = function( data ) {
      var interval = setInterval( this.poll, 200);
    },
    this.poll = function() {
      var hash = window.Sandbox.get( ['window.location.hash|'] )[0];
      var aj = { url: '', param: '' };
      if (current_hash!==hash) {        // compare last received location.HASH with new one
        aj.param = '';
        aj.url = '';
        switch (hash) {
           case '#!/sign_in':
            aj.param = '';
            aj.url = '/parts/login.php';
            break;
        }

        if ( aj.url ) {                           // if we need to get new data:
          $.ajax({                            // load new page PARTS from server
            type: "GET",
            url: aj.url,
            data: aj.param,
            success: render
          });
        }
      current_hash = hash;
    }
  }
  Lib.extend( window.Module );

// REGISTER this module in the CORE
  $( window ).trigger({
    type: "core_request",        
    header: "attach",
    body: {
      module: Lib,
      name: "navigation"
    }
  });

} ();

Так мы и завершили написание первого модуля. Просто и одновременно очень удобно!
По материалам Хабрахабр.



загрузка...

Комментарии:

Наверх