Здравствуй! Данная статья — презентация javascript-класса, к которому я пришел в результате перевода веб-сервисов на ajax-навигацию.
Что я имел перед началом работы
- веб-сервис на PHP-MVC-фреймворке с URI вида controller/method
- несколько неподходящих примеров ajax-навигации из гугла и хабра
Требования были такими
- минимальное взаимодействие с пространством имён
- минимальное взаимодействие с представлениями (view)
- автоматическая установка/восстановление по URI обработчиков событий, которые исчезают после перезаписи html на странице
- работа с URI вида любой_контроллер/конкретный_метод, напирмер «*/view»
- работа с URI вида конкретный_контроллер/любой_метод, напирмер «profile/*»
- работа с URI вида конкретный_контроллер/конкретный_метод, например «profile/edit»
- глобальная обработка на всех URI, фактически «*/*»
- возможность неиспользования 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-класса:
- Ссылки, которые необходимо обрабатывать лучше всего узнавать по наличию конкретного класса(у меня это класс ajaxNav), а не по отсутствию класса «ignoreAjax», как в некоторых примерах, которые мне не подошли. Объясняется это тем, что в противном случае придётся переписывать множество сторонних JS-UI модулей (например, KendoUI datepicker, JQuery UI datepicker)
- Вместо #хеш-навигации лучше использовать History API, а в браузерах, которые не поддерживают его лучше ничего не использовать. Оставил это на плечах программиста, который будет использовать класс
- Как всегда, "обрадовал"
контуженныйхром: в отличии отдругихбраузеров он зачем-то дважды обрабатывал popstate, в результате чего при первой загрузке страницы на сервер уходило сразу два идентичных запроса — пришлось писать костыль - Нужен колбек для визуализации отправки запроса после клика по ссылке, и соответстующий колбек для скрытия/отмены визуализации запроса при окончании обработки. Сказано — сделано
- Нужна прослойка в методе обработки пришедших данных. Ок
- Нужно предусмотреть выход из обработки, если ссылка внешняя
Что из этого вышло или лучше так:
hg clone https://code.google.com/p/x13ajax-nav-js/
Как использовать
Требования:
- наличие jQuery
- Требуется чтобы ajax-ответ с сервера являлся JSON-объектом со следующими полями:
- controller — имя контроллера
- method — имя метода
- content — контент для страницы
- [title] — опциональное поле, title для страницы
- [destinationNode] — опциональное поле, определяющее целевой html-элемент
- параметр инициализации 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
хороший урок ,правда что-то не получается … вы не можете помочь и скинуть готовый вариант в zip или в другом архиве , заранее спасибо=)