Всем привет.
В этой теме мы будем рассматривать реализацию full-ajax навигации на примере обычного блога. Если кому-то интересно, прошу под кат.
В очередной раз просматривая хабрахабр, меня посетила мысль наваять что-нибудь свое. Поэтому заказав пиццу и вооружившись большой кружкой чая — начал думать.
Я заметил, что на хабре много постов о том, как написать блог с использованием Fat-Free Framework, symfony, Zend и так далее… И тут у меня в голове закралась идея написать блог с ajax навигацией. А почему бы и нет? На хабре я не встретил такой статьи, может быть плохо искал…
Для того, чтобы пост не получился слишком большой я решил разделить его на несколько частей. Хочу обратить Ваше внимание на то, что это мой первый пост на хабре, да и писарь из меня никудышный. Поэтому, если что не так, извиняйте.
Итак, приступим.
Демо.
Ссылки в нашем блоге будут следующего вида:
http://localhost/#!/
http://localhost/#!/page
http://localhost/#!/another-apge
Такие ссылки Вы могли видеть в твиттере.
В нашей корневой директории создаем индексный файл, в котором будет немного верстки нашего кульного блога.
Я над дизайном заморачиваться не стал, так как это пост не об этом. Поэтому без комментариев выкладываю его содержание:
<!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" xml:lang="en" lang="en">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<meta name="description" content="" />
<meta name="keywords" content="" />
<meta name="generator" content="" />
<title>My thirst Ajax Blog</title>
<script type="text/javascript" src="inc/ajax.js"></script>
<script src="//ajax.googleapis.com/ajax/libs/jquery/1.10.2/jquery.min.js"></script>
<link type="text/css" rel="stylesheet" href="style.css"/>
</head>
<body>
<div id="content">
<h1><a href="/#!/">Мой блог</a> <span>v1.0</span></h1>
<p>
<a href="/#!/">Home page</a>
<a href="/#!/about">About page</a>
</p>
<hr />
<div id="posts"></div>
</div>
<div id="preloader">
<div style="position: absolute; left: 50%; margin-left: -50px; top: 50%; margin-top: -50px;">
<img src="loading.gif" title="Loading..." alt="Loading.." />
</div>
</div>
</body>
<script>
$(document).ready(function(){
ajax.onLoadStart = function(){
$('#preloader').show();
};
ajax.onLoadEnd = function(){
$('#preloader').hide();
};
ajax.init();
});
</script>
</html>
Единственное, на что хотелось бы обратить внимание, это яваскрипт в конце страницы, который собственно и будет инициализировать нашу ajax-навигацию по блогу.
Чуть не забыл про стили, содержимое style.css:
html, body, div, ul {
margin: 0;
padding: 0;
}
body {
color: #262626;
background: #f4f4f4;
font: normal 12px/18px Verdana, sans-serif;
}
#content {
position: absolute;
width: 800px;
right: 0px;
left: 0px;
margin: 40px auto 0 auto;
padding: 0 60px 30px 60px;
border: solid 1px #cbcbcb;
background: #fafafa;
-moz-box-shadow: 0px 0px 10px #cbcbcb;
-webkit-box-shadow: 0px 0px 10px #cbcbcb;
}
h1 {
margin: 30px 0 15px 0;
font-size: 30px;
font-weight: bold;
font-family: Arial;
}
h1 span {
font-size: 50%;
letter-spacing: -0.05em;
}
hr {
border: none;
height: 1px; line-height: 1px;
background: #E5E5E5;
margin-bottom: 20px;
padding: 0;
}
p {
margin: 0;
padding: 7px 0;
}
a {
outline: none;
}
link {
color: #000;
text-decoration: none;
}
a:visited, a:link {
color: #000;
text-decoration: none;
}
a:hover {
color: #000;
text-decoration: none;
}
a:active {
color: #000;
text-decoration:none;
}
#preloader{
display: none;
position:fixed;
z-index: 777;
background:none repeat scroll 0 0 #000000;
cursor:wait;
width:100%;
height:100%;
top:0;
left:0;
opacity:0.7;
-moz-opacity: 0.5;
-khtml-opacity: 0.5;
}
Здесь все понятно, идем дальше… Файл ajax.js:
var ajax = {
/**
* Скрипт, который будет обрабатывать наши ajax запросы.
*/
ajSrc: 'ajax.php',
ajUrl: '',
/**
* Функция, которая будет вызываться при начале загрузки
*/
onLoadStart: function(){},
/**
* Функция, которая будет вызываться после получения ответа
*/
onLoadEnd: function(){},
/**
* Мы организовали навигацию при помощи урлов вида #!/my-url.
* Поэтому эта функция проверяет адресную строку на соответствие урла такому виду и в случае чего, отправляет запрос.
* @return {Boolean}
*/
checkAjaxNav: function(){
hash = document.location.hash;
navInd = hash.substr(0, 3);
if(navInd != '#!/'){
this.ajUrl = hash;
return false;
}
hash = hash.substr(2);
if( hash != this.ajUrl ){
this.ajUrl = hash;
this.sendData(hash);
}
return true;
},
/**
* Отправляем запрос на сервер
* @param ajaxData
*/
sendData: function(ajaxData){
this.onLoadStart();
$.post(this.ajSrc, {
ajax_data: ajaxData
}, function( data ){
ajax.receiveData(data);
}, 'json');
},
/**
* Получаем ответ от сервера и обрабатываем его.
* @param data
*/
receiveData: function( data ){
for( var key in data ){
var val = data[key];
if( 'eval' == key )
eval(val);
else
$(key).html(val);
}
this.onLoadEnd();
},
/**
* Инициализируем нашу навигацию
*/
init: function(){
this.checkAjaxNav();
$(window).bind('hashchange', function(){
ajax.checkAjaxNav();
});
}
};
Здесь видно, что мы будем отправлять запросы функцией sendData()
на наш обработчик ajax.php
.
Перед тем, как запрос будет отправлен, вызывается функция onLoadStart()
в которой можно выполнять что-то. Например показать пользователю красивый индикатор загрузки, прикрутить валидацию форм и т.д.
После того, как наш запрос будет обработан, вызывается функция receiveData()
, в которой мы обрабатываем полученные данные и вызываем функцию onLoadEnd()
, которая скрывает наш индикатор загрузки и выполняет какие-то другие функции. Например, ре-инициализация форм страницы и т.д
Обработчик ajax.php
<?php
error_reporting(0);
define("coolBlogCms", true);
define("DIR", getcwd() . "/");
define("INC", DIR . "inc/");
require_once INC . "myAjax.php";
$blog = new myAjax();
if( isset($_POST['ajax_data']) ){
$ew = $blog->receiveData();
switch($ew[1]){
case 'about':
$html['#posts'] = <<<HTML
This is about page. Loaded from my ajax cms.
HTML;
break;
default:
$html['#posts'] = <<<HTML
This is the main page of my cool blog. Thank's for reading.
HTML;
break;
}
$blog->sendData($html);
}
?>
Это небольшой контролер, который будет обрабатывать наши запросы и данные. Пока что здесь нет ничего сверх естественного.
Функция receiveData()
получает данные POST-запроса. А sendData()
отправляет данные. Сейчас это только json, но дальше мы прикрутим еще что-нибудь.
Данные мы будем отправлять массивом, в котором ключом будет выступать селектор элементов или #id элемента на конечной странице, а значением — некие данные.
Так же этой функцией мы можем отправлять js код, который затем выполнится на странице при помощи eval()
Пример для наглядности:
$arr = array();
$arr['#first_div'] = "First div content";
$arr['#second_div'] = "Second div content";
$arr['.another_divs'] = "Content that will be placed to several divs";
$blog->sendData($arr, "alert('Hello world !');");
myAjax.php
<?php
if(!defined("coolBlogCms"))
exit;
class myAjax{
/**
* @return bool
*/
public function receiveData(){
if( !isset($_POST['ajax_data']) ){
return false;
}
$data = $_POST['ajax_data'];
$data = explode('/', $data);
unset( $_POST['ajax_data'] );
return $data;
}
/**
* @param $data
* @param string $eval
* @return bool
*/
public function sendData( $data, $eval = '' ){
if(!$data && !$eval)
return false;
if( !headers_sent() ){
header('Content-Type: application/json; charset=utf-8' );
}
echo json_encode( array_merge($data, array('eval' => $eval)) );
return true;
}
}
Вот и все. Если читателям будет интересно продолжение, то я с радостью напишу вторую часть статьи. Примерное содержание второй части:
- Организация БД для хранения постов, комментариев
- Обработчик форм
- * Допиливание существующего функционала
- Оптимизация кода
В качестве БД можно расмотреть такие варианты как традиционная MySQL, или MongoDb.
* Планируется добавление xml и plain типов данных.
Если у Вас есть какие-либо пожелания, о том, что бы Вы хотели видеть в следующей статье — пишите.
Если у Вас есть свое мнение, по поводу того, что и как можно было бы сделать лучше — пишите, буду рад.
Так же рад буду и конструктивной критике.
Автор: byabuzyak