В начале
В данной статье речь пойдет о написании Ajax-приложения. Если говорить проще — то, о написании сайта – работающего без перезагрузок. Быстро, легко, доступно. В этой статье не будет рассматриваться код серверной стороны, будут только примеры, для лучшего понимания.
Меня давно интриговала тема написания сайта, в котором несколько компонентов (например, flash плееры) не перезагружаются с каждым переходом по ссылкам, а продолжают себе напевать песенки. И вот однажды, набравшись смелости — я начал думать насчет структуры такого вот приложения. Что в итоге получилось — читайте ниже.
Начнемс
Для начала нам потребуется несколько js-плагинов – а именно:
Первый, это знакомый
Для начала создадим папку, например jstemp — в этой папке будут находится шаблоны jquery-tmpl. Еще нужно создать хотя бы один шаблон, например — шаблон главной страницы. Создаем в папке jstemp подпапку main в которой будет файл page.html
В файле простой html код:
<div id="name_of_page">${Content.name}</div> <div id="info_of_page">${Content.info}</div>
Суть работы
В тот момент, когда пользователь заходит на страницу, наше ajax приложение обращается к серверу, с текущей ссылкой, и параметрами, и ждет в ответ JSON. Полученный JSON мы парсим в js-объект и отправляем плагину jquery-tmpl, который расставляет данные из объекта по полочкам, и показывает нужный шаблон нашему пользователю. А так же, если пользователь решит, что текущая страница ему не нужна, и попробует перейти на другую — ajax-приложение тут же отловит его действие и сделает те же самые процедуры, только уже с новой ссылкой, по которой юзер хотел перейти, и вернет результат работы.
Реализация
Для начала напишем начальную страницу:
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> <html xmlns="http://www.w3.org/1999/xhtml"> <head> <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> <script language="Javascript" src="js/jquery-1.5.min.js"></script> <script language="JavaScript" src="js/jquery.tmpl.js"></script> <!--Шаблонизатор--> <script language="JavaScript" src="js/jquery.tmplPlus.min.js"></script> <!--Шаблонизатор--> <script language="JavaScript" src="js/jquery.json-2.2.min.js"></script> <!-- $.toJSON --> <title>Пример</title> <style type="text/css"> body { font: 11pt Arial, Helvetica, sans-serif; margin: 0; } h1 { font-size: 36px; margin: 0; color: #fc6; } h2 { margin-top: 0; } #header { padding: 10px; } #sidebar { float: left; border: 1px solid #eee; width: 20%; padding: 5px; margin: 10px 10px 20px 5px; } #sidebar p { margin-left:20px; } #content { margin: 10px 5px 20px 25%; padding: 5px; border: 1px solid #eee; } #footer { background: #eee; padding: 5px; color: #fff; clear: left; } .error { padding:10px; width:80%;background-color:#ff4f4f; } </style> </head> <body> <div id="header"><h1>Какой - нибудь хеадер.</h1></div> <div id="sidebar"> <h2>Ссылки</h2> <p><a href="#">Главная</a></p> <p><a href="#page/about">О сайте</a></p> <p><a href="#page/contacts">Контакты</a></p> <p><a href="#page/somepage">Какая - то страница</a></p> <p><a href="#user/login">Авторизация</a></p> </div> <div id="content"> <h2>Какой - то контент </h2> <div id="content_wrap"></div><!-- Именно сюда будут грузиться данные --> </div> <div id="footer">© 1</div> </body> </html>
Отметим наличие div с id= «content_wrap» — именно в него будут подгружаться загруженные шаблоны.
Далее напишем начальную загрузку контента.
var user = {}; /** * Возвращает текущий hash без # в начале **/ function hash() { return document.location.hash.replace('#',''); } function load(u) { console.log('loading page '+ u +':'); $.ajax({ url: "/" + u,//я обращаюсь на страницу, которую мне нужно загрузить, //т.к. на серверной стороне - все запросы идут к index.php, //и там я могу найти тот контроллер, который мне нужен type: "GET", data: "action=pageLoad&url="+u+"", // action=pageLoad на серверной стороне - говорит мне, что нужно возвращать JSON success: function(msg){//в этот момент, мы можем вернуть какие - то еще данные о юзере, из сервера, на текущий момент времени var arr = $.parseJSON(msg); console.log('success'); if (arr.my) {//в моем случае, я вернул в arr.my данные о пользователе //обновляем данные о юзере user = { a: (arr.my.id)?true:false, id:arr.my.id, login: arr.my.login, site_login: arr.my.site_login, status: arr.my.status } } document.location.hash = u; render(arr, u); console.log("load template"); } }); } function render(data, url) { //Грузит шаблон, параметр data - объект данных, передаваемых в шаблон; url - вида main/page , user/login $("#content_wrap").show().html('');// обнуляем тот самый участок html-кода, в котором будет подгружена новая страница $.get("jstemp/"+ url +".html", function(template) {//получаем html файл - шаблона console.log("Template finded at jstemp/"+ url +".html"); $.tmpl(template, { Content: data// в шаблоне tmpl все, переданные мною переменные будут хранится в массиве Content }).appendTo('#content_wrap');//добавляем к #content_wrap $("#content_wrap").prepend("<script language='JavaScript' src='js/included.js' />");//позже поясню для чего нужен этот код. }); } $(function(){//функ��ия, вызываемая после загрузки DOM if (hash()) {//если есть хэш var url = hash();// он и будет ссылкой, но без # в начале. } else { var url = 'main/page';// ставим какое - нибудь дефолтное значение } load(url);//загружаем страницу. });
На данном этапе, если все нормально, то можно загрузить главную страницу. Для примера напишу совсем малюсенький серверный код:
<?php if(isset($_GET['action'])&&$_GET['action']=='pageLoad'){ switch($_GET['url']) { case 'page/contacts': $arr = array('name'=>'Контакты', 'info'=>'Связаться с нами можно с помощью сарафанного радио, ответ последует таким же образом.'); break; case 'page/about': $arr = array('name'=>'О сайте', 'info'=>'Этот сайт написан не профессионалами за еду.'); break; case 'page/somepage': $arr = array('name'=>'Еще одна страница', 'info'=>'Тут тоже что - то есть'); break; case 'main/page': default: $arr = array('name'=>'Главная страница', 'info'=>'Разного рода информация'); break; } echo json_encode($arr); } else { ?> Тут Html код, который описан выше. <?php } ?>
Теперь, при обращении к main/page — должно вывестись
Главная страница
Разного рода информация
Ура! 3/4 сделано. Теперь напишем простой скрипт, для отлова клики на ссылки.
/** * Клик на ссылке */ $("a[href^='#']").unbind('click');//старое событие нужно убрать, иначе появляется много одинаковых событий на один клик. $("a[href^='#']").click(function(e){//селектор - только ссылки, у которых параметр href начинается с символа # var url = $("a:hover").attr('href').replace("#",""); if (page_url != url) { if (url) load(url); else load('main/page'); return false; } });
и поместим этот код в тот самый included.js
Назначение этого файла простое: При подгрузки html текста — скрипты, которые уже были на страницы, не хотят с ним работать, для этого приходит на помощь included.js.
А как же работа с формами, спросите вы? Да легко!
Работа с формами
Для примера создадим шаблон user/login.html
и поместим в него код:
{{if Content.error}}<!-- например сообщение о том, что пользователь уже залогинен --> <div class="error login">${Content.error}</div> {{else}} <form class="form" id="login" action="" method="POST"> <div class="error" style="display:none;" id="message_login"></div><!-- Параметр id должен быть равен - message_[id_формы_выше] --> <table> <tr> <td>Логин</td> <td><input name="username[login]" type="text" value="" /></td> </tr> <tr> <td>Пароль</td> <td><input type="password" name="username[password]" value="" /></td> </tr> <br /> <tr> <td colspan="2"><input value="Войти" style="width: 300px; height: 70px;" type="submit" /></td> </tr> </table> </form> {{/if}}
А в тот же included.js следует добавить:
/** * сабмит формы */ $('form').submit(function() {//при отправке формы var form = $(this); var method = form.attr('method'); //забираем method формы var id = form.attr('id'); //и id формы $.ajax({ //url: не нужен, т.е. мы отправляем запрос на текущую страницу. type: method, data: "ajax=1&"+form.serialize(), //отправляем серверу все данные формы в виде строки + параметр ajax - что должно указать, что возвращать нужно JSON success: function(msg){ var arr = $.parseJSON(msg); if (arr.message) $("#message_"+id).show().html(arr.message);//если есть message(например ошибка), тогда вернем его в тот скрытый див. if (arr.go) { // если есть go - то должен быть совершен переход на другую страницу, в нашем случае - без перезагрузок страницы. if (arr.go == '' || arr.go == '/') arr.go = 'main/page'; page.load(arr.go);//грузим другую страницу } } }); return false; });
Обновим серверный код, чтобы было понятно на примере, что происходит:
<?php error_reporting(0); session_start(); if(isset($_POST['username'])){//если отправили форму авторизации if(!$_SESSION['user']){//если еще не авторизированы $user = $_POST['username']; if($user['login']!='test'){ //если логин юзера не test, выдаем message echo json_encode(array('message'=>'Пользователя '.$user['login'].' не существует')); } else {//в противном случае перенаправляем юзера на главную страницу $_SESSION['user'] = $user['login']; //просто для примера. echo json_encode(array('go'=>'/')); } } else {//выдаем error если пользователь уже авторизирован echo json_encode(array('error'=>'Вы уже авторизированы.')); } } else if(isset($_GET['action'])&&$_GET['action']=='pageLoad'){ switch($_GET['url']) { case 'page/contacts': $arr = array('name'=>'Контакты', 'info'=>'Связаться с нами можно с помощью сарафанного радио, ответ последует таким же образом.'); break; case 'page/about': $arr = array('name'=>'О сайте', 'info'=>'Этот сайт написан не профессионалами за еду.'); break; case 'page/somepage': $arr = array('name'=>'Еще одна страница', 'info'=>'Тут тоже что - то есть'); break; case 'main/page': default: $arr = array('name'=>'Главная страница', 'info'=>'Разного рода информация'); break; } echo json_encode($arr); } else { ?> тут полный html код <? } ?>
При POST запросе со страницы, мы проверяем авторизирован ли юзер, и если да — выводим ошибку, и убираем форму, в противном случае — проверяем логин пользователя, если не существует — выводим Message, иначе — отправляем юзера на главную страницу.
В заключении
В заключении хочу сказать, что данный способ не самый правильный, и тем более идеальный, но он заслуживает место быть. Надеюсь, тема статьи была интересна, и может быть, даже, кому — то окажется полезной сама статья.
Спасибо за внимание.
Update: ссылка на сорцы
