JavaScript 表格拖放排序 AJAX 資料庫 for PHP

說明如何使用原生 JavaScript 的 HTML5 Drap and Drop API(拖放操作 API),進行表格拖放排序,且搭配 AJAX 與 PHP 來同步更新資料庫,達到即時排序功能,並提供線上與下載範例。

drag-sort-ajax-php

線上範例 下載範例

HTML 拖放操作 API

之前要讓網頁有拖放功能,通常都需使用 jQuery Plugin(例如 Table Drag and Drop jQuery plugin)來完成。

HTML5 定義了很多有用的 APIs,而 Drap and Drop API(拖放操作 API)是其中一個,可用它來拖放網頁元素。

程式解說

針對程式的主要部分與運作原理說明。

HTML

除了文字、圖片或超連結,預設可拖拉外,其它元素要可以拖拉必須設定 draggable="true" 屬性。

如果要讓 <tr> 元素可進行拖拉:

<table id="draggable">
    <thead>
        <tr>
            <th>ID</th>
            <th>Sort</th>
            <th>Name</th>
            <th>Height</th>
            <th>Weight</th>
        </tr>
    </thead>
    <tbody>
        <tr class="data" draggable="true">
            <td class="id">1</td>
            <td class="sort">0</td>
            <td>Jacky</td>
            <td>172</td>
            <td>54</td>
        </tr>
        <tr class="data" draggable="true">
            <td class="id">2</td>
            <td class="sort">1</td>
            <td>Kevin</td>
            <td>175</td>
            <td>60</td>
        </tr>
        <tr class="data" draggable="true">
            <td class="id">3</td>
            <td class="sort">2</td>
            <td>Mary</td>
            <td>164</td>
            <td>45</td>
        </tr>
        <tr class="data" draggable="true">
            <td class="id">4</td>
            <td class="sort">3</td>
            <td>Carri</td>
            <td>160</td>
            <td>52</td>
        </tr>
        <tr class="data" draggable="true">
            <td class="id">5</td>
            <td class="sort">4</td>
            <td>Kay</td>
            <td>167</td>
            <td>48</td>
        </tr>
    </tbody>
</table>

JavaScript

使用者對網頁元素進行拖放操作時:

  • 變更 CSS 樣式與元素的排序
  • 放開元素時,AJAX 當前所有 ID 的排序,讓後續 PHP 更新資料庫使用
    使用 jQuery 的 AJAX 功能
<script type="text/javascript">
/*
 * HTML Drag and Drop API(拖、放操作 API)
 */
var dragged;  // 保存拖動元素的引用(ref.),就是拖動元素本身

// 當開始拖動一個元素或一個選擇文本的時候 dragstart 事件就會觸發(設定拖動資料和拖動用的影像,且當從 OS 拖動檔案進入瀏覽器時不會觸發)
document.addEventListener('dragstart', function(event) {
    dragged = event.target;
    event.target.style.backgroundColor = 'rgba(240, 240, 240, 0.5)';
    event.target.style.color = 'rgba(255, 255, 255, 0.5)';
}, false);

// 不論結果如何,拖動作業結束當下,被拖動元素都會收到一個 dragend 事件(當從 OS 拖動檔案進入瀏覽器時不會觸發)
document.addEventListener('dragend', function(event) {
    // 重置樣式
    event.target.style.backgroundColor = '#222222';
    event.target.style.color = '#ffffff';
}, false);

// 當一個元素或者文本被拖動到有效放置目標 dragover 事件就會一直觸發(每隔幾百毫秒)
// 絕大多數的元素預設事件都不准丟放資料,所以想要丟放資料到元素上,就必須取消預設事件行為
// 取消預設事件行為能夠藉由呼叫 event.preventDefault 方法
document.addEventListener('dragover', function(event) {
    // 阻止預設事件行為
    event.preventDefault();
}, false);

// 當拖動的元素或者文本進入一個有效的放置目標 dragenter 事件就會觸發
document.addEventListener('dragenter', function(event) {
    // 當拖動的元素進入可放置的目標(自訂符合條件),變更背景顏色
    // 自訂條件:class 名稱 && 不是本身的元素
    if (event.target.parentNode.className == 'data' &&
        dragged !== event.target.parentNode) {
        dragged.style.background = 'purple';

        // 判斷向下或向上拖動,來決定在元素前或後插入元素
        if (dragged.rowIndex < event.target.parentNode.rowIndex) {
            event.target.parentNode.parentNode.insertBefore(dragged, event.target.parentNode.nextSibling);
        }
        else {
            event.target.parentNode.parentNode.insertBefore(dragged, event.target.parentNode);
        }
    }
}, false);

// 當拖動的元素或者文本離開有效的放置目標 dragleave 事件就會觸發
document.addEventListener('dragleave', function(event) {
    // 當拖動元素離開可放置目標節點,重置背景
    // 自訂條件:class 名稱 && 不是本身的元素
    if (event.target.parentNode.className == 'data' &&
        dragged !== event.target.parentNode) {
        // 當拖動元素離開可放置目標節點,重置背景
        event.target.parentNode.style.background = '';
    }
}, false);

// 當丟放拖動元素到拖拉目標區時 drop 事件就會觸發;此時事件處理器可能會需要取出拖拉資料並處理之
// 這個事件只有在被允許下才會觸發,如果在使用者取消拖拉操作時,如按 ESC 鍵或滑鼠不是在拖拉目標元素上,此事件不會觸發
document.addEventListener('drop', function(event) {
    /*
     * AJAX Update DB
     */
    var id = document.querySelectorAll('.id');
    var data = [];  // 儲存所有 ID
    
    for (var i = 0, len = id.length; i < len; i++) {
        // 取得所有 ID 並存為 array
        data.push(id[i].innerHTML);
        // 重新排序表格 Sort 數值
        id[i].parentNode.querySelector('.sort').innerHTML = i;
    }

    // jQuery AJAX
    $.get('ajax.php', {"data": data});
}, false);
</script>

PHP

接收 AJAX 過來的 ID,並依順序重新排序資料庫裡所有資料的更新。

<?php
/**
 * AJAX 更新排序
 */

if (isset($_REQUEST['data'])) {
    // PDO 連結
    include_once 'pdo-conn.php';

    $sql = 'UPDATE drag_drop
            SET sort = :sort
            WHERE ID = :ID';

    $stmt = $dbConn->prepare($sql);

    // 更新所有資料排序
    foreach ($_REQUEST['data'] as $key => $value) {
        $stmt->execute(array(
            'sort'  => $key,
            'ID'    => $value
        ));
    }
}

線上範例 下載範例

發表迴響