最近筆者終于把H5-Dooring的后臺管理系統初步搭建完成, 有了初步的數據采集和數據分析能力, 接下來我們就復盤一下其中涉及的幾個知識點,并一一闡述其在Dooring H5可視化編輯器中的解決方案. 筆者將分成3篇文章來復盤, 主要解決場景如下: 如何使用JavaScript實現前端導入和導出excel文件(H5編輯器實戰復盤) 前端如何基于table中的數據一鍵生成多維度數據可視化分析報表 * 如何實現會員管理系統下的權限路由和權限菜單
以上場景也是前端工程師在開發后臺管理系統中經常遇到的或者即將遇到的問題, 本文是上述介紹中的第一篇文章, 你將收獲: 使用JavaScript實現前端導入excel文件并自動生成可編輯的Table組件 使用JavaScript實現前端基于Table數據一鍵導出excel文件 * XLSX和js-export-excel基本使用
本文接下來的內容素材都是基于H5可視化編輯器(H5-Dooring)項目的截圖, 如果想實際體驗, 可以訪問H5-Dooring網站實際體驗. 接下來我們直接開始我們的方案實現.
在開始實現之前, 我們先來看看實現效果.
導入excel文件并通過antd的table組件渲染table:
編輯table組件:
保存table數據后實時渲染可視化圖表:
以上就是我們實現導入excel文件后, 編輯table, 最后動態生成圖表的完整流程.
導入excel文件的功能我們可以用javascript原生的方式實現解析, 比如可以用fileReader這些原生api,但考慮到開發效率和后期的維護, 筆者這里采用antd的Upload組件和XLSX來實現上傳文件并解析的功能. 由于我們采用antd的table組件來渲染數據, 所以我們需要手動將解析出來的數據轉換成table支持的數據格式.大致流程如下:
所以我們需要做的就是將Upload得到的文件數據傳給xlsx, 由xlsx生成解析對象, 最后我們利用javascript算法將xlsx的對象處理成ant-table支持的數據格式即可. 這里我們用到了FileReader對象, 目的是將文件轉化為BinaryString, 然后我們就可以用xlsx的binary模式來讀取excel數據了, 代碼如下:
// 解析并提取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 draftObj = {}
sheetNames.forEach(name => {
// 通過工作表名稱來獲取指定工作表
let worksheet = workbook.Sheets[name];
for(let key in worksheet) {
// v是讀取單元格的原始值
if(key[0] !== '!') {
if(draftObj[key[0]]) {
draftObj[key[0]].push(worksheet[key].v)
}else {
draftObj[key[0]] = [worksheet[key].v]
}
}
}
});
// 生成ant-table支持的數據格式
let sourceData = Object.values(draftObj).map((item,i) => ({ key: i + '', name: item[0], value: item[1]}))
經過以上處理, 我們得到的sourceData即是ant-table可用的數據結構, 至此我們就實現了表格導入的功能.
table表格的編輯功能實現其實也很簡單, 我們只需要按照antd的table組件提供的自定義行和單元格的實現方式即可. antd官網上也有實現可編輯表格的實現方案, 如下:
大家感興趣的可以研究一下. 當然自己實現可編輯的表格也很簡單, 而且有很多方式, 比如用column的render函數來動態切換表格的編輯狀態, 或者使用彈窗編輯等都是可以的.
根據table數據動態生成圖表這塊需要有一定的約定, 我們需要符合圖表庫的數據規范, 不過我們有了table數據, 處理數據規范當然是很簡單的事情了, 筆者的可視化庫采用antv的f2實現, 所以需要做一層適配來使得f2能消費我們的數據.
還有一點就是為了能使用多張圖表, 我們需要對f2的圖表進行統一封裝, 使其成為符合我們應用場景的可視化組件庫.
我們先看看f2的使用的數據格式:
const data = [
{ genre: 'Sports', sold: 275 },
{ genre: 'Strategy', sold: 115 },
{ genre: 'Action', sold: 120 },
{ genre: 'Shooter', sold: 350 },
{ genre: 'Other', sold: 150 }
];
此數據格式會渲染成如下的圖表:
所以說我們總結下來其主要有2個緯度的指標, 包括它們的面積圖, 餅圖, 折線圖, 格式都基本一致, 所以我們可以基于這一點封裝成組件的可視化組件, 如下:
import { Chart } from '@antv/f2';
import React, { memo, useEffect, useRef } from 'react';
import ChartImg from '@/assets/chart.png';
import styles from './index.less';
import { IChartConfig } from './schema';
interface XChartProps extends IChartConfig {
isTpl: boolean;
}
const XChart = (props: XChartProps) => {
const { isTpl, data, color, size, paddingTop, title } = props;
const chartRef = useRef(null);
useEffect(() => {
if (!isTpl) {
const chart = new Chart({
el: chartRef.current || undefined,
pixelRatio: window.devicePixelRatio, // 指定分辨率
});
// step 2: 處理數據
const dataX = data.map(item => ({ ...item, value: Number(item.value) }));
// Step 2: 載入數據源
chart.source(dataX);
// Step 3:創建圖形語法,繪制柱狀圖,由 genre 和 sold 兩個屬性決定圖形位置,genre 映射至 x 軸,sold 映射至 y 軸
chart
.interval()
.position('name*value')
.color('name');
// Step 4: 渲染圖表
chart.render();
}
}, [data, isTpl]);
return (
<div className={styles.chartWrap}>
<div className={styles.chartTitle} style={{ color, fontSize: size, paddingTop }}>
{title}
</div>
{isTpl ? <img src={ChartImg} alt="dooring chart" /> : <canvas ref={chartRef}></canvas>}
</div>
);
};
export default memo(XChart);
當然其他的可視化組件也可以用相同的模式封裝,這里就不一一舉例了. 以上的組件封裝使用react的hooks組件, vue的也類似, 基本原理都一致.
同樣的, 我們實現將table數據一鍵導出為excel也是類似, 不過方案有所不同, 我們先來看看在Dooring中的實現效果.
以上就是用戶基于后臺采集到的數據, 一鍵導出excel文件的流程, 最后一張圖是生成的excel文件在office軟件中的呈現.
一鍵導出功能主要用在H5-Dooring的后臺管理頁面中, 為用戶提供方便的導出數據能力. 我們這里導出功能也依然能使用xlsx來實現, 但是綜合對比了一下筆者發現有更簡單的方案, 接下來筆者會詳細介紹, 首先我們還是來看一下流程:
很明顯我們的導出流程比導入流程簡單很多, 我們只需要將table的數據格式反編譯成插件支持的數據即可. 這里筆者使用了js-export-excel來做文件導出, 使用它非常靈活,我們可以自定義: 自定義導出的excel文件名 自定義excel的過濾字段 * 自定義excel文件中每列的表頭名稱
由于js-export-excel支持的數據結構是數組對象, 所以我們需要花點功夫把table的數據轉換成數組對象, 其中需要注意的是ant的table數據結構中鍵對應的值可以是數組, 但是js-export-excel鍵對應的值是字符串, 所以我們要把數組轉換成字符串,如[a,b,c]變成'a,b,c', 所以我們需要對數據格式進行轉換, 具體實現如下:
const generateExcel = () => {
let option = {}; //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 = 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文件
}
注意, 以上筆者實現的方案對任何table組件都使用, 可直接使用以上代碼在大多數場景下使用. 至此, 我們就實現了使用JavaScript實現前端導入和導出excel文件的功能.
所以, 今天你又博學了嗎?
以上教程筆者已經集成到H5-Dooring中,對于一些更復雜的交互功能,通過合理的設計也是可以實現的,大家可以自行探索研究。
地址:H5-Dooring | 一款強大的H5編輯器
如果想學習更多H5游戲, webpack,node,gulp,css3,javascript,nodeJS,canvas數據可視化等前端知識和實戰,歡迎在《趣談前端》一起學習討論,共同探索前端的邊界。
有天老板找我到辦公室跟我說要做一個商城,商城賣出去東西就有傭金可以拿。我聽著就頭大。老板打開電腦給我看了網站:你看一下這個網站,照著它的流程就可以擁有一個商城了。我靠過去一看,大概了解一下:原來是利用第三方工具就可以構建一個導購網站,只要消費者在網站領取優惠券就會自動跳轉到某bao的購買頁面,購買成功后就可以有傭金了。我看了一下覺得可以,只要不讓我敲代碼一切好說。于是我照著流程構建了一個網站,然后勾選了很多零食進行推廣,然后我就發現了一個問題:我只勾選了一些零食啊,商城怎么還有其它類型的商品?我思索了一下就明白了,這網站還是挺流氓的,還摻雜著其他人的推廣鏈接,我一想這樣不行,轉化率肯定低啊。果不其然,試用了一天就只有5個單子,因為公司的網站還是挺有流量的,所以這轉化率不可能這么低。老板看了一下,覺得沒什么用讓我把商城入口給關了,我只好照做,但是我心里對這流氓網站不服啊,于是我打算自己做一個導購網站。(最后還是要敲代碼(。?_?)/~~~)
1. 安裝xlrd
cmd窗口: pip install xlrd
2.創建index.py,導入模塊
import xlrd
3.打開Excel文件讀取數據
wb= xlrd.open_workbook('文件路徑')
4.獲取表格
sheet1 = wb.sheet_by_index(0) #這里的excel文檔內只有一個表格,0代表第一個
5.獲取表格的行數
rows = sheet1.nrows
6.獲取表格中的類目
商品一級類目
住宅家具
影音電器
影音電器
美容護膚
廚房電器
運動服/休閑服裝
餐飲具
category0 = sheet1.col_values(4) #獲取列內容(類目),這里excel文檔的第四列是類目 del category0[0] #刪除列表中的 "商品一級類目" category = sorted(set(category0),key=category0.index) #類目列表->去除重復
7.整理數據
[ [ 分類名, [商品信息] ], [ 分類名, [商品信息] ] ] data = [] for i,v in enumerate(category): data.append([v,[]]) for i,v in enumerate(data): for x in range(rows): if v[0] == sheet1.cell(x,4).value: data[i][1].append(sheet1.row_values(x))
8.導出json文件
jsonData = json.dumps(data, ensure_ascii=False) with open('results.json', 'w',encoding="utf-8") as f: f.write(jsonData)
9.運行index.py,獲得json文件
cmd窗口:python index.py
10.創建html頁面,并引用json文件
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <script src="http://libs.baidu.com/jquery/2.0.0/jquery.min.js"></script> <script>//引用jquery $(function(){ function color16(){//十六進制顏色隨機 var r = Math.floor(Math.random()*256); var g = Math.floor(Math.random()*256); var b = Math.floor(Math.random()*256); var color = '#'+r.toString(16)+g.toString(16)+b.toString(16); return color; } var navo = '';//類目導航 var info = '';//商品內容 $.get('./results.json', function(data) {//請求json文件 $.each(data, function(index, val) { navo+="<a href='#"+val[0]+"''>"+val[0]+"</a> " });//把json文件中的類目數組遍歷出來,并用錨定位 $.each(data, function(index, val) { var div_title = "<div id='"+val[0]+"' style='float:left;'>"; var div_content = ""; $.each(val[1], function(index, val) { div_content+="<div style='background:"+color16()+"' onclick=\"location.href=\'"+val[21]+"\'\" class='pro_img'>"+val[1]+"<span class='money'>¥"+val[6]+"</span><\/div>" }); var div_footer ="</div><br>"; info+=div_title+div_content+div_footer }); $('#nav').html(navo);//把導航顯示出來 $('#content').html(info);//把商品顯示出來 },'json'); }) </script> <style> #content{ margin-top: 10px } .money{ position: absolute; left: 0; bottom: 0; height: 30px; line-height: 30px; color: #e22a40; font-weight: 700 } .pro_img{ position: relative; float: left; width: 220px; height: 220px; line-height: 220px; text-align: center; border: 1px solid #eee; cursor: pointer; font-size: 30px; white-space:normal; overflow:hidden; /*超過部分不顯示*/ text-overflow:ellipsis; /*超過部分用點點表示*/ white-space:nowrap;*//*不換行 } </style> </head> <body> <div id="nav"></div> <div id="content"></div> </body> </html>
https://fjxasdf.github.io/daogou (github比較卡)
目開發中遇到導入表格常見的就是excel和csv 格式,一般情況下我們會前端首先得到這個表格里面的數據,然后再把數據發送給后端,也有的是直接上傳文件傳給后臺后臺自己處理,這樣就不好控制上傳前預覽和處理數據,如果不需要預覽直接上傳的需求,那還是直接上傳文件交給后臺處理,本文實例是基于vue+elementu-ui 表格去實現。
https://www.papaparse.com/
1.安裝
*請認真填寫需求信息,我們會在24小時內與您取得聯系。