在管理後臺中咱們會使用大量的表格表單組件, 導入導出各類報表, 有些場景還須要對報表數據進行可視化分析, 動態生成可視化圖表, 筆者將基於以上場景, 總結一些實用的 Table 組件開發技巧, 讓前端開發再也不吃力.javascript
以上是幾個經常使用的業務分場景, 接下來筆者帶你們一一實現.css
通常咱們渲染表格, 大多數是預先將表格結構寫好, 比先定義好columns
再向後端請求數據填充表格, 以下:前端
const columns = [
{
title: '姓名',
dataIndex: 'name',
key: 'name',
},
{
title: '年齡',
dataIndex: 'age',
key: 'age',
},
{
title: '住址',
dataIndex: 'address',
key: 'address',
},
];
const dataSource = [
{
key: '1',
name: '徐小夕',
age: 18,
address: '杭州夕湖區',
}
];
<Table dataSource={dataSource} columns={columns} />
複製代碼
這種業務場景雖然能夠知足大部分後臺管理系統的Table
需求, 也可使用 antd 或者 element 構建, 可是對於 lowcode
系統而言, 不少模塊都是不肯定的, 咱們須要根據協議和數據來驅動 Table 的渲染.vue
好比咱們在 H5-Dooring 中配置了一個表單, 咱們要統計分析表單的數據, 因爲表單項是不肯定的, 因此咱們沒法提早定義好一個 table schema. java
那如何來動態渲染這個 Table 呢? 這裏給你們提供一個思路, 基於數據驅動 + 協議層約束. 相似於國外 SAP 的 低代碼平臺, 徹底基於 odata 協議, 咱們能夠約束表單的提交數據格式, 而後結合用戶提交的數據, 動態提取出 Table 所需的 columns, 最後再渲染 Table 組件.node
協議層主要約束不一樣字段的展現類型, 好比字符串, 按鈕, 連接, 標籤等, 用戶在提交表單以後會攜帶協議層對應的 flag 和用戶輸入的值, 這有利於咱們解析器渲染Table時能夠對不一樣的列展現不一樣的類型. 以下: react
筆者這裏簡單實現一個demo
, 以下:webpack
// table數據源
let tableData = res.map((item:any,i:number) => ({ ID: nanoid(8), ...item }));
let baseRow = tableData[0],
keys = Object.keys(baseRow);
setColumns(() => {
const baseColumn = keys.map(item => {
return {
title: item,
dataIndex: item,
key: item,
width: item === 'ID' ? 0 : null,
render: (v:any) => {
if(typeof v === 'object') {
return <> { v.map(item => <Tag color="#2F54EB">{ item.label || item }</Tag>) } </>
}
return item === 'ID' ? '' : v
}
}
})
baseColumn.push({
title: '操做',
key: 'operation',
fixed: 'right',
width: 100,
render: (row) => <a onClick={() => handleDel(row)}>刪除</a>,
})
return baseColumn
})
複製代碼
以上咱們就實現了一個動態 Table 渲染方案, 案例中使用了 react, 你們也可使用熟悉的 vue3.0.css3
Table 排序, 多列排序實現方式也很簡單, 咱們只須要自定義 Table 頭部, 對排序字段提高爲 Table 的公共 State
, 最後經過排序標識和排序方法進行排序便可. 目前 antd4.0已經支持多列排序, 你們能夠直接參考學習便可, 以下: 對於自定義搜索, 也就是文章開頭的 demo 展現的列搜索, 咱們能夠採用以下方案實現:git
const getColumnSearchProps = dataIndex => ({
filterDropdown: ({ setSelectedKeys, selectedKeys, confirm, clearFilters }) => (
<div style={{ padding: 8 }}> <Input ref={node => { searchInput = node; }} placeholder={`Search ${dataIndex}`} value={selectedKeys[0]} onChange={e => setSelectedKeys(e.target.value ? [e.target.value] : [])} onPressEnter={() => handleSearch(selectedKeys, confirm, dataIndex)} style={{ width: 188, marginBottom: 8, display: 'block' }} /> <Space> <Button type="primary" onClick={() => handleSearch(selectedKeys, confirm, dataIndex)} icon={<SearchOutlined />} size="small" style={{ width: 90 }} > 搜索 </Button> <Button onClick={() => handleReset(clearFilters)} size="small" style={{ width: 90 }}> 重置 </Button> </Space> </div>
),
filterIcon: filtered => <SearchOutlined style={{ color: filtered ? '#1890ff' : undefined }} />,
onFilter: (value, record) =>
record[dataIndex]
? record[dataIndex].toString().toLowerCase().includes(value.toLowerCase())
: '',
onFilterDropdownVisibleChange: visible => {
if (visible) {
setTimeout(() => searchInput.select(), 100);
}
},
render: text =>
searchedColumn === dataIndex ? (
<Highlighter highlightStyle={{ backgroundColor: '#ffc069', padding: 0 }} searchWords={[searchText]} autoEscape textToHighlight={text ? text.toString() : ''} />
) : (
text
),
});
複製代碼
此時咱們只須要對動態生成的columns
每一列添加自定義頭部便可:
{
title: item,
dataIndex: item,
key: item,
...getColumnSearchProps(item)
}
複製代碼
antd4.0 中也有詳細的使用方式, 這裏筆者就不一一介紹了, 效果以下: 你們也能夠在 H5-Dooring 的管理後臺中查看具體效果.
在不少數據分析後臺中咱們須要處理不少電子表格, 用傳統的excel手動錄入的方式將慢慢被淘汰. 好比不一樣渠道方收集到了不少業務數據, 整理到 excel 中, 那如何快速保存到本身的後臺系統中呢? 通常的思路以下:
第一種方案因爲效率過低, 適合C端用戶手動錄入, 咱們暫時忽略, 筆者將實現一下第三種方案. 實現思路以下:
這裏咱們用到了 XLSX
這個庫, 結合 FileReader API. 咱們經過FileReader
拿到excel
文件的二進制數據, 而後傳給 XLSX
解析成 js object
, 最後經過筆者寫的 table 渲染器生成符合規範的table
數據結構. 源碼以下:
// 解析並提取excel數據
let reader = new FileReader();
reader.onload = function(e) {
let data = e.target.result;
let workbook = XLSX.read(data, {type: 'binary'});
let sheetNames = workbook.SheetNames; // 工做表名稱集合
let draftArr = {}
sheetNames.forEach(name => {
let worksheet = workbook.Sheets[name]; // 只能經過工做表名稱來獲取指定工做表
for(let key in worksheet) {
// v是讀取單元格的原始值
if(key[0] !== '!') {
if(draftArr[key[0]]) {
draftArr[key[0]].push(worksheet[key].v)
}else {
draftArr[key[0]] = [worksheet[key].v]
}
}
}
});
// 獲得table合法的數據產物
const sourceData = Object.values(draftArr);
}
reader.readAsBinaryString(file);
複製代碼
拿到合法的table
數據源以後咱們就能夠進行第一節說的動態渲染 Table 的邏輯了.
經過以上的方式, 咱們能夠實現任何結構的excel
表格的導入. 在導入後咱們能夠自動發送請求存儲到咱們的業務後臺中.
相似的, 上面咱們介紹了將 excel 導入 table, 一樣咱們也能夠將Table 導出爲 excel, 進行數據的分發, 本地化, 好比咱們最近流行的在線文檔等應用. 筆者這裏簡單講一下實現思路:
也就是咱們第3節說的反解析. excel 文件生成筆者採用 js-export-excel 這個庫, 基於它筆者實現了一個開箱即用的方法, 避免你們燒腦造輪子. 以下:
import ExportJsonExcel from 'js-export-excel';
const generateExcel = () => {
let option:any = {}; //option表明的就是excel文件
let dataTable = []; //excel文件中的數據內容
let len = list.length;
if (len) {
for(let i=0; i<len; i++) {
let row = list[i];
let obj:any = {};
for(let key in row) {
if(typeof row[key] === 'object') {
let arr:any = row[key];
obj[key] = arr.map((item:any) => (typeof item === 'object' ? item.label : item)).join(',')
}else {
obj[key] = row[key]
}
}
dataTable.push(obj); //設置excel中每列所獲取的數據源
}
}
let tableKeys = Object.keys(dataTable[0]);
option.fileName = tableName; //excel文件名稱
option.datas = [
{
sheetData: dataTable, //excel文件中的數據源
sheetName: tableName, //excel文件中sheet頁名稱
sheetFilter: tableKeys, //excel文件中需顯示的列數據
sheetHeader: tableKeys, //excel文件中每列的表頭名稱
}
]
let toExcel = new ExportJsonExcel(option); //生成excel文件
toExcel.saveExcel(); //下載excel文件
}
複製代碼
在後臺管理系統和 BI 平臺中咱們會遇到不少數據分析和報表展現的需求, 接下來筆者未來介紹一下如何基於 Table 數據動態生成多維度可視化分析報表.
筆者在以前的文章中介紹過 度量行這個概念, 對於數據分析而言, 咱們也要考慮可分析維度的概念, 好比什麼是可分析的, 什麼是不可分析的. 好比咱們又一個表格, 裏面有以下結構: 對於聯繫方式而言, 它是不可度量的, 即分析該項指沒有任何價值, 因此在自動生成多維度分析中咱們理論上不因該分析它, 基於這個原理, 咱們來設計一個簡單的自動生成多維度可視化報表的方案.
咱們針對具備範圍屬性的維度進行度量, 生成度量數據, 代碼以下:
const generateDistData = (key:string, list:any) => {
let distDataMap:any = {},
distData = []
list.forEach((item:any) => {
// 當前緯度的類別
let curKey = typeof item[key] === 'object' ? item[key][0].label : item[key];
if(distDataMap[curKey]) {
distDataMap[curKey]++;
}else {
distDataMap[curKey] = 1;
}
})
// 生成目標數組
for(let key in distDataMap) {
distData.push({name: key, value: distDataMap[key]})
}
return distData
}
複製代碼
此時咱們只須要根據維度的字段, 便可獲取某一維度的數據值, 後經過可視化組件渲染便可.
咱們用@ant-design/charts
, 代碼以下:
<div className={styles.anazlyHeader}>
<div className={styles.anazlyItem}> <span>分析緯度: </span> <Select style={{ width: 120 }} onChange={(v) => handleAnazlyChange(0, v)} defaultValue={keys[0]}> { keys.map((item,i) => { return <Option value={item} key={i}>{ item }</Option> }) } </Select> </div>
</div>
<div className={styles.anazlyContent}> { !!config && <Pie {...config} /> } </div>
複製代碼
實現效果以下:
實現 Table 編輯器其實筆者在 前端如何一鍵生成多維度數據可視化分析報表 已經詳細分析過了,也集成在了H5-Dooring 的可視化組件編輯器中, 具體 demo
以下:
你們感興趣能夠研究一下.
目前筆者也在持續更新H5編輯器 H5-Dooring, 最近來同步一下功能:
以爲有用 ?喜歡就收藏,順便點個贊吧,你的支持是我最大的鼓勵!微信搜 「趣談前端」,發現更多有趣的H5遊戲, webpack,node,gulp,css3,javascript,nodeJS,canvas數據可視化等前端知識和實戰.