jQuery DataTables 的幾個坑,非同步載入(伺服器)、監聽、過載等等

至天發表於2018-04-04

  今天真的被這破外掛氣瘋了,於是有了下面的截圖。此文不定期更新,要是有新坑歡迎來填。

jQuery DataTables 的幾個坑,監聽、過載等等

看看截圖娛樂娛樂

圖1

圖2

圖3

圖4

好了,正事兒要緊,先來說說這玩意兒的載入過程

  1. 首先必不可少的 jQueryDataTables.jsDataTables.css 的引入略過

  2. 我們先手寫好一張 table 表格,大概就像下面這樣

    <!-- 我就寫簡單點,去掉了所有 class,根據樣式自己新增 -->
    <table id="user-list">
        <thead>
            <tr>
                <th>ID</th>
                <th>賬號</th>
                <th>使用者組</th>
                <th>賬號狀態</th>
                <th>新增時間</th>
                <th>操作</th>
            </tr>
        </thead>
        <!-- tbody 這兒留空,依靠 Ajax 返回的資料填充 -->
        <tbody></tbody>
    </table>
    
  3. 來吧,先大概寫個 JS

    說一下,下方的一些引數,大家在網上可能經常看到 ab 開頭的寫法,那是舊式寫法,當然是不影響使用的,推薦用新駝峰寫法。對應表:Datatables | 升級 | 1.10.x與1.9.x引數名對照表

    // 根據上面的 HTML 程式碼操作,上方已定義 table 的 id 為 user-list
    var table = $('#user-list');
    table.dataTable({
    	/**
    	 * 分頁的幾個顯示方式,大致翻譯一下
    	 * `numbers` - 僅含頁碼按鈕
    	 * `simple` - 僅含“上一頁”和“下一頁”
    	 * 'simple_numbers` - “上一頁”和“下一頁”,加上頁碼
    	 * `full` - “首頁”,“上一頁”,“下一頁”,“尾頁”按鈕
    	 * `full_numbers` - “首頁”,“上一頁”,“下一頁”,“尾頁”按鈕以及頁碼
    	 * `first_last_numbers` - “首頁”和“尾頁”按鈕,加上頁碼
    	 */
    	pagingType: 'full_numbers', // 所以這兒我用了 full_numbers
    	lengthMenu: [10, 15, 20],   // 可選每頁顯示數量
    	serverSide: true, // 服務端分頁
        searching: true,  // 過濾功能
        ordering: true,   // 排序功能
        columnDefs: [{
            orderable: false,
            targets: [1, 2, 5] // 指定不排序列,下標 0(比如 ID,從 0 開始數,此處帳號、使用者組和操作不能排序)
        }],
        language: {
            url: '/assets/js/plugins/datatables/Chinese.json' // 語言檔案,下方會貼出來
        },
        ajax: {
            url: '',     // 非同步請求地址,沒啥好說的
            type: 'get', // 請求方式,因為是取資料,所以我選擇了 get
            data: ''     // 額外請求引數,一般是不需要的
        },
        // 暫時先寫這部分,下部分再慢慢道來
    });
    
  4. 官方對於伺服器端的說明在這兒:伺服器處理(server-side) 手冊 Datatables 中文網

    當然了,愛看不看…從“伺服器需要返回的資料(Returned data)”這一段(上方連結帶上了錨點,訪問即可到達),我們可以看到服務端需要返回什麼資料:

    型別 簡述
    aw integer\\|JS
    cordsTotal integer\\|JS
    cordsFiltered integer\\|JS
    ta array\\|Type
    error string\\|JS
    - -
    DT_RowId string\\|JS
    DT_RowClass string\\|JS
    DT_RowData object\\|JS
    DT_RowAttr object\\|JS
    - -
  5. 通過上方表格的簡述,我們知道了 DataTables 需要從服務端返回什麼資料,下面就是一個簡單的資料格式返回,程式碼為~~“拍黃片”~~ PHP

    // 假設我們已經從資料庫拿到使用者列表並存入了變數 $userList
    // 在這兒先對資料進行一次處理,便於前端顯示
    foreach ($userList as $key => $val) {
        $userList[$key]['DT_RowClass'] = "text-center"; // 可忽略這個
        $userList[$key]['add_time'] = date('Y-m-d H:i', $val['add_time']); // 格式化時間
        $userList[$key]['operate'] = [ // 解釋一下這個,因為我們 HTML 中最後一列是操作,含有編輯和刪除功能,資料庫肯定是沒有這個相關資料的,我們模擬一個 `operate` 列出來。放入 ID 是因為我們編輯和刪除需要這貨啊!
            'id' => $val['id']
        ];
    }
    $data = [
        // 前面說了這個按照接收資料來返回,為了防止 XSS 攻擊
        // 我這兒就沒詳寫,因為我用 Laravel 框架這兒直接 $request->draw
        'draw' => 1,
        // 使用者資料存入 data
        'data' => $userList,
        // 總記錄數(不過濾)
        'recordsTotal' => $count, // 實際有多少就是多少
        // 記錄數(已過濾)
        'recordsFiltered' => $filteredCount // 經過檢索/過濾後的
    ];
    if (!$userList) {
        $data['error'] = '這兒什麼也沒有';
    }
    // 實際上...在 Laravel 框架中直接 return $data 會自動變成 Json,嘿...嘿嘿嘿
    return json_encode($data);
    

    這兒再說一下排序,我是這麼做的。還是愛看不看

    // 依舊是 Laravel 框架,$request->order 這個可以看成 _GET['order']
    // 接收請求拿到 DataTables 傳過來的 order
    $order = $request->order;
    // 將排序欄位名和值組合成新陣列
    $order = [
        $request->columns[$order[0]['column']]['data'] 
    	    => $order[0]['dir']];
    // 此時的 $order 是一個陣列,形式為 id => desc
    // 在寫取資料方法的時候建議給 $order 一個預設值
    
  6. 現在資料拿到了,再來處理處理第 3 步未完成的 JS

    // 其實也就是再加一個 columns。注意下方程式碼和第 3 步是銜接的
    columns: [
    	// 這裡 data 後的值如果 SQL 語句正常預設就是欄位名
    	{data: 'id'},
    	{data: 'username'},
    	{   // 這裡也是一段重要的說明,如下程式碼,我資料庫內 status 狀態存的數字
    		// 在這兒總不能顯示 0 和 1 吧?我們需要通過 render 方法來執行一些資料處理
    		// 當然也可以加一些樣式在這個地方,文章末尾會有截圖可供參考
    		data: 'status', render: function (data) {
    			var content;
    			switch (data) {
    				case 0:
    					content = '已禁用';
    					break;
    				case 1:
    					content = '正常';
    					break;
    				case -1:
    					content = '已刪除';
    					break;
    			}
    			return content;
    		}
    	},
    	{data: 'add_time'},
    	{
    		// 對了,前文的額外引數 DT_RowData,在下行 function 括號內的第三個引數可以獲取。
    		// 當然我前面並沒有傳入這個資料,所以下行的 type 和 row 並未使用,可刪除
    		data: 'operate', render: function (data, type, row) {
    			// TODO: return(string);
    			/*
    			 這裡的程式碼我就不寫上來了,關於操作前面說了就是兩個按鈕,一個編輯一個刪除
    			 每個人的樣式不一樣,而我前面的 PHP 程式碼裡給 data 傳了一個 ID
    			 此處可以通過 data.id 得到其值
    			 類似這樣:return '<button data-id="' + data.id + '"></button>';
    			 至此,資料已經可以拿到併成功顯示啦!
    			 */ 
    		}
    	}
    ]
    

    低調上圖:(文中精簡了不少東西嘛,使用 BootStrap 樣式更佳哦~)
    成功截圖

