Пишем блог с Full-Fjax навигацией сами и с нуля. Часть 1

в 8:00, , рубрики: ajax, cms, php, блог, метки: , , ,

Всем привет.

В этой теме мы будем рассматривать реализацию 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

Источник


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


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