Javascript →
Модульность в JavaScript
Хочу поделиться своим опытом в написании модульного JS. Еще недавно обычно написаны скрипты выглядели аккуратно и упорядоченно, но сейчас в сравнение с модульным разбивкой по файлам это просто ужасно и очень неудобно. Постараюсь показать эту всю красоту на примере модуля «navigation» (AJAX навигация по сайту). Хочу также заметить, что это упрощеная, но не менее действенная система модулей которые уже когда-то предлагали на Хабре, чем и выгодна для применения даже в небольших проектах.
Чтобы уменьшить связь между объектами кода будем использовать асинхронную связь (для простоты будем пользоваться функциями jquery — bind и trigger).
Кусок кода для будущего унаследование псевдоклассов:
Далее основная функция js-приложения, где модули регистрируются:
(потом сюда можно добавить динамическую загрузку модулей, их выгрузки и возможно еще что-то )
она у нас играет роль соединений двух структур — ядра с модулем. И должен иметь такие методы как запрос переменной в ядра, запрос на выполнение какой то функции в другом модуле или ядре.
Нужно также добавить кроме обычного способа еще асинхронный через hook-и на определенные event `s.
Ну и под конец инициализация:
Так мы и завершили написание первого модуля. Просто и одновременно очень удобно!
Код состоит из трех основных частей:
- Ядро
- Песочница
- Модули
Чтобы уменьшить связь между объектами кода будем использовать асинхронную связь (для простоты будем пользоваться функциями 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;
}
* This source code was highlighted with Source Code Highlighter.
Далее основная функция 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;
}
* This source code was highlighted with Source Code Highlighter.
(потом сюда можно добавить динамическую загрузку модулей, их выгрузки и возможно еще что-то )
Теперь по песочнице:
она у нас играет роль соединений двух структур — ядра с модулем. И должен иметь такие методы как запрос переменной в ядра, запрос на выполнение какой то функции в другом модуле или ядре.
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;
}
}
}
* This source code was highlighted with Source Code Highlighter.
Нужно также добавить кроме обычного способа еще асинхронный через hook-и на определенные event `s.
Ну и под конец инициализация:
window.Module = {
init: function() {},
render: function() {}
}
!function () {
window.module_list = [];
$( window ).bind('core_request', window.App );
$( document ).ready( init );
function init() {
/* ... */
}
} ();
* This source code was highlighted with Source Code Highlighter.
Модуль ( '/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"
}
});
} ();
* This source code was highlighted with Source Code Highlighter.
Так мы и завершили написание первого модуля. Просто и одновременно очень удобно!
23.09.2011 01:15+0400