Уроки Сортировка перетаскиванием
28 декабря 2013
4562
cортировка перетаскиванием, JavaScript, PHP, MySQL, sortable, drag

Сортировка перетаскиванием

Сложность Рубрика PHP
Демонстрация » Скачать »

Здравствуйте! В данном уроке я покажу, как можно реализовать сортировку перетаскиванием с последующим сохранением порядка элементов в базу данных. Хотелось бы заметить, что данная тематика уже раньше поднималась, но она была 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, посмотрите, может это то что Вам нужно! На этом урок наш урок окончен. Спасибо за внимание!





Евгений Болдырев