Emmm…一不小心就把這貨寫清楚了

這兒說說我遇到的幾個坑:

  • 首先第一個!不要去重複 table.dataTable({});。不然就是一個彈框提示你無法重新初始化,頂部圖1的由來。

  • 前文說到我的最後一列是兩個按鈕,我嘗試過用 $('table tbody button').click(); 的方式,根本監聽不了,最後發現要用 on,也就是

    // table 為之前用於初始化 DataTables 的那個,等於上文已存入 table 變數的 $('#user-list') 
    // tbody 這個可以不要,個人習慣精確定位
    // on 後面的第一個引數為事件引數,什麼 touch 啊,click 啊之類
    // 第二個就是重點,精確到你要監聽事件的控制元件、標籤。例如我要監聽按鈕就寫 tr button
    // 第三個匿名函式沒什麼好說的
    table.find('tbody').on('click', 'tr button', function (){
    	// TODO: ...
    	var $this = $(this); // 可以拿到當前操作的物件
    });
    
  • 再就是所有的 API!必須使用 table.api() 呼叫

    我最開始看文件的示例:重新載入資料(ajax.reload()) 選項(option) 參考(reference) Datatables 中文網
    MD!這裡面根本沒寫 api() 好嗎,最後在 Google 搜尋到這篇:table.ajax.reload() is undefined — DataTables forums 才解決…哎!
    當然不帶 api() 的方法是把 DataTables 初始程式碼存入變數,直接使用那個變數就無需 $('#table').api() 這樣的形式使用,例如:

    var table = $('#table').DataTable({
    	// TODO: 各種配置
    });
    table.ajax.reload();
    
  • 還有…待更吧…


差點忘了中文支援:(非官方,有小修改。官方在這兒 Chinese - DataTables

{
    "sProcessing": "處理中...",
    "sLengthMenu": "顯示 _MENU_ 項結果",
    "sZeroRecords": "沒有相應內容",
    "sInfo": "顯示第 _START_ 至 _END_ 項結果,共 _TOTAL_ 項",
    "sInfoEmpty": "顯示第 0 至 0 項結果,共 0 項",
    "sInfoFiltered": "(由 _MAX_ 項結果過濾)",
    "sInfoPostFix": "",
    "sSearch": "搜尋:",
    "sUrl": "",
    "sEmptyTable": "表中資料為空",
    "sLoadingRecords": "載入中...",
    "sInfoThousands": ",",
    "oPaginate": {
        "sFirst": "首頁",
        "sPrevious": "上頁",
        "sNext": "下頁",
        "sLast": "末頁"
    },
    "oAria": {
        "sSortAscending": ": 以升序排列此列",
        "sSortDescending": ": 以降序排列此列"
    }
}

相關文章