Динамическая сортировка меню с использованием метода Ajax.

01.12.2011 Рубрика: Обучение \ PHP

сортировка меню

От автора: если Вы работали с CMS WordPress, то, наверное, знакомы с такой штукой, как виджеты WordPress. В данном случае виджеты – это блоки, которые можно перемещать в режиме Drag and Drop («тащи и бросай»). При этом, после перемещения блока, он сохраняет свою позицию, т.е., к примеру, в сайдбаре сайта у нас имеется блок поиска, под которым размещен блок с произвольным текстом… мы захотели поменять их позиции… нет ничего проще – перетащили блок с поиском под блок с текстом и… вуаля – на сайте эти изменения расположения блоков вступили в силу. Согласитесь, быстро, удобно и эффектно. Сегодня мы научимся делать подобное.

План урока:

    1. Постановка задач. Создание БД (9:42)

    2. Выводим меню из БД (11:09)

    3. Реализуем сортировку без сохранения (11:48)

    4. Обращаемся к методу ajax (6:47)

    5. Реализуем сохранение сортировки (7:07)

    6. Логика работы скрипта (7:59)

    7. Добавляем юзабельности (15:38)

автор

Автор: Андрей Кудлай

Зовут меня Андрей Кудлай. Родом я из Украины, живу в Днепропетровске. Веб-программированию учился сам. Неплохо знаю HTML, CSS, PHP. Немного разбираюсь в JavaScript’e – в свободное время как раз занимаюсь его изучением.

скачать исходникискачать урок

1. Постановка задач. Создание БД

Для начала сформулируем задачу. Вместо блоков у нас будет меню, пункты которого у нас и будут перетаскиваемыми блоками. Для чего вообще это нужно? Допустим, мы хотим изменить сортировку пунктов меню, т.е. сделать так, чтобы из БД пункты меню выводились не отсортированными по идентификатору пункта меню, а по, к примеру, полю position. Для этого, конечно же, можно написать несложный скрипт, который будет выводить текущую позицию каждого из пунктов меню в числовом виде (1, 2, 3 и т.д.). Далее мы сможем для конкретного пункта задать новую числовую позицию и сохранить изменения в БД. Но гораздо быстрее и красивее будет выглядеть реализация, когда мы просто возьмем пункт меню и перетащим его на новое место… все – он сохранит свою позицию.

Итак, мы создаем меню и через административную часть сайта сможем изменять позицию его пунктов. Давайте теперь определимся с тем, что нам понадобится. Прежде всего, нам понадобятся 2 библиотеки jQuery:

собственно сама библиотека jQuery;

библиотека jQuery User Inteface.

Взять их можно на офф сайте jQuery. Также Вы найдете эти скрипты в исходниках к уроку. Также нам понадобится файл стилей для оформления пунктов меню, который Вы можете сгенерировать на сайте jQuery в разделе jQueryUI или найти в исходниках к уроку (или написать стили для пунктов меню самостоятельно в зависимости от дизайна Вашего сайта).

У нас будет 2 файла. Первый файл (index.php) – это страница сайта для общего доступа. Второй файл (admin.php) – это страница админки, на которой мы сможем изменять позицию пунктов меню. Конечно же, доступ к админке должен быть ограничен (как это сделать Вы можете узнать из предыдущих уроков). Основное отличие файла admin.php состоит в том, что мы подключили в него 2 указанных скрипта:

<script src="scripts/jquery-1.6.2.min.js" type="text/javascript"></script>
<script src="scripts/jquery-ui-1.8.14.custom.min.js" type="text/javascript"></script>

В файл index.php эти библиотеки подключать не нужно.

Также в оба файла мы подключим файл стилей:

<link type="text/css" href="css/jquery-ui-1.8.14.custom.css" rel="stylesheet" />

И напишем несколько правил в стилях на странице index.php:

<style>
	#sortable { list-style-type: none; margin: 0; padding: 0; width: 200px; }
	#sortable li { margin: 0 3px 3px 3px; padding: 0.4em; padding-left: 1.5em; font-size: 1.4em; height: 15px; cursor: pointer;}
	#sortable li span { position: absolute; margin-left: -1.3em; }
</style>

И на странице admin.php:

<style>
	#sortable { list-style-type: none; margin: 0; padding: 15px 40px 15px 0; width: 200px; }
	#sortable li { margin: 0 3px 3px 3px; padding: 0.4em; padding-left: 1.5em; font-size: 1.4em; height: 15px; cursor:move}
	#sortable li span { position: absolute; margin-left: -1.3em; }
	.block{/*border:1px solid #ccc;*/ width:200px;}
