Warning: error_log(/data/www/wwwroot/hmttv.cn/caches/error_log.php): failed to open stream: Permission denied in /data/www/wwwroot/hmttv.cn/phpcms/libs/functions/global.func.php on line 537 Warning: error_log(/data/www/wwwroot/hmttv.cn/caches/error_log.php): failed to open stream: Permission denied in /data/www/wwwroot/hmttv.cn/phpcms/libs/functions/global.func.php on line 537
這幾天在開發(fā)中遇到一個(gè)事情,做一個(gè)導(dǎo)出的功能,但是后臺(tái)是新來的菜鳥,等了三天沒反應(yīng),接口做不出來,我內(nèi)心一萬個(gè)。。。。,于是乎我就打算前端做導(dǎo)出了,網(wǎng)上復(fù)制了一些代碼就出來了。
// npm
npm install -S file-saver xlsx
npm install -D script-loader
復(fù)制代碼
首先拷貝以下兩個(gè)文件代碼: 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")
}
復(fù)制代碼
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));
復(fù)制代碼
因?yàn)槲覀冊(cè)贓xport2Excel.js中設(shè)置的Blob路徑為vendor,所以我們要在src下建立相關(guān)文件夾并放入這兩個(gè)js。
假設(shè)我們需要導(dǎo)出一個(gè)這樣的表格
數(shù)據(jù)
// data
dataList: [
{ name: "張明", loginTime: 16, id: 1, department: "生產(chǎn)部", sex: "男" },
{ name: "小金", loginTime: 11, id: 2, department: "生產(chǎn)部", sex: "女" },
{ name: "小凌", loginTime: 21, id: 3, department: "生產(chǎn)部", sex: "男" },
{ name: "蓋倫", loginTime: 5, id: 4, department: "測試部", sex: "男" }
]
復(fù)制代碼
html
<table border>
<tr>
<th>ID</th>
<th>名稱</th>
<th>登陸次數(shù)</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">導(dǎo)出信息</button>
復(fù)制代碼
methods
// 導(dǎo)出excel
exportExcel() {
// 引入文件
const { export_json_to_excel }=require("vendor/Export2Excel.js");
// 表頭
const tHeader=["ID", "名稱", "登陸次數(shù)", "部門"];
// table表格中對(duì)應(yīng)的屬性名
const filterVal=["id", "name", "loginTime", "department"];
// 表格綁定數(shù)據(jù)轉(zhuǎn)json
const data=this.formatJson(filterVal, this.dataList);
export_json_to_excel(
tHeader,
data,
"部門登陸信息" + new Date().toLocaleDateString()
); // 對(duì)應(yīng)下載文件的名字
},
// 導(dǎo)出列表格式化數(shù)據(jù)的方法
formatJson(filterVal, jsonData) {
return jsonData.map(v=> filterVal.map(j=> v[j]));
}
復(fù)制代碼
展示效果
到此,前端導(dǎo)出功能實(shí)現(xiàn)。這種方式的優(yōu)勢(shì)在于:1.不用請(qǐng)求后端獲取文件。2.所見即所得,前端可有靈活地把控輸出的數(shù)據(jù),不用因?yàn)閷?dǎo)出的數(shù)據(jù)有差錯(cuò)而拉著后端一起聯(lián)調(diào)。
我們可能有時(shí)候會(huì)遇到對(duì)Excel多sheet的操作,比如部門的多季度績效分多sheet導(dǎo)出。
我們需要在Export2Excel.js中添加一個(gè)方法:
/**
* 多sheet導(dǎo)出
* @param {Array} th 表頭
* @param {Array} jsonDatas 數(shù)據(jù)集
* @param {String} defaultTitle 導(dǎo)出的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")
}
復(fù)制代碼
頁面中的data內(nèi)容:
// data 季度績效數(shù)據(jù)
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 }
]
]
復(fù)制代碼
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">導(dǎo)出績效信息</button>
復(fù)制代碼
執(zhí)行方法
// methods 導(dǎo)出績效信息excel
exportSeason() {
// 引入文件
const { export_season_to_excel }=require("vendor/Export2Excel.js");
// 表頭
const tHeader=["名稱", "績效分"];
// table表格中對(duì)應(yīng)的屬性名
const filterVal=["name", "score"];
let datas=[];
let sheets=[];
this.seasonDatas.forEach((item, index)=> {
// 表格綁定數(shù)據(jù)轉(zhuǎn)json
datas.push(this.formatJson(filterVal, item));
sheets.push(`第${index + 1}季度績效`);
});
export_season_to_excel(
tHeader,
datas,
"部門季度績效" + new Date().toLocaleDateString(),
sheets
); // 對(duì)應(yīng)下載文件的名字
},
復(fù)制代碼
展示效果:
至此,多Sheet導(dǎo)出我們也完成了。
項(xiàng)目地址:https://github.com/FireSmallPanda/vuexDemo.git
在文章發(fā)出后大家對(duì)大數(shù)據(jù)導(dǎo)出和怎么自定義表頭存在疑惑,我這邊設(shè)置了一個(gè)可以自定義導(dǎo)出規(guī)模的例子。
html部分
<p><input type="number" v-model="rows" />行</p>
<p><input type="number" v-model="cols" />列</p>
<button @click="outPutBigData">導(dǎo)出自定義大小表格信息</button>
復(fù)制代碼
js部分
// data
rows: 100, // 行
cols: 100 // 列
// methods
// 導(dǎo)出自定義數(shù)據(jù)
outPutBigData() {
// 引入文件
const { export_json_to_excel }=require("vendor/Export2Excel.js");
// 表頭
let tHeader=[];
// table表格中對(duì)應(yīng)的屬性名
let filterVal=[];
// 需要導(dǎo)出的內(nèi)容
let pushData=[];
// 自定義生成列
for (let i=0; i < this.cols * 1; i++) {
tHeader.push(`第${i + 1}列數(shù)據(jù)`);
filterVal.push(i);
}
// 生成自定義數(shù)據(jù)
for (let j=0; j < this.rows * 1; j++) {
let pushObj={};
for (let i=0; i < this.cols * 1; i++) {
// 這邊為展示數(shù)據(jù)不一致性設(shè)置為隨機(jī)數(shù)
pushObj[i]=Math.random();
}
// 插入一條數(shù)據(jù)
pushData.push(pushObj);
}
// ---至此模擬后端請(qǐng)求數(shù)據(jù)結(jié)束---
// 表格綁定數(shù)據(jù)轉(zhuǎn)json
const data=this.formatJson(filterVal, pushData);
export_json_to_excel(
tHeader,
data,
"自定義導(dǎo)出數(shù)據(jù)" + new Date().toLocaleDateString()
); // 對(duì)應(yīng)下載文件的名字
},
復(fù)制代碼
演示效果:
為方便大家直觀的看到,我們這次導(dǎo)出10000行10列的隨機(jī)數(shù)據(jù).可以看到,其中的列名稱我也是自動(dòng)生成的。
作者:有趣的老凌
鏈接:https://juejin.cn/post/7030291455243452429
來源:稀土掘金
著作權(quán)歸作者所有。商業(yè)轉(zhuǎn)載請(qǐng)聯(lián)系作者獲得授權(quán),非商業(yè)轉(zhuǎn)載請(qǐng)注明出處。
年(Light Year Admin)后臺(tái)管理系統(tǒng)模板是一個(gè)基于Bootstrap v3.3.7的純HTML模板。
作為后端開發(fā)人員,自己在做一些簡單系統(tǒng)時(shí),經(jīng)常為了后臺(tái)的模板煩惱,國內(nèi)的少,也不太喜歡tab形式的;國外的又太復(fù)雜;vue什么框架的又不會(huì)用,因而想自己整理出來一個(gè)簡單點(diǎn)的通用后臺(tái)模板,結(jié)合自己的使用和國外模板的配色、細(xì)節(jié)處理,這就有了光年后臺(tái)模板。
簡潔而清新的后臺(tái)模板,功能雖少,倒也滿足簡單的后臺(tái)功能,也能夠快速上手,希望大家支持。
特別感謝
登錄頁面
后臺(tái)首頁
開關(guān)樣式
文檔列表
東優(yōu)就業(yè)
頁面?zhèn)髦敌〖记?/span>
平常我們?cè)谧龅膚eb項(xiàng)目,一般一個(gè)HTML頁面上會(huì)有好幾個(gè)步驟,step_num①,step_num②,step_num③,一般先顯示step_num①,根據(jù)跳轉(zhuǎn)條件顯示step_num②,step_num①隱藏,再跳轉(zhuǎn)step_num③,step_num①,step_num②隱藏,step_num③顯示。
思路: (js設(shè)置全局變量,哪里需要在哪里添加一個(gè)input標(biāo)簽,把值賦給一個(gè)input,然后再讓input隱藏)。
廣東優(yōu)就業(yè)
先說下這個(gè)頁面的結(jié)構(gòu),進(jìn)入xxx.html頁面,通過js發(fā)送ajax.postForm請(qǐng)求,請(qǐng)求一個(gè)action,action調(diào)用handler,每一個(gè)功能都要請(qǐng)求一個(gè)action。
廣東優(yōu)就業(yè)
前兩天就是這樣的一個(gè)頁面,然后在傳值的時(shí)候就碰到了一個(gè)讓人腦仁疼的問題,需要在step_num①中顯示和未顯示的值,傳到step_num③對(duì)應(yīng)的后臺(tái)Java代碼,試了好幾種方法都不好用,最后,采用了一個(gè)小技巧
在js中先設(shè)一個(gè)全局變量,比如var groupID=" "; ,然后把從step_num①中從后臺(tái)action傳過來的GroupID賦給groupID,怎么傳給頁面三對(duì)應(yīng)的Java后臺(tái)呢?
現(xiàn)在step_num③對(duì)應(yīng)的HTML代碼中寫上這樣一條語句:<input id="chuanzhi" name="chuanzhi" type="hidden"/>然后在對(duì)應(yīng)的js代碼中把 $("#chuanzhi").val(groupID);
這樣你在step_num③對(duì)應(yīng)的Java后臺(tái)中就可以通過request.getParameter("chuanzhi"); 獲得你想要的groupID了
更多IT精彩內(nèi)容推薦:http://www.ujiuye.com/guangdong/?wt.mc_id=17009338
*請(qǐng)認(rèn)真填寫需求信息,我們會(huì)在24小時(shí)內(nèi)與您取得聯(lián)系。