Здравствуйте! В данном уроке я покажу, как можно реализовать сортировку перетаскиванием с последующим сохранением порядка элементов в базу данных. Хотелось бы заметить, что данная тематика уже раньше поднималась, но она была JQuery сортировкой, поэтому сегодня для Вас новенькое на JavaScript, PHP и MySQL. Начнем сразу с таблицы, в которой будут записаны элементы. В примере я храню в базе только заголовок элемента, его порядковый номер и идентификатор:
CREATE TABLE IF NOT EXISTS `items` ( `id` int(11) NOT NULL AUTO_INCREMENT, `title` varchar(20) DEFAULT NULL, `number` int(11) NOT NULL, PRIMARY KEY (`id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8;
Далее создадим файл, который будет формировать список из данных, хранимых в базе, а вместе с ним и файл с настройками подключения к базе:
// Файл db.php <?php $engine = 'mysql'; $host = 'localhost'; $database = 'sortable'; $user = 'root'; $pass = ''; $dns = $engine.':dbname='.$database.";host=".$host; $db = new PDO( $dns, $user, $pass ); // Файл get.php <?php include_once './db.php'; // Сортируем по порядковому номеру $query = "SELECT * FROM items ORDER BY number"; $sth = $db->prepare($query); $sth->execute(); $result = $sth->fetchAll(); foreach ($result as $row): ?> // Записываем идентификатор в data-id <li data-id="<?php echo $row["id"]; ?>"><?php echo $row["title"]; ?></li> <?php endforeach; ?>
Мы записываем идентификатор прямо в элемент с помощью атрибута data, так как в процессе ручной сортировки порядок будет меняться, и новый порядок можно будет сохранить, сопоставив его с идентификаторами.
Полученный список тегов li записываем в ul контейнер асинхронным запросом. Делаем это при помощи объекта класса XMLHttpRequest, но поскольку в некоторых старых браузерах название класса может отличаться, объект получаем через следующую функцию:
function getXmlHttp(){ var xmlhttp; try { xmlhttp = new ActiveXObject("Msxml2.XMLHTTP"); } catch (e) { try { xmlhttp = new ActiveXObject("Microsoft.XMLHTTP"); } catch (E) { xmlhttp = false; } } if (!xmlhttp && typeof XMLHttpRequest!="undefined") { xmlhttp = new XMLHttpRequest(); } return xmlhttp; }
Далее сам запрос:
var xhp = getXmlHttp(); xhp.open("GET", "/get.php", true); // При изменении состояния запроса будет вызываться функция xhp.onreadystatechange = function() { // 4 – означает, что браузер получил ответ от сервера if (xhp.readyState == 4) { // 200 – код статуса запроса, который означает, что запрос выполнен успешно if(xhp.status == 200) { var container = document.getElementById("wrap"); container.innerHTML = xhp.responseText; // Применяем «плагин» сортировки, который рассмотрен ниже по тексту container.sortable({update:function(item){ sending(container); }}); } else { alert("Error!"); } } }; xhp.send(null);
Теперь приступим к рассмотрению самого плагина. А я его называю именно плагином, так как реализация позволяет его применить, причем с указанием нескольких событий.
Сам плагин основан на переопределении событий drag’n’drop, а именно dragstart, dragover и dragend. Ниже вы можете увидеть код реализации плагина.
Element.prototype.sortable = function(options){ var current, following; // Указываем, что дочерние элементы ul перетаскиваемы [].slice.call(this.children).forEach(function(element){ element.draggable = true; }); // Функция для события dragover function dragging(event){ event.preventDefault(); /* Процесс сортировки (если элемент сместился вверх или вниз более чам на половину своей высоты, то соответственно переставляем его выше или ниже по списку) */ var target = event.target; if(target && target !== current && target.parentNode === this){ var rect = target.getBoundingClientRect(); var next = (event.clientY - rect.top)/(rect.bottom - rect.top) > 0.5; this.insertBefore(current, next && target.nextSibling || target); } } // Функция для события dragend function drop(event){ event.preventDefault(); current.classList.remove("place"); // Вызов событий stop и update if(typeof options.update === "function" && following !== current.nextSibling){ options.update(current); } if(typeof options.stop === "function"){ options.stop(current); } } // Определение события dragstart this.addEventListener("dragstart", function (event){ // Запуск события start if(typeof options.start === "function"){ options.start(current); } // Сохранение текущего и следующего элементов списка current = event.target; following = current.nextSibling; this.addEventListener("dragover", dragging); this.addEventListener("dragend", drop); current.classList.add("place"); }); }
Последней частью js-скрипта будет функция сбора информации о текущей последовательности элементов списка, и ее отправки для сохранение в базе по событию update:
function sending (container) { // Создание объекта и запись в него идентификаторов и позиции каждого элемента в списке var sendData = new FormData(); for (var i = 0; i < container.children.length; i++) { sendData.append(container.children[i].getAttribute("data-id"), (i+1)); } // Отправка запроса xhp = getXmlHttp(); xhp.open("POST", "/set.php", true); xhp.onreadystatechange = function() { if (xhp.readyState == 4) { if(xhp.status == 200) { // … } else { alert("Error!"); } } }; xhp.send(sendData); }
Ниже представлено содержание php-файла, отвечающего за обновление последовательности.
<? include_once './db.php'; $query = "UPDATE items SET number=:number WHERE id=:id"; $sth = $db->prepare($query); foreach ($_POST as $key => $value) { $sth->execute(array(":number" => $value, ":id" => $key)); }
Если Вас интересует более расширенная сортировка, то имеется урок на тему сортировка на PHP и MySQL, посмотрите, может это то что Вам нужно! На этом урок наш урок окончен. Спасибо за внимание!