</style>

Следующее, что нам понадобится – это БД, в которой будут храниться названия каждого из пунктов меню и их текущая позиция на сайте. Чтобы не создавать БД вручную, Вы можете импортировать дамп БД из исходников (файл test.sql).

БД я назову test и создам в ней таблицу sortable, для которой понадобится всего 3 поля:

id, тип INT, первичный ключ, автоинкремент;

name, тип VARCHAR, длина 255 символов;

position, тип INT.

Теперь занесем в созданную таблицу 3 тестовых пункта меню:

Пункт 1 с позицией 1;

Пункт 2 с позицией 2;

Пункт 3 с позицией 3;

Отлично! БД готова.

2. Выводим меню из БД

БД создана и теперь можно вывести меню на сайт. Прежде, чем сделать это создадим файл с подключением к БД. Этот файл мы будем включать на индексную и админскую страницы сайта. Я назову файл db.php. Как подключаться к серверу БД и выбирать необходимую для работы БД мы уже знаем, поскольку неоднократно это делали:

<?php

mysql_connect("localhost", "root", "") or die("No connect to server");
mysql_select_db("test") or die("No select DB");

?>

Теперь подключим этот файл в самом верху индексной и админской страницы:

<?php require_once 'db.php'; ?>

Отлично! Теперь выведем пункты меню на сайт. Для этого создадим заявку (запрос), которой выберем из таблицы sortable все, что там есть, и отсортируем выбранное по полю position в порядке возрастания (таким образом, пункты меню будут выведены традиционно – 1, 2, 3). С запросами мы уже также работали, поэтому ничего нового здесь быть для Вас не должно.

Открываем конструкцию PHP в том месте, где должно быть выведено меню и пишем код:

<?php

$res = mysql_query("SELECT * FROM `sortable` ORDER BY `position`") or die(mysql_error());
echo "<ul id='sortable'>\r\n";
while($row = mysql_fetch_assoc($res)){
	echo "<li id='{$row['id']}' class='ui-state-default'>{$row['name']}</li>\r\n";
}
echo "</ul>";

?>

Здесь мы выводим пункты меню списком. При этом стоит обратить внимание на то, что каждый из пунктов имеет свой идентификатор, значением которого является идентификатор конкретного поля в БД. Этот идентификатор нам понадобится для того, чтобы уникализировать каждый из пунктов меню.

Отлично!

Пункты меню выбраны из БД и появились на сайте.

3. Реализуем сортировку без сохранения

С файло index.php мы закончили и теперь можно перейти к админке. Для начала просто скопируем код вывода меню из индексного файла. Теперь, если посмотреть в браузере страницу admin.php, то увидим аналогичное меню за одним исключением – при наведении на пункты меню курсор приобретает крестовидную форму, что говорит о том, что данные пункты можно перетаскивать. Реализуется такая форма курсора правилом в стилях:

cursor:move

Это правило мы прописали ранее. Курсор изменяет свою форму, но пункты меню пока что невозможно перетаскивать. Для того, чтобы это было возможно сделать, пропишем простой скрипт в блоке head:

<script type="text/javascript">
$(document).ready(function(){
	$('#sortable').sortable({

	});
});
</script>

Все…

Теперь мы уже можем перетаскивать пункты меню. Это реализовано благодаря работе тех двух библиотек, которые мы подключили ранее. Здесь же мы просто взяли в набор jQuery элемент с идентификатором sortable и вызвали для него метод sortable. Если Вы не знакомы с основами jQuery, то рекомендую Вам обратиться к предыдущим урокам на сайте, где мы знакомились с основами работы jQuery. Сам метод sortable, к которому мы обратились, описан в библиотеке jQuery UI. Он имеет множество параметров, событий и методов, некоторыми из которых мы сейчас и воспользуемся. Прежде всего, давайте ограничим перемещение блоков только осью Y (только по вертикали). Для этого обратимся к опции axis:

<script type="text/javascript">
$(document).ready(function(){
	$('#sortable').sortable({
		axis: 'y'
	});
});
</script>

Теперь давайте уменьшим непрозрачность перетаскиваемого элемента до 50%:

<script type="text/javascript">
$(document).ready(function(){
	$('#sortable').sortable({
		axis: 'y',
		opacity: 0.5
	});
});
</script>

Отлично!

Теперь надо сделать так, чтобы мы могли получить текущую позицию каждого из элементов после того, как мы завершим перемещение. Для этого обратимся к событию stop и методу (функции) toArray:

