MIS 腳印 logo

MIS 腳印

記錄 IT 學習的軌跡

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

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

JavaScript 表格拖放排序 AJAX 資料庫 for PHP
線上範例 下載範例

HTML 拖放操作 API

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

HTML5 定義了很多有用的 APIs,而 Drag 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>
    </tbody>
</table>

JavaScript

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

  • 變更 CSS 樣式與元素的排序
  • 放開元素時,AJAX 當前所有 ID 的排序,讓後續 PHP 更新資料庫使用
/*
 * 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);

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
        ));
    }
}

參考

在〈JavaScript 表格拖放排序 AJAX 資料庫 for PHP〉中有 6 則留言

  1. 這個程式很好用,但是在firefox上無法拖曳,應如何解決。我的firefox是V62.0版。

    • 您可能需先確認 Firefox:
      1. 版本是否支援 Drag and Drop API。
      2. 使用瀏覽器控制台查看顯示的 Error 訊息。

      • 爬了一些文章匯整如下:
        在javascript中加入
        function dragstart_handler(ev) {
        //console.log("dragStart");
        ev.dataTransfer.setData("text", ev.target.id);
        ev.effectAllowed = "copyMove";

        另外在被拖曳的元素上除了draggable="true"還需加上ondragstart="dragstart_handler(event);",不加ondragstart在firefox中無法拖曳。

        感謝您提供這麼好的程式,並熱心的指導。

發表迴響