AJAX и история или одна из идей как упростить себе труд

1
  • написал: MpaK
  • 293
В целом об AJAX написано много. Море фреймворков, библиотек, учебников, уроков вокруг облегчающих работу с этой технологией. Но всегда хочется сделать еще проще, еще удобнее и иногда быстрее чем у других и возможно погоня за оригинальностью. Не скажу, что всё это про мой пост, просто пришла идея и захотелось реализовать.

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

В целом — идея.
Меня постоянно убивало, что нужно писать много кода, куда и что запрашивать AJAX и при этом делать несколько версий. В момент работы с Prototype был написан один большой объект, где просто назначались действия, какую ссылку запросить, куда засунуть, какое сообщение показать. Но время движется и хочется не таскать для простых казалось таскать столь громадные махины как Prototype, я перешел на JQuery. Конечно и вторая причина перехода, это обилие плагинов сыграло роль.
JQuery код упрощает, хотя и меняет логику привычную с Prototype.
Но код всё же опять пухнет, смешивается в кучу JavaScript и HTML, вставки кругом, поддержка работы без JavaScript (например для поисковиков) — всё это заставляет мешать и мешать код. Мне это не нравится.

В какой-то момент меня посещает идея, что все ссылки которые будут например работать в двух версиях, как переход например на страницу 1.html и как вторая версия это загрузка этой самой 1.html страницы в поле #content, можно легко пометить классом, уникальным id и для удобства назначения запроса AJAX мы можем втюхать его в атрибут rel:

<a href="1.html" id="link1" class="ajax" rel="1-ajax.php">Наша ссылка</a>

То есть мы просто при загрузке нашей страницы вставим свой обработчик нажатия на каждую такую ссылку и можем с легкостью доставать адреса запросов и творить с ними удобные штуки.

Встал второй вопрос, история. Как все понимают AJAX никак не отражается на нашей адресной строке и истории браузера — они вообще не изменяются! Но как уже вошло в практику мы можем использовать якора (anchor). Да эти самые простые штучки #link1 будут нашими путеводителями, подумал я! Как раз по якорю как id элемента мы начнем определять есть ли ссылка и указан у неё ли rel с адресом запроса. Можно пойти конечно дальше, если захотите например засовывать в rel некий json текст с указаниями например div#id куда будет результат попадать или эффекты какие, но это уже расширение.

Ну в целом, вот пример, смотрите mrak7.com/ex/dax/
Сразу можете открыть код и сравнить например ссылку 1 и 2 в реализации :) Обе работают, кнопка браузера работает так же :) Проверял разумеется пока только в FireFox 3.6 и Chrome 4, остальные не знаю, пока для примера идеи считаю не важно.

На всякий случай копирую код сюда:


	(function($) {
		function DAX(){
			// наш мега объект
			this.anchor = '';
			this.initialize();
		};

		$.extend(
			DAX.prototype, {
				// типа конструктор
				initialize: function() {
					// проходим по всем ссылкам с классом AJAX и ставим наш обработчик
					$("a.ajax").bind("click", function(e){
						// обработчик, достаем у ссылки его id и засовываем в uri якорем
						// чтобы "временной" обработчик потом схавал его и увидел изменения
						var id = $(this).attr('id');
						document.location.hash = '#'+id;
						return false;
				    });
					// запустим наш временной обработчик с интервалом
					setInterval(this.check, 100);
				},

				// наш триггер по времени
				check: function() {
					// достанем якорь из uri
					var hash = document.location.hash;
					hash = hash.replace(/^#/, '');

					// изменился ли он, не пустой и не ноль?
					if( (hash != $.DAX.anchor) && (hash!='') && (hash!=null) ){
						// если так, то попробуем поискать rel у возможной ссылки
						var url = $('#'+hash).attr('rel');
						if( url ){
							/*
							если есть rel с адресом, то попробуем запросить его
							и т.п. тут уже от разработчика
							*/
							$.ajax({
								type: 'POST',
								url: url,
								success: function(text){
									$('#content').html(text);
									$.DAX.anchor = hash;
								}
							});
						}
					}

				}
		});

		$(document).ready(function() { $.DAX = new DAX();  }); // Создаем наш объект, синглетон

	})(jQuery);



И разумеется ссылка на скачивание всего кода .rar 1.5 Kb

P.S. Метод у объекта DAX можно даже убрать или сократить, без bind'а так сказать
  • +2

9 комментариев

avatar
  • akhmetov
  • 0
avatar
  • MpaK
  • 0
Почитал, ничего нового и интересного по данной теме нету.

Как принцип hijak соблюден.

Одно только, что я определение делаю так на сервере, а не как тот автор.

model: Request.php

if( $_SERVER['HTTP_X_REQUESTED_WITH'] == 'XMLHttpRequest') $this->ajax = TRUE;

avatar
  • xxen
  • 0
можно вообще обойтись без атрибута rel, а спрашивать ajax у того же адреса, что указан в href. Просто узнавать на сервере ajax это или обычный запрос.

ps: в Yii например это можно узнать из переменной Yii::app()->request->isAjaxRequest
avatar
  • MpaK
  • 0
В каком-то простейшем случае конечно можно, так как всё же суть темы не та, но отвлекусь и объясню почему.

В простейшем случае конечно у тебя один запрос — один ответ модуля, как YII сработает MVC, определяем запрос был из аякса и отдаем разные контенты. Кстати выше комментом написал как раз как определяю лично я, а не механизм YII :)