<script type="text/javascript">
$(document).ready(function(){
	$('#sortable').sortable({
		axis: 'y',
		opacity: 0.5,
		stop: function(){
			var arr = $('#sortable').sortable("toArray");
			alert(arr);
		}
	});
});
</script>

Итак, что мы здесь сделали? После наступления события stop (когда завершено перетаскивание элемента) мы обращаемся к элементу с id sortable (это наше меню) и вызываем функцию toArray. Данная функция получает id каждого из отсортированных элементов и помещает его в массив в виде строки, где значения разделены запятой. Результат помещаем в переменную arr. Таким образом, если мы изменим изначальную позицию пунктов 1 и 2, то в переменной arr будет содержаться вот такая строка – 2, 1, 3. Для наглядности можно вывести методом alert значение переменной arr после каждого из перетаскиваний.

4. Обращаемся к методу ajax

Мы выполнили часть задачи – пункты меню можно теперь перетаскивать. Но они не сохраняют своей позиции в БД и после обновления страницы, все встает на круги своя. Для того, чтобы обновления были внесены в БД, необходимо передать значение переменной arr в скрипт PHP, который бы занес обновленные данные в БД. Сделать это, обратившись к методу jQuery под названием ajax(). Итак, пропишем его со всеми необходимыми нам параметрами:

<script type="text/javascript">
$(document).ready(function(){
	$('#sortable').sortable({
		axis: 'y',
		opacity: 0.5,
		stop: function(){
			var arr = $('#sortable').sortable("toArray");
			//alert(arr);
			$.ajax({
				url: 'save.php',
				type: 'POST',
				data: {masiv:arr},
				error: function(){
					$('#res').text("Ошибка!");
				},
				success: function(){
					$('#res').text("Сохранено!");
				}
			});
		}
	});
});
</script>

Пройдемся по параметрам:

url: указываем имя файла, который примет данные из скрипта (аналог атрибута action в форме);

type: тип передаваемых данных (аналог атрибута method в форме);

data: передаваемые данные в формате {переменная:значение};

error и success: события ошибки и успеха запроса соответственно.

Таким образом, мы передаем значение переменной masiv методом POST в файл save.php. В случае успеха в блок с идентификатором res будет добавлен текст "Сохранено!", в случае ошибки – «Ошибка!».

Все просто…

5. Реализуем сохранение сортировки

Осталось написать скрипт для файла save.php, который бы принимал данные. Создадим файл save.php и запишем в него следующий код:

<?php 

require_once 'db.php';

$pos_new = 1;
foreach($_POST['masiv'] as $item){
	$res = mysql_query("UPDATE `sortable` SET `position`='{$pos_new}' WHERE `id`='{$item}'");
	$pos_new++;
}

?>

Теперь давайте попробуем разобраться в работе того, что мы написали только что.

6. Логика работы скрипта

Поскольку мы принимаем массив данных – используем цикл foreach для того, чтобы пройтись по каждому из элементов массива. До начала цикла создадим переменную $pos_new со значением 1, которая будет новым значением позиции для каждого из пунктов меню. В теле цикла мы будем с каждым шагом цикла увеличивать значение переменной на единицу. Таким образом, ее значение последовательно будет изменяться от 1 до 3. Также в теле цикла указываем запрос, которым устанавливаем текущее значение переменной $pos_new значением поля position. Но делаем мы это для того поля, в котором значение поля id будет равно текущему значению перебираемого элемента массива, который мы получили. Здесь важно понять саму логику работы запроса. Поскольку мы передаем в массиве идентификаторы каждого из пунктов меню, то логично, что они будут соответствовать идентификаторам пунктов меню в БД. Именно поэтому для полученного идентификатора мы установим текущее значение переменной $pos_new в БД.

Вам проще будет уяснить работу скрипта, если Вы при помощи метода alert будете видеть что отсылается и наблюдать изменения в БД.

7. Добавляем юзабельности

Осталось добавить некоторые улучшения, которые сделают более приятной работу со скриптом. Например, мы можем после каждого сохранения только на время показывать текст "Сохранено!", а затем сделать так, чтобы он исчезал. Также сделаем так, чтобы место блока, который мы захватили, подсвечивалось:

<script type="text/javascript">
$(document).ready(function(){
	$('#sortable').sortable({
		axis: 'y',
		opacity: 0.5,
		placeholder: 'ui-state-default',
		containment: '.block',
		stop: function(){
			var arr = $('#sortable').sortable("toArray");
			//alert(arr);
			$.ajax({
				url: 'save.php',
				type: 'POST',
				data: {masiv:arr},
				error: function(){
					$('#res').text("Ошибка!");
				},
				success: function(){
					$('#res').show().text("Сохранено!").fadeOut(1000);
				}
			});
		}
	});
});
</script>

Теперь гораздо лучше. Вот и все. Наша задача реализована.

Заключение

Пункты меню после перетаскивания сохраняют свою позицию в БД. Стоит только напомнить о безопасности. В принципе, об этом я уже неоднократно говорил в предыдущих уроках, но напомню основное правило безопасности: все данные, принимаемые от пользователя, должны соответствующим образом быть обработаны. Здесь, конечно, в этом особого смысла нет, поскольку работа с БД осуществляется на уровне админки, но если бы мы принимали данные из пользовательской части, то каждый из элементов массива необходимо было бы привести к явному целочисленному типу функцией (int) или intval(), чтобы в запрос гарантированно попадало число.

На этом наш урок завершен. Ваши вопросы и отзывы всегда будем рады видеть в комментариях. Удачи в Ваших разработках и до новых встреч!

Автор: Кудлай Андрей. Команда webformyself.

Подписаться Поделиться

Метки:

Комментарии (13)

  1. Руслан

    Спасибо, как всегда пошаговая и подробная инструкция. Урок пригодится.

    Нравится или не нравится: Thumb up 2 Thumb down 1

  2. Эдуард

    Очень интересно!
    Спасибо!!!
    Теперь не успокоюсь, пока где-нибудь не опробую!

    Нравится или не нравится: Thumb up 1 Thumb down 0

  3. skrabus

    Спасибо за очень добротно сделанный и полезный урок.

    Нравится или не нравится: Thumb up 1 Thumb down 0

  4. Любовь

    Понравилось, как всегда всё понятно, но пока ещё придётся разбираться, как я поняла.

    Нравится или не нравится: Thumb up 1 Thumb down 0

  5. fortinbras

    Андрей, подскажите, пожалуйста, как на Вордпресс сделать Популярные записи картинками, как у вас, а не просто заголовок статьи.

    Нравится или не нравится: Thumb up 2 Thumb down 0

    • Андрей Кудлай

      Если не ошибаюсь, то в этом Вам поможет плагин WordPress Related Posts. Также можете посмотреть плагин WordPress Popular Posts и другие похожие.

      Нравится или не нравится: Thumb up 3 Thumb down 0

    • Andrey Bernacki

      Да, как сказал Андрей, я использовал плагин WordPress Popular Posts, но не в читом виде, так как он картинки не выводит, а дописывал его немного, чтобы он выводил картинки. Картинки которые выводятся нужно делать миниатюрами – в эту сторону копать нужно, если хотите подобное сделать.

      Нравится или не нравится: Thumb up 2 Thumb down 0

  6. Святослав

    Супер урок!!! Побольше бы таких про ajax!!!

    Нравится или не нравится: Thumb up 0 Thumb down 0

  7. Сергей

    Спасибо за урок! Автору ОГРОМНЫЙ респект!!!

    Нравится или не нравится: Thumb up 0 Thumb down 0

  8. Виктор

    О да.. Давно хотел сделать, но с аяксом не особа знаком.. Сделал сортировку вотографий в фотоальбоме, потом ужаснулся… Так низя :) Если в альбоме больше 100 фоток, представляете что будет? Сколько будет инсертов в БД внутри цикла?

    Нравится или не нравится: Thumb up 0 Thumb down 0

    • Андрей Кудлай

      Логично :)
      Этот способ хорош для незначительного количества информации – блоки, пункты меню и т.п.

      Нравится или не нравится: Thumb up 0 Thumb down 0

  9. Виктор

    Скажем так, раз они перемещаются, сохраняя позицию и без записи, то впринципе сабмит можно повесить на кнопку. Хотя наверное логичнее менять местами 2 цифры каждый раз.. Вот это было бы идеально. Где бы ещё пример реализации найти для ознакомления..

    Нравится или не нравится: Thumb up 0 Thumb down 0

  10. Виктор

    Кстати, как бы проверить откуда пришёл запрос? Куда всавить переменну, или идентификатор, чтобы он и массиву не мешал и можно было проверить его наличие в скрипте сохраниения.

    Нравится или не нравится: Thumb up 0 Thumb down 0

Добавить комментарий

Ваш e-mail не будет опубликован. Обязательные поля помечены *

*

Я не робот.

Spam Protection by WP-SpamFree