Ajax-навигация на сайте и решение задачи с переустановкой колбеков по URI. Класс x13AjaxNav

в 11:19, , рубрики: ajax, javascript, jquery, php, Песочница, метки: , ,

Здравствуй! Данная статья — презентация javascript-класса, к которому я пришел в результате перевода веб-сервисов на ajax-навигацию.

Что я имел перед началом работы

  1. веб-сервис на PHP-MVC-фреймворке с URI вида controller/method
  2. несколько неподходящих примеров ajax-навигации из гугла и хабра

Требования были такими

  1. минимальное взаимодействие с пространством имён
  2. минимальное взаимодействие с представлениями (view)
  3. автоматическая установка/восстановление по URI обработчиков событий, которые исчезают после перезаписи html на странице
  4. работа с URI вида любой_контроллер/конкретный_метод, напирмер «*/view»
  5. работа с URI вида конкретный_контроллер/любой_метод, напирмер «profile/*»
  6. работа с URI вида конкретный_контроллер/конкретный_метод, например «profile/edit»
  7. глобальная обработка на всех URI, фактически «*/*»
  8. возможность неиспользования ajax-навигации для некоторых ссылкок

Ближе к делу

Первое, что пришлось сделать — переписать выдачу в PHP-фреймворке в случае, если в метод пришел ajax-запрос. Было:

	public function method($id = 0)
	{
		//........
		$content = $this->load->view('dom/content', $data, true);
		$this->load->view('dom/carcass', $content);
	}

Стало:

	public function method($id = 0)
	{
		//........
		$content = $this->load->view('dom/content', $data, true);
		if ($this->_jetsAjaxNav($content, $data)) return true;
		$this->load->view('dom/carcass', $content);
	}

	protected function _letsAjaxNav($content, $data)
	{
		if (empty($this->isAjax)) return false;
		$response = (object)array();

		$response->content = $content;
		$response->controller = $this->router->controller;
		$response->method = $this->router->method;
		$response->title = $data->title;
		$response->destinationNode = 'body';

		$this->output->set(json_encode($response));
		return true;	
	}

Грабли и мысли, которые меня посетили во время разработки javascript-класса:

  1. Ссылки, которые необходимо обрабатывать лучше всего узнавать по наличию конкретного класса(у меня это класс ajaxNav), а не по отсутствию класса «ignoreAjax», как в некоторых примерах, которые мне не подошли. Объясняется это тем, что в противном случае придётся переписывать множество сторонних JS-UI модулей (например, KendoUI datepicker, JQuery UI datepicker)
  2. Вместо #хеш-навигации лучше использовать History API, а в браузерах, которые не поддерживают его лучше ничего не использовать. Оставил это на плечах программиста, который будет использовать класс
  3. Как всегда, "обрадовал" контуженный хром: в отличии от других браузеров он зачем-то дважды обрабатывал popstate, в результате чего при первой загрузке страницы на сервер уходило сразу два идентичных запроса — пришлось писать костыль
  4. Нужен колбек для визуализации отправки запроса после клика по ссылке, и соответстующий колбек для скрытия/отмены визуализации запроса при окончании обработки. Сказано — сделано
  5. Нужна прослойка в методе обработки пришедших данных. Ок
  6. Нужно предусмотреть выход из обработки, если ссылка внешняя

Что из этого вышло или лучше так:

hg clone https://code.google.com/p/x13ajax-nav-js/

Как использовать

Требования:

  1. наличие jQuery
  2. Требуется чтобы ajax-ответ с сервера являлся JSON-объектом со следующими полями:
    • controller — имя контроллера
    • method — имя метода
    • content — контент для страницы
    • [title] — опциональное поле, title для страницы
    • [destinationNode] — опциональное поле, определяющее целевой html-элемент

  3. параметр инициализации params — объект для хранения служебной информации. должен содержать поля:
    • base_url — корневой URL сайта, например «http://example.com/»
    • controller текущий открытый контроллер, например «profile»
    • method — текущий открытый метод контроллера, например «view»

Так же ссылки для ajax-навигации должны иметь класс ajaxNav или возможен альтернативный вариант — первый родитель ссылки должен иметь класс ajaxNav, например:

<div class="pagination ajaxNav">
<a href="url">1</a>
<a href="url">2</a>
<a href="url">3</a>
<a href="url">3</a>
</div>

Запуск конструктора с передачей в него объекта window (так уж получилось, но именно так использовать совсем не обязательно)
и объекта jQuery (реализовано для избежания вероятных конфликтов в пространстве имён)

$$$ = new $$$(window, $);

Устанавливаем прослойку для изменения дополнительных служебных данных и описания (на случай взаимодействия с поисковиками):

$$$.$.processAjaxResponseInterlayer = function (d)
{
	if (typeof d.hashId != 'undefined')
		this.params.hashId = d.hashId;

	if (typeof d.userId != 'undefined')
		this.params.userId = d.userId;

	if (typeof d.description != 'undefined')
		this.jQuery('#description').attr('content', d.description);

};

Устанавливаем визуальные эффекты:

$$$.$.navEffect = function ()
{
	this.jQuery('html').css('box-shadow', 'inset 0px 0px 10px 10px rgba(0, 0, 150, 0.2)');
	this.jQuery('a').css({'cursor': 'wait'});
};

$$$.$.navDisEffect = function ()
{
	this.jQuery('a').css({'cursor': 'pointer'});
	this.jQuery('html').css('box-shadow', '');
}

Во всех методах+контроллерах превращаем все формы в ajax-формы:

$$$('*', letsAjaxAllForms);
function letsAjaxAllForms()
{
	//.....
}

Запускаем инициализацию лайтбокса для просмотра фото во всех методах просмотра:

$$$('/view', initLightBox);
function initLightBox()
{
	//.....
}

Запускаем инициализацию валидатора форм во всех методах редактирования:

$$$('/edit', initValidation);
function initValidation()
{
	//.....
}

В контроллере профиля во всех методах инициализируем мессенджер:

$$$('profile/', initIM);
function initIM()
{
	//.....
}

Надеюсь, данный класс обретёт жизнь и в ваших проектах. Спасибо за внимание, алоха!

Автор: frostosx

Источник

  1. женя:

    хороший урок ,правда что-то не получается … вы не можете помочь и скинуть готовый вариант в zip или в другом архиве , заранее спасибо=)

* - обязательные к заполнению поля


https://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js