這一章我們要實現(xiàn)是一個網(wǎng)格組件,該組件除了最基本的數(shù)據(jù)展示功能外,還提供排序以及數(shù)據(jù)過濾功能。
創(chuàng)新互聯(lián)專業(yè)為企業(yè)提供神木網(wǎng)站建設(shè)、神木做網(wǎng)站、神木網(wǎng)站設(shè)計、神木網(wǎng)站制作等企業(yè)網(wǎng)站建設(shè)、網(wǎng)頁設(shè)計與制作、神木企業(yè)網(wǎng)站模板建站服務(wù),10余年神木做網(wǎng)站經(jīng)驗,不只是建網(wǎng)站,更提供有價值的思路和整體網(wǎng)絡(luò)服務(wù)。
數(shù)據(jù)源
為了測試我們即將編寫好網(wǎng)格組件,我們采用如下格式的數(shù)據(jù)源。此數(shù)據(jù)源包含兩部分的內(nèi)容,分別是表頭數(shù)據(jù)集和表體數(shù)據(jù)集。網(wǎng)格組件實例最終的列數(shù)由表頭數(shù)據(jù)集的長度決定。
var data = { gridColumns: ['name', 'power'], gridData: [ { name: 'Chuck Norris', power: Infinity }, { name: 'Bruce Lee', power: 9000 }, { name: 'Jackie Chan', power: 7000 }, { name: 'Jet Li', power: 8000 } ] };
頂層設(shè)計
從視覺上,我們很自然地把網(wǎng)格組件劃分為表頭與表體。此網(wǎng)格組件有三個功能,所以應(yīng)該提供三個動態(tài)接口。但我們注意到排序功能是通過點擊表頭進(jìn)行的,而表頭屬于網(wǎng)格組件的一部分,所以該功能應(yīng)該內(nèi)置。從而,實際上我們的網(wǎng)格組件對外只暴露兩個動態(tài)接口:一個用于過濾,另一個用于接收數(shù)據(jù)源。所以我們可以得到如下的一個頂層設(shè)計。
DataGrid: { xml: `
設(shè)計表頭
表頭只有一行,所以可以直接給它提供一個 tr 元素。tr 元素的子級項 th 的個數(shù)取決于表頭數(shù)據(jù)集的長度,所以需要動態(tài)創(chuàng)建。由于 th 元素包含了排序功能,所以需要另行封裝。下面是我們給出的表頭的設(shè)計。
Thead: { xml: ``, fun: function (sys, items, opts) { function setValue(value) { sys.tr.children().call("remove"); data.forEach(item => sys.tr.append("Th").value().val(item)); } return { val: setValue }; } }
表頭數(shù)據(jù)項組件提供一個文本設(shè)置接口。該組件本身并不負(fù)責(zé)排序,它只完成自身視圖狀態(tài)的變更以及排序命令的派發(fā)。排序命令的派發(fā)需要攜帶兩個數(shù)據(jù):一個是排序關(guān)鍵字,也就是表頭文本;另一個排序方向,升或者降。
Th: { css: "#active { color: #fff; } #active #arrow { opacity: 1; } #active #key { color: #fff; }\ #arrow { display: inline-block; vertical-align: middle; width: 0; height: 0; margin-left: 5px; opacity: 0.66; }\ #asc { border-left: 4px solid transparent; border-right: 4px solid transparent; border-bottom: 4px solid #fff;}\ #dsc { border-left: 4px solid transparent; border-right: 4px solid transparent; border-top: 4px solid #fff; }", xml: "\ \ ", fun: function (sys, items, opts) { var order = "#asc"; this.watch("sort", function (e, key, order) { sys.key.text().toLowerCase() == key || sys.th.removeClass("#active"); }); this.on("click", function (e) { sys.th.addClass("#active"); sys.arrow.removeClass(order); order = order == "#asc" ? "#dsc" : "#asc"; sys.arrow.addClass(order).notify("sort", [sys.key.text().toLowerCase(), order]); }); sys.arrow.addClass("#asc"); return { val: sys.key.text }; } }
設(shè)計表體
表體可以有多行,但表體只負(fù)責(zé)展示數(shù)據(jù),所以實現(xiàn)起來比表頭要簡單的多。
Tbody: { xml: ``, fun: function (sys, items, opts) { function setValue(gridColumns, gridData) { sys.tbody.children().call("remove"); gridData.forEach(data => tr = sys.tbody.append("tr"); gridColumns.forEach(key => tr.append("td").text(data[key])); )); } return { val: setValue }; } }
加入排序功能
為了便于管理,我們把排序功能單獨封裝成一個組件,該組件提供一個排序接口,同時偵聽一個排序消息。一旦接收到排序消息,則記錄下關(guān)鍵字與排序方向,并派發(fā)一個表體刷新命令。
Sort: { fun: function (sys, items, opts) { var sortKey, sortOrder; this.watch("sort", function (e, key, order) { sortKey = key, sortOrder = order; this.trigger("update"); }); return function (data) { return sortKey ? data.slice().sort(function (a, b) { a = a[sortKey], b = b[sortKey]; return (a === b ? 0 : a > b ? 1 : -1) * (sortOrder == "#asc" ? 1 : -1); }) : data; }; } }
要完整地實現(xiàn)排序功能,對組件 DataGrid 作一些修正,主要是內(nèi)置上述的排序功能組件并偵聽表體刷新指令。一旦接收到刷新指令,則對表體數(shù)據(jù)完成排序并刷新表體。
DataGrid: { xml: `
加入過濾功能
與排序功能的加入流程類似,我們把過濾功能單獨封裝成一個組件,該組件提供一個過濾接口,同時偵聽一個過濾消息。一旦接收到消息,則記錄下過濾關(guān)鍵字,并派發(fā)一個表體刷新命令。
Filter: { fun: function (sys, items, opts) { var filterKey = ""; this.watch("filter", function (e, key) { filterKey = key.toLowerCase(); this.trigger("update"); }); return function (data) { return data.filter(function (row) { return Object.keys(row).some(function (key) { return String(row[key]).toLowerCase().indexOf(filterKey) > -1; }); }); }; } }
另外需要對組件 DataGrid 作一些修正,修正內(nèi)容與上述的排序功能的加入類似,區(qū)別在于額外完善了 filter 接口以及對消息作用域進(jìn)行了限制。下面是我們最終的網(wǎng)格組件。
DataGrid: { css: `#table { border: 2px solid #42b983; border-radius: 3px; background-color: #fff; } #table th { background-color: #42b983; color: rgba(255,255,255,0.66); cursor: pointer; -webkit-user-select: none; -moz-user-select: none; -ms-user-select: none; user-select: none; } #table td { background-color: #f9f9f9; } #table th, #table td { min-width: 120px; padding: 10px 20px; }`, xml: `
值得注意的是這里一定要在映射項中配置限制消息作用域的選項。否則,當(dāng)在一個應(yīng)用中實例化多個網(wǎng)格組件時,消息就會互相干擾。
測試
最后我們來測試下我們完成的組件,測試的功能主要就是剛開始提到的三個:數(shù)據(jù)展示、排序以及過濾。
Index: { css: "#index { font-family: Helvetica Neue, Arial, sans-serif; font-size: 14px; color: #444; }\ #search { margin: 8px 0; }", xml: "\ Search \", fun: function (sys, items, opts) { items.table.val(data); sys.search.on("input", e => items.table.filter(sys.search.prop("value"))); } }\
本系列文章基于 xmlplus 框架。如果你對 xmlplus 沒有多少了解,可以訪問 www.xmlplus.cn。這里有詳盡的入門文檔可供參考。
以上就是本文的全部內(nèi)容,希望對大家的學(xué)習(xí)有所幫助,也希望大家多多支持創(chuàng)新互聯(lián)。