Но в случае некой системы, запрос к странице /news/ к примеру будет запускать кучу модулей установленных на оной (например: меню, новости 4х категорий, контакты и т.п.), что нам разумеется не надо. Конечно мы можем узнать как нас вызвали, но всё равно надо же нам какой-то один модуль например новости раздела политика. К тому и rel например я указал в примере своего поста. Разумеется можно поставить проверку на пустоту и использовать href, но цель всё же была объяснить другую идею :)
avatar
  • xxen
  • 0
какую еще кучу модулей7. Модули(виджеты) вызываются в шаблоне. В нормальных MVC фреймворках можно отдавать вьюшку в чистом виде(без шаблона).
avatar
  • MpaK
  • 0
Это MVC в чистом виде, когда нет модулей, а виджеты (или еще любят называть их компонентами) это так сказать блоки.

Я имею в виду про модульную систему, например CMS когда не как MVC работаем, а как страница ядра, а потом куча модулей. В CodeIgniter этому есть расширение HMVC. Но думаю подробнее расскажу попоже как буду презентовать нашу систему, она как раз на базе CI и модульная до косточек.
avatar
  • daken
  • 0
у меня js-код пробегается по всем ссылкам и перебивает те, которые ведут на этот же домен на аякс-запросы.
в качестве возврата идет json, где есть
preJs — javascript код, его выполнить перед трансформацией шаблонов и вставки контента в нужные места
postJs — то же самое, только в конце
content — ассоциативный массив, где ключ — jQuery селектор, куда надо засунуть контент, который лежит в значении
transform — массив, каждый элемент которого содержит название шаблона, данные и то, куда засунуть результат. для трансформации юзаю jTemplates, но там есть 1 минус — нет поддержки рекурсии, так что многоуровневые меню через него хз как сделать.
errors — ошибки, которые надо сообщить юзеру, используется для отладки.

пхп-скрипт при любом обращении генерит такой массив, просто если запрос был через аякс — выкидывает результат через json_encode, иначе рендерит в хтмл. при желании тут хоть генерацию пдф на лету можно прикрутить)
avatar
  • MpaK
  • 0
Мысли сходят, у меня тоже такой же код был, вот старая версия на Prototype объект:


DC.AJAX = {
	// When load begin
	ajaxLoad: function( divID ){
		if(divID){ this.toggleRollDiv(divID); }
		$('ajaxprogress').show();
	},
    // When complete
	ajaxSuccess: function ( divID ){
		$('ajaxprogress').hide();
		if(divID){ new Effect.BlindDown(divID, { duration: 0.5 });}
	},

	// Get query, analize and do what need
	get: function( url, divID, form, dont_serialize ){
    	if(!url) return;
    	if(form) {
    		if( !(dont_serialize) ){
	    		form = $(form).serialize();
	   		}
    	}else{
    		form = '';
    	}
		new Ajax.Request(url, {
			method: 'POST',
			parameters: form,

			onLoading:function(request){ DC.AJAX.ajaxLoad(); },
			onComplete:function(request){ DC.AJAX.ajaxSuccess(); },

			onSuccess: function(transport) {
				res = transport.responseText;
				// if JSON
				if( res.isJSON() ){
					res = res.evalJSON(true);
					// error
					if(res.error){
						DC.message( 'error', res.error );
					}
					// msg
					if(res.msg){
						DC.message( 'ok', res.msg );
					}
         			// if have id_text and text go and update it!
	           		if( (res.id_text) && (res.text) ){
            			$(res.id_text).update( res.text );
            		}
         			// if have id_append and text go and APPEND it!
            		if( (res.id_append) && (res.append) ){
            			$(res.id_append).insert( {bottom: res.append} );
            		}
            		//# todo:
         			// if have id_top and text go and REPLACE it!
            		if( (res.id_replace) && (res.replace) ){
            			$(res.id_replace).insert( res.replace );
            		}

					// if some need code to evaluate
         			if(res.eval){
         				eval( res.eval );
         			}
				}else{
				// else only update if have container
                	if(divID) $(divID).update( res );
				}
			}
		}
		);
	}
}


Хотя статью писал не о том, АЯКС тут как пример, я о кнопку BACK браузера, о том как html код сам начинает решать как что и варианты использования слежения за location.hash
avatar
  • eye-ru
  • 0
Хорошая тема. У меня она станет актуальной в ближайшее время в проекте на ASP.NET MVC + jQuery.
Только зарегистрированные и авторизованные пользователи могут оставлять комментарии.