這幾天在開發中遇到一個事情,做一個導出的功能,但是后臺是新來的菜鳥,等了三天沒反應,接口做不出來,我內心一萬個。。。。,于是乎我就打算前端做導出了,網上復制了一些代碼就出來了。
// npm
npm install -S file-saver xlsx
npm install -D script-loader
復制代碼
首先拷貝以下兩個文件代碼: Export2Excel.js
/* eslint-disable */
require('script-loader!file-saver');
require('script-loader!vendor/Blob');
require('script-loader!xlsx/dist/xlsx.core.min');
function generateArray(table) {
var out=[];
var rows=table.querySelectorAll('tr');
var ranges=[];
for (var R=0; R < rows.length; ++R) {
var outRow=[];
var row=rows[R];
var columns=row.querySelectorAll('td');
for (var C=0; C < columns.length; ++C) {
var cell=columns[C];
var colspan=cell.getAttribute('colspan');
var rowspan=cell.getAttribute('rowspan');
var cellValue=cell.innerText;
if (cellValue !=="" && cellValue==+cellValue) cellValue=+cellValue;
//Skip ranges
ranges.forEach(function (range) {
if (R >=range.s.r && R <=range.e.r && outRow.length >=range.s.c && outRow.length <=range.e.c) {
for (var i=0; i <=range.e.c - range.s.c; ++i) outRow.push(null);
}
});
//Handle Row Span
if (rowspan || colspan) {
rowspan=rowspan || 1;
colspan=colspan || 1;
ranges.push({s: {r: R, c: outRow.length}, e: {r: R + rowspan - 1, c: outRow.length + colspan - 1}});
}
;
//Handle Value
outRow.push(cellValue !=="" ? cellValue : null);
//Handle Colspan
if (colspan) for (var k=0; k < colspan - 1; ++k) outRow.push(null);
}
out.push(outRow);
}
return [out, ranges];
};
function datenum(v, date1904) {
if (date1904) v +=1462;
var epoch=Date.parse(v);
return (epoch - new Date(Date.UTC(1899, 11, 30))) / (24 * 60 * 60 * 1000);
}
function sheet_from_array_of_arrays(data, opts) {
var ws={};
var range={s: {c: 10000000, r: 10000000}, e: {c: 0, r: 0}};
for (var R=0; R !=data.length; ++R) {
for (var C=0; C !=data[R].length; ++C) {
if (range.s.r > R) range.s.r=R;
if (range.s.c > C) range.s.c=C;
if (range.e.r < R) range.e.r=R;
if (range.e.c < C) range.e.c=C;
var cell={v: data[R][C]};
if (cell.v==null) continue;
var cell_ref=XLSX.utils.encode_cell({c: C, r: R});
if (typeof cell.v==='number') cell.t='n';
else if (typeof cell.v==='boolean') cell.t='b';
else if (cell.v instanceof Date) {
cell.t='n';
cell.z=XLSX.SSF._table[14];
cell.v=datenum(cell.v);
}
else cell.t='s';
ws[cell_ref]=cell;
}
}
if (range.s.c < 10000000) ws['!ref']=XLSX.utils.encode_range(range);
return ws;
}
function Workbook() {
if (!(this instanceof Workbook)) return new Workbook();
this.SheetNames=[];
this.Sheets={};
}
function s2ab(s) {
var buf=new ArrayBuffer(s.length);
var view=new Uint8Array(buf);
for (var i=0; i !=s.length; ++i) view[i]=s.charCodeAt(i) & 0xFF;
return buf;
}
export function export_table_to_excel(id) {
var theTable=document.getElementById(id);
console.log('a')
var oo=generateArray(theTable);
var ranges=oo[1];
/* original data */
var data=oo[0];
var ws_name="SheetJS";
console.log(data);
var wb=new Workbook(), ws=sheet_from_array_of_arrays(data);
/* add ranges to worksheet */
// ws['!cols']=['apple', 'banan'];
ws['!merges']=ranges;
/* add worksheet to workbook */
wb.SheetNames.push(ws_name);
wb.Sheets[ws_name]=ws;
var wbout=XLSX.write(wb, {bookType: 'xlsx', bookSST: false, type: 'binary'});
saveAs(new Blob([s2ab(wbout)], {type: "application/octet-stream"}), "test.xlsx")
}
function formatJson(jsonData) {
console.log(jsonData)
}
export function export_json_to_excel(th, jsonData, defaultTitle) {
/* original data */
var data=jsonData;
data.unshift(th);
var ws_name="SheetJS";
var wb=new Workbook(), ws=sheet_from_array_of_arrays(data);
/* add worksheet to workbook */
wb.SheetNames.push(ws_name);
wb.Sheets[ws_name]=ws;
var wbout=XLSX.write(wb, {bookType: 'xlsx', bookSST: false, type: 'binary'});
var title=defaultTitle || '列表'
saveAs(new Blob([s2ab(wbout)], {type: "application/octet-stream"}), title + ".xlsx")
}
復制代碼
Blob.js
(function (view) {
"use strict";
view.URL=view.URL || view.webkitURL;
if (view.Blob && view.URL) {
try {
new Blob;
return;
} catch (e) {}
}
// Internally we use a BlobBuilder implementation to base Blob off of
// in order to support older browsers that only have BlobBuilder
var BlobBuilder=view.BlobBuilder || view.WebKitBlobBuilder || view.MozBlobBuilder || (function(view) {
var
get_class=function(object) {
return Object.prototype.toString.call(object).match(/^\[object\s(.*)\]$/)[1];
}
, FakeBlobBuilder=function BlobBuilder() {
this.data=[];
}
, FakeBlob=function Blob(data, type, encoding) {
this.data=data;
this.size=data.length;
this.type=type;
this.encoding=encoding;
}
, FBB_proto=FakeBlobBuilder.prototype
, FB_proto=FakeBlob.prototype
, FileReaderSync=view.FileReaderSync
, FileException=function(type) {
this.code=this[this.name=type];
}
, file_ex_codes=(
"NOT_FOUND_ERR SECURITY_ERR ABORT_ERR NOT_READABLE_ERR ENCODING_ERR "
+ "NO_MODIFICATION_ALLOWED_ERR INVALID_STATE_ERR SYNTAX_ERR"
).split(" ")
, file_ex_code=file_ex_codes.length
, real_URL=view.URL || view.webkitURL || view
, real_create_object_URL=real_URL.createObjectURL
, real_revoke_object_URL=real_URL.revokeObjectURL
, URL=real_URL
, btoa=view.btoa
, atob=view.atob
, ArrayBuffer=view.ArrayBuffer
, Uint8Array=view.Uint8Array
;
FakeBlob.fake=FB_proto.fake=true;
while (file_ex_code--) {
FileException.prototype[file_ex_codes[file_ex_code]]=file_ex_code + 1;
}
if (!real_URL.createObjectURL) {
URL=view.URL={};
}
URL.createObjectURL=function(blob) {
var
type=blob.type
, data_URI_header
;
if (type===null) {
type="application/octet-stream";
}
if (blob instanceof FakeBlob) {
data_URI_header="data:" + type;
if (blob.encoding==="base64") {
return data_URI_header + ";base64," + blob.data;
} else if (blob.encoding==="URI") {
return data_URI_header + "," + decodeURIComponent(blob.data);
} if (btoa) {
return data_URI_header + ";base64," + btoa(blob.data);
} else {
return data_URI_header + "," + encodeURIComponent(blob.data);
}
} else if (real_create_object_URL) {
return real_create_object_URL.call(real_URL, blob);
}
};
URL.revokeObjectURL=function(object_URL) {
if (object_URL.substring(0, 5) !=="data:" && real_revoke_object_URL) {
real_revoke_object_URL.call(real_URL, object_URL);
}
};
FBB_proto.append=function(data/*, endings*/) {
var bb=this.data;
// decode data to a binary string
if (Uint8Array && (data instanceof ArrayBuffer || data instanceof Uint8Array)) {
var
str=""
, buf=new Uint8Array(data)
, i=0
, buf_len=buf.length
;
for (; i < buf_len; i++) {
str +=String.fromCharCode(buf[i]);
}
bb.push(str);
} else if (get_class(data)==="Blob" || get_class(data)==="File") {
if (FileReaderSync) {
var fr=new FileReaderSync;
bb.push(fr.readAsBinaryString(data));
} else {
// async FileReader won't work as BlobBuilder is sync
throw new FileException("NOT_READABLE_ERR");
}
} else if (data instanceof FakeBlob) {
if (data.encoding==="base64" && atob) {
bb.push(atob(data.data));
} else if (data.encoding==="URI") {
bb.push(decodeURIComponent(data.data));
} else if (data.encoding==="raw") {
bb.push(data.data);
}
} else {
if (typeof data !=="string") {
data +=""; // convert unsupported types to strings
}
// decode UTF-16 to binary string
bb.push(unescape(encodeURIComponent(data)));
}
};
FBB_proto.getBlob=function(type) {
if (!arguments.length) {
type=null;
}
return new FakeBlob(this.data.join(""), type, "raw");
};
FBB_proto.toString=function() {
return "[object BlobBuilder]";
};
FB_proto.slice=function(start, end, type) {
var args=arguments.length;
if (args < 3) {
type=null;
}
return new FakeBlob(
this.data.slice(start, args > 1 ? end : this.data.length)
, type
, this.encoding
);
};
FB_proto.toString=function() {
return "[object Blob]";
};
FB_proto.close=function() {
this.size=this.data.length=0;
};
return FakeBlobBuilder;
}(view));
view.Blob=function Blob(blobParts, options) {
var type=options ? (options.type || "") : "";
var builder=new BlobBuilder();
if (blobParts) {
for (var i=0, len=blobParts.length; i < len; i++) {
builder.append(blobParts[i]);
}
}
return builder.getBlob(type);
};
}(typeof self !=="undefined" && self || typeof window !=="undefined" && window || this.content || this));
復制代碼
因為我們在Export2Excel.js中設置的Blob路徑為vendor,所以我們要在src下建立相關文件夾并放入這兩個js。
假設我們需要導出一個這樣的表格
數據
// data
dataList: [
{ name: "張明", loginTime: 16, id: 1, department: "生產部", sex: "男" },
{ name: "小金", loginTime: 11, id: 2, department: "生產部", sex: "女" },
{ name: "小凌", loginTime: 21, id: 3, department: "生產部", sex: "男" },
{ name: "蓋倫", loginTime: 5, id: 4, department: "測試部", sex: "男" }
]
復制代碼
html
<table border>
<tr>
<th>ID</th>
<th>名稱</th>
<th>登陸次數</th>
<th>部門</th>
</tr>
<tr v-for="item in dataList" :key="item.id">
<td>{{ item.id }}</td>
<td>{{ item.name }}</td>
<td>{{ item.loginTime }}</td>
<td>{{ item.department }}</td>
</tr>
</table>
<button @click="exportExcel">導出信息</button>
復制代碼
methods
// 導出excel
exportExcel() {
// 引入文件
const { export_json_to_excel }=require("vendor/Export2Excel.js");
// 表頭
const tHeader=["ID", "名稱", "登陸次數", "部門"];
// table表格中對應的屬性名
const filterVal=["id", "name", "loginTime", "department"];
// 表格綁定數據轉json
const data=this.formatJson(filterVal, this.dataList);
export_json_to_excel(
tHeader,
data,
"部門登陸信息" + new Date().toLocaleDateString()
); // 對應下載文件的名字
},
// 導出列表格式化數據的方法
formatJson(filterVal, jsonData) {
return jsonData.map(v=> filterVal.map(j=> v[j]));
}
復制代碼
展示效果
到此,前端導出功能實現。這種方式的優勢在于:1.不用請求后端獲取文件。2.所見即所得,前端可有靈活地把控輸出的數據,不用因為導出的數據有差錯而拉著后端一起聯調。
我們可能有時候會遇到對Excel多sheet的操作,比如部門的多季度績效分多sheet導出。
我們需要在Export2Excel.js中添加一個方法:
/**
* 多sheet導出
* @param {Array} th 表頭
* @param {Array} jsonDatas 數據集
* @param {String} defaultTitle 導出的excel名稱
* @param {Array} sheetNames sheet名稱集
*/
export function export_season_to_excel(th, jsonDatas, defaultTitle, sheetNames) {
var wb=new Workbook()
jsonDatas.forEach((item, index)=> {
var data=item;
data.unshift(th);
var ws_name=sheetNames[index];
var ws=sheet_from_array_of_arrays(data);
/* add worksheet to workbook */
wb.SheetNames.push(ws_name);
wb.Sheets[ws_name]=ws;
})
var wbout=XLSX.write(wb, {
bookType: 'xlsx',
bookSST: false,
type: 'binary'
});
var title=defaultTitle || '列表'
saveAs(new Blob([s2ab(wbout)], {
type: "application/octet-stream"
}), title + ".xlsx")
}
復制代碼
頁面中的data內容:
// data 季度績效數據
seasonDatas: [
[
{ name: "張明", score: 72 },
{ name: "小金", score: 21 },
{ name: "小凌", score: 16 },
{ name: "蓋倫", score: 84 }
],
[
{ name: "張明", score: 32 },
{ name: "小金", score: 54 },
{ name: "小凌", score: 45 },
{ name: "蓋倫", score: 26 }
],
[
{ name: "張明", score: 67 },
{ name: "小金", score: 87 },
{ name: "小凌", score: 45 },
{ name: "蓋倫", score: 78 }
],
[
{ name: "張明", score: 54 },
{ name: "小金", score: 34 },
{ name: "小凌", score: 26 },
{ name: "蓋倫", score: 34 }
]
]
復制代碼
html
<div class="season">
<template v-for="(item, index) in seasonDatas">
<div :key="index">
{{ `第${index + 1}季度績效` }}
<table border>
<tr>
<th>名稱</th>
<th>績效分</th>
</tr>
<tr v-for="(scoreItem, scoreindex) in item" :key="scoreindex">
<td>{{ scoreItem.name }}</td>
<td>{{ scoreItem.score }}</td>
</tr>
</table>
</div>
</template>
</div>
<button @click="exportSeason">導出績效信息</button>
復制代碼
執行方法
// methods 導出績效信息excel
exportSeason() {
// 引入文件
const { export_season_to_excel }=require("vendor/Export2Excel.js");
// 表頭
const tHeader=["名稱", "績效分"];
// table表格中對應的屬性名
const filterVal=["name", "score"];
let datas=[];
let sheets=[];
this.seasonDatas.forEach((item, index)=> {
// 表格綁定數據轉json
datas.push(this.formatJson(filterVal, item));
sheets.push(`第${index + 1}季度績效`);
});
export_season_to_excel(
tHeader,
datas,
"部門季度績效" + new Date().toLocaleDateString(),
sheets
); // 對應下載文件的名字
},
復制代碼
展示效果:
至此,多Sheet導出我們也完成了。
項目地址:https://github.com/FireSmallPanda/vuexDemo.git
在文章發出后大家對大數據導出和怎么自定義表頭存在疑惑,我這邊設置了一個可以自定義導出規模的例子。
html部分
<p><input type="number" v-model="rows" />行</p>
<p><input type="number" v-model="cols" />列</p>
<button @click="outPutBigData">導出自定義大小表格信息</button>
復制代碼
js部分
// data
rows: 100, // 行
cols: 100 // 列
// methods
// 導出自定義數據
outPutBigData() {
// 引入文件
const { export_json_to_excel }=require("vendor/Export2Excel.js");
// 表頭
let tHeader=[];
// table表格中對應的屬性名
let filterVal=[];
// 需要導出的內容
let pushData=[];
// 自定義生成列
for (let i=0; i < this.cols * 1; i++) {
tHeader.push(`第${i + 1}列數據`);
filterVal.push(i);
}
// 生成自定義數據
for (let j=0; j < this.rows * 1; j++) {
let pushObj={};
for (let i=0; i < this.cols * 1; i++) {
// 這邊為展示數據不一致性設置為隨機數
pushObj[i]=Math.random();
}
// 插入一條數據
pushData.push(pushObj);
}
// ---至此模擬后端請求數據結束---
// 表格綁定數據轉json
const data=this.formatJson(filterVal, pushData);
export_json_to_excel(
tHeader,
data,
"自定義導出數據" + new Date().toLocaleDateString()
); // 對應下載文件的名字
},
復制代碼
演示效果:
為方便大家直觀的看到,我們這次導出10000行10列的隨機數據.可以看到,其中的列名稱我也是自動生成的。
作者:有趣的老凌
鏈接:https://juejin.cn/post/7030291455243452429
來源:稀土掘金
著作權歸作者所有。商業轉載請聯系作者獲得授權,非商業轉載請注明出處。
年(Light Year Admin)后臺管理系統模板是一個基于Bootstrap v3.3.7的純HTML模板。
作為后端開發人員,自己在做一些簡單系統時,經常為了后臺的模板煩惱,國內的少,也不太喜歡tab形式的;國外的又太復雜;vue什么框架的又不會用,因而想自己整理出來一個簡單點的通用后臺模板,結合自己的使用和國外模板的配色、細節處理,這就有了光年后臺模板。
簡潔而清新的后臺模板,功能雖少,倒也滿足簡單的后臺功能,也能夠快速上手,希望大家支持。
特別感謝
登錄頁面
后臺首頁
開關樣式
文檔列表
東優就業
頁面傳值小技巧
平常我們在做的web項目,一般一個HTML頁面上會有好幾個步驟,step_num①,step_num②,step_num③,一般先顯示step_num①,根據跳轉條件顯示step_num②,step_num①隱藏,再跳轉step_num③,step_num①,step_num②隱藏,step_num③顯示。
思路: (js設置全局變量,哪里需要在哪里添加一個input標簽,把值賦給一個input,然后再讓input隱藏)。
廣東優就業
先說下這個頁面的結構,進入xxx.html頁面,通過js發送ajax.postForm請求,請求一個action,action調用handler,每一個功能都要請求一個action。
廣東優就業
前兩天就是這樣的一個頁面,然后在傳值的時候就碰到了一個讓人腦仁疼的問題,需要在step_num①中顯示和未顯示的值,傳到step_num③對應的后臺Java代碼,試了好幾種方法都不好用,最后,采用了一個小技巧
在js中先設一個全局變量,比如var groupID=" "; ,然后把從step_num①中從后臺action傳過來的GroupID賦給groupID,怎么傳給頁面三對應的Java后臺呢?
現在step_num③對應的HTML代碼中寫上這樣一條語句:<input id="chuanzhi" name="chuanzhi" type="hidden"/>然后在對應的js代碼中把 $("#chuanzhi").val(groupID);
這樣你在step_num③對應的Java后臺中就可以通過request.getParameter("chuanzhi"); 獲得你想要的groupID了
更多IT精彩內容推薦:http://www.ujiuye.com/guangdong/?wt.mc_id=17009338
*請認真填寫需求信息,我們會在24小時內與您取得聯系。