Использование Аякса всегда имеет некоторые сложности, потому что требуется сразу решить несколько задач: HTML + CSS, PHP и JS. Сегодня я расскажу как можно создать небольшое приложение на MaxSite CMS.
Назвал я его «Крестики-нолики» по аналогии с одноименной игрой. Правда я не стал реализовывать алгоритм поиска верных ходов и анализ выигрышних комбинаций. Эта часть довольно трудоёмкая, и при желании, вы можете её самостоятельно сделать.
Для начала, как обычно, нужно составить небольшое ТЗ.
- У нас будет приложение, которое мы оформим в виде шаблона MaxSite CMS. Пусть он называется «cross».
- Нужно оформить внешний вид в виде клеток 3x3.
- Нужно использовать анимацию для красоты.
- Нужно запретить ставить ходы на уже занятые клетки.
- Ответ сервера будет генерироваться случайным образом из пустых клеток.
- Ответ сервера нужно получать без перезагрузки страницы по AJAX.
Итак приступаем.
Делаем каталог «cross» и в нем располагаем файлы index.php и info.php. Поскольку у нас будет только одна страница, то в index.php мы подключим основной файл нашего приложения cross.php:
require('cross.php');
Почему мы делаем подключение еще одного файла, а не сразу программируем в index.php? Всё просто: я стараюсь использовать «классический» вариант построения шаблона MaxSite CMS, где index.php выполняет роль диспетчера типов данных. То есть, если у вас возникнет потребность что-то добавить, то это легко сделать именно в index.php.
По этой же причине мы оформим наш HTML в виде файлов:
- main-start.php
- header.php
- main-end.php
- style.css
Описывать разметку нет смысла, потому что дизайн будет зависеть от ваших потребностей, просто остановлюсь на нескольких моментах.
Прежде всего еще раз напомню как происходит подключение файлов. В index.php мы подключаем cross.php. Этот файл в свою очередь выполняется так:
require(getinfo('template_dir') . 'main-start.php'); тут наш код require(getinfo('template_dir') . 'main-end.php');
В main-start.php мы подключаем header.php. Таким образом наш шаблон разбит на секцию HEAD, начальную часть, выполняемую и конечную.
В header.php мы должны подключить jQuery, поскольку js-часть будет использовать именно эту библиотеку. Кроме этого мы вынесем свою часть js в отдельный файл (my.js).
<?= mso_load_jquery() ?> <?= mso_load_jquery('ui/effects.core.packed.js') ?> <?= mso_load_jquery('ui/effects.highlight.packed.js') ?> <script type="text/javascript" src="<?= getinfo('stylesheet_url') ?>js/my.js"></script>
В первой строчке подключаем jQuery. Во второй и третьей подключаем эффекты. Последней - наш скрипт.
Теперь давайте перейдем к cross.php. Я решил не усложнять задачу, поэтому наше поле 3x3 оформил в виде обычной таблицы, где каждой ячейке прописал свой class. Поскольку код очень маленький, то я привожу полный листинг файла:
<?php if (!defined('BASEPATH')) exit('No direct script access allowed'); # начальная часть шаблона require(getinfo('template_dir') . 'main-start.php'); ?> <table> <tr> <td class="r1"></td> <td class="r2"></td> <td class="r3"></td> </tr> <tr> <td class="r4"></td> <td class="r5"></td> <td class="r6"></td> </tr> <tr> <td class="r7"></td> <td class="r8"></td> <td class="r9"></td> </tr> </table> <?php # конечная часть шаблона require(getinfo('template_dir') . 'main-end.php'); ?>
Оформление я вынес в style.css.
Уверен, что никаких сложностей с пониманием этого кода у вас не возникнет. В браузере это будет выглядеть так:
Теперь переходим к самому интересному: определим алгоритм работы. У нас есть уникальные ячейки (td.class) - по ним мы можем отследить какой был клик/ход. На сервер нам нужно передавать не только последний ход посетителя, но и всю таблицу. Сделать это можно получив js-свойство text() каждой ячейки и сформировав строчку вида: «r1 - - X - 0 - - - -». Где элементы разделены пробелом; если «-», значит клетка пустая; «X» - ход посетителя; «0» - ход сервера.
Эту строчку мы передаем на сервер, что-то с ней делаем и отдаем обратно в виде массива (в формате JSON). JS-скрипт обходит этот массив и устанавливает тексты ячеек таблицы в соответствии с массивом. В массиве от сервера мы также передадим и номер хода - он потребуется для анимации.
Теперь перейдем непосредственно к js. В файле my.js вначале подключим jQuery.
$(function(){ тут js-код });
Все дальнейшие действия мы будем проводить внутри этого блока.
Для начала определимся с анимацией. Я выбрал «вспышку», которая будет происходить когда курсор мыши находится над ячейкой таблицы:
$('td').mouseover( function() { if ( $(this).text() ) $(this).effect("highlight", {color: "#FFE0E0"}, 500); else $(this).effect("highlight", {color: "#A0FFA0"}, 500); });
Единственный момент - я указал условие «if ( $(this).text() )», которое проверяет есть ли текст внутри ячейки. Если есть, значит в ней ход ставить нельзя и мы подсвечиваем его светло-красным. Если же текста нет, то это пустая ячейка и она подсвечивается светло-зеленым.
Теперь нам нужно определить действия по клику.
$("td").click(function() { наши действия };
Для начала мы должны запретить действия, если ход запрещен. Код вам уже знаком:
if ( $(this).text() ) { $(this).effect("highlight", {color: "#FF0000"}, 200); return; }
Подсвечиваем красным и выходим из функции.
Теперь нам нужно создать строчку, которую мы отправим на сервер. Каждая ячейка может содержать три значения: пусто, X и 0. Я сделал вспомогательную функцию, которая получает какое-то значение текста, а на выходе отдает одно из трех вариантов (пусто заменяем на «-»).
function k(e) { if (e) { if ( e == "0") m = "0"; else m = "X"; } else m = "-"; return m; }
Составить строчку теперь не составлает труда:
var s = $(this).attr("class") + ' ' + k($("td.r1").text()) + ' ' + k($("td.r2").text()) + ' ' + k($("td.r3").text()) + ' ' + k($("td.r4").text()) + ' ' + k($("td.r5").text()) + ' ' + k($("td.r6").text()) + ' ' + k($("td.r7").text()) + ' ' + k($("td.r8").text()) + ' ' + k($("td.r9").text());
Мы прогоняем через функцию k() каждую ячейку и получаем строчку, разделенную пробелами. Вот эта часть «$(this).attr("class")» возвращает класс нажатой ячейки (r1-r9). То есть на сервере по этому значению мы можем отследить последний ход.
Для того чтобы отправить строчку на сервер используется несколько функций. Я остановился на $.ajax(), которая считается универсальной.
$.ajax({ type: "POST", url: path_ajax, data: "cross=" + s, dataType: "text", success: function(msg) { ответ сервера в msg } });
Мы отправляем данные как POST. Данные (data) отправляются как поле «cross». Тип - текст.
Ответ сервера помещается в success в виде аргумента функции, в нашем случае это msg.
Теперь самое интересное. Обратите внимание на переменнную path_ajax. Это путь к «приёмному» php-файлу. Здесь я хочу остановиться поподробнее.
Путь к файлу нужно указывать полным в виде адреса. Казалось бы ничего сложного, однако есть маленький нюанс. Если мы напрямую обратимся к php-файлу, то мы не сможем получить доступ к MaxSite CMS! Очень часто нужна работа АЯКСА именно в рамках системы. Например при отправке данных со страницы какой-то записи. Очевидно, что одиночный php-скрипт просто не получит никаких данных об отправляемой странице. Чтобы обойти все эти ограничений в MaxSite CMS используется предопределенный тип данных «ajax» (http://сайт/ajax/). Во втором сегменте (уточнение ниже) нужно указать путь до файла относительно каталога «maxsite».
В нашем примере это будет так:
http://сайт/ajax/templates/cross/cross-post-ajax.php
Получив такой адрес, MaxSite CMS подключит файл
путь_на_сервере/application/maxsite/templates/cross/cross-post-ajax.php
Таким образом обращение к cross-post-ajax.php произойдет уже на уровне системы и мы преспокойно можем использовать все её функции, плагины и т.п.
Однако это еще не всё. Тип «ajax» должен иметь только один сегмент URL. Дело в том, что адреса могут быть самыми разными и иметь разную вложенность («/»). И чтобы не «сбивать» сегменты URL следует кодировать путь к файлу с помощью base64.
Таким образом путь определяется так:
$p = getinfo('ajax') . base64_encode( 'templates/' . getinfo('template') . '/cross-post-ajax.php' );
В итоге получится что-то вроде такого:
http://сайт/ajax/dGVtcGxhdGVzL2Nyb3NzL2Nyb3NzLXBvc3QucGhw
Система автоматически декодирует эту строчку и подключит нужный файл.
В последних версиях MaxSite CMS в целях безопасности имя ajax-файла должно иметь формат «имя-ajax.php». Только в этом случае произойдет его подключение.
Ну вот, когда мы определились с путями для Аякса, нам следует передать имя файла в наш js-скрипт. Очевидно, что php выполнять в js-файле не получится, поэтому мы с помощью php сгенерируем js-код, где в качестве переменной path_ajax укажем путь к файлу.
Перед подключением my.js в header.php допишем:
<script type="text/javascript"> var path_ajax = "<?= getinfo('ajax') . base64_encode( 'templates/' . getinfo('template') . '/cross-post-ajax.php' ) ?>"; </script>
Как видите всё очень просто.
Что делать если нужно оправлять несколько Аякс-запросов к разным файлам? В принципе можно задать для них разные переменные, вроде path_ajax, path_ajax1, path_ajax2 и т.д. Но можно воспользорваться и одним. В этом случае в «приёмном» файле следует отслеживать входные данные (в $.ajax это data) и от этого подключать другие php-файлы.
Последняя часть работы с js - получив ответ сервера, изменить тексты ячеек. Сервер будет отдавать массив, где ключи совпадают с номером ячейки, а значения - с текстом. Таким образом мы просто обходим массив и расставляем тексты в ячейки.
... success: function(msg) { var t = eval('(' + msg + ')'); for (var i = 1; i < 10; i++) { $("td.r" + i).text(t[i]); }; $("td.r" + t[0]).effect("highlight", {color: "#40FF40"}, 1500); $("td.r" + t[10]).effect("highlight", {color: "#FFA080"}, 1500); }
Первая строчка - преобразование JSON-данных в обычный js-массив. Дальше мы запускаем цикл for с 1 по 9 и выставляем тексты. Последние две строчки - анимация. В нулевом элементе у нас хранится последний ход посетителя, в 10-м - ход сервера.
С js покончено, переходим к php-части. Как вы уже поняли из описаний выше, наш «приёмный» файл это cross-post-ajax.php.
Работа в нем организуется аналогично обработке обычной формы, а результат нужно отдать по echo, предварительно кодировав его в формат JSON.
Дальше я привожу полный листинг с комментариями.
<?php if (!defined('BASEPATH')) exit('No direct script access allowed'); mso_checkreferer(); // защищаем реферер if ( $post = mso_check_post(array('cross')) ) { # разобьем строку в массив $ar = explode(' ', $post['cross']); # $ar[0] - это только что выбранная ячейка # $ar[1]...$ar[9] - клетки # если «-» - пустая # если «X» - ход посетителя # если «0» - ход сайта # заменим - на '' foreach ($ar as $key => $val) if ($ar[$key] == '-') $ar[$key] = ''; # добавим X в новый ход # сразу преобразуем в число - это номер ячейки $ar[0] = substr($ar[0], 1, 1); $ar[ $ar[0] ] = 'X'; # после выбираем свой ход случайно из пустых # сделаем массив от 1 до 9 $my_hod = array_fill(1, 9, '0'); while($my_hod) { # случайный элемент $n = array_rand($my_hod); # удалим его, чтобы повторно не обращаться unset($my_hod[$n]); # пустая клетка? if ($ar[$n] === '') { $ar[$n] = '0'; // да, ставим свой ход break; // выходим из цикла } } # наш ход в $ar[10] $ar[] = $n; # отправляем данные echo json_encode($ar); } ?>
Скачать «Крестики-нолики» 776 (ок. 23КБ.)
Комментариев: 3 RSS
1@maxsite30-03-2010 13:34
Тест.
2Сергей26-11-2011 07:48
Спасибо, все работает, но:
при ошибке возвращает 200 ОК со всеми вытекающими последствиями, если вместо die
и добавить еще строчку чтобы если файл не существует, также возвращало ошибку.3Дмитрий05-06-2013 15:48
Работаю с ajax все отправка данных работает отлично и проверка в php тоже.
Но есть одно но, пытаюсь сделать ответ из базы данных обратно в ajax и тут не чего не выходит. Что можно здесь сделать?