思路:
因为岗位是PHP,框架用的TP5,所以想用PHPExcel插件生成excel,无赖折腾了半个小时,不想折腾了。所以用js+html做算了(最终花费20分钟,又快又好做)。
利用js将上万条数据导出到Excel,解决数据量大卡顿和导不出的问题。
调用:
1. html标签:<table id="backViewTable">(thead、tbody、th、tr、td等内容)</table>
2. 调用:mix_excel("测试生成Excel", "backViewTable");
核心js代码:
/*
* 利用js将上万条数据导出到Excel,解决数据量大卡顿和导不出的问题
*
* 1. html标签:<table id="backViewTable">(thead、tbody、th、tr、td等内容)</table>
* 2. 调用:mix_excel("测试生成Excel", "backViewTable");
*
* */
let excel_blob;
function make_excel_html(table_id) { // 生成Excel-html节点
console.log("table_id="+ table_id +",正在生成Excel-html节点..");
let _table = document.getElementById(table_id);
// 设置边框
_table.setAttribute("border", "1");
_table.setAttribute("cellspacing", "0");
_table.setAttribute("cellpadding", "0");
// 使用outerHTML属性获取整个table元素的HTML代码(包括<table>标签),然后包装成一个完整的HTML文档
// 设置charset为urf-8以防止中文乱码
let html = '<html><head><meta charset="utf-8" /></head><body>' + document.getElementById(table_id).outerHTML + '</body></html>';
// 实例化一个Blob对象,其构造函数的第一个参数是包含文件内容的数组,第二个参数是包含文件类型属性的对象
excel_blob = new Blob([html], { type: "application/vnd.ms-excel" });
// 生成a标签
let _a = '<a class="out-excel-a" id="out-excel-a" style="display: none;">点击导出表格</a>';
let _div = document.createElement("div");
_div.innerHTML = _a;
_table.insertBefore(_div, null);
console.log(excel_blob);
}
function download_excel_file(name, call_func) { // 下载
console.log("正在下载Excel...");
if (name === ""){
name = "导出Excel";
}
let time = Math.round(new Date().getTime()/100000)*100; // 确保100s内不重复下载
let a = document.getElementById("out-excel-a"); // 利用a标签下载
a.href = URL.createObjectURL(excel_blob); // 利用URL.createObjectURL()方法为a元素生成blob URL
a.download = name+"_"+ time +".xls";
a.click(); // 模拟点击,开始下载
console.log("Excel生成完成,保存即可。");
if (call_func) {
call_func();
}else {
console.log("Excel生成完成的可选回调函数未设置。");
}
}
function mix_excel(excel_name, table_id, call_func) {
if (table_id === "" && !table_id){
console.log("未知明table对应的id");
return;
}
make_excel_html(table_id);
setTimeout(function () {
console.log("table_id="+ table_id +",正在生成Excel-html节点...");
setTimeout(function () {
download_excel_file(excel_name, call_func);
}, 2000); // 加长时间确保可以正常输出
}, 2000);
}
//mix_excel("测试生成Excel", "backViewTable");
=============以下不推荐使用,因为超过900条数据就生成不了。==============
1. 后端返回查询的数据集:
/*
* 利用js合成excel接口
* */
public function out_excel(){
$login_name = input("login_name");
$pwd = input("pwd"); // 前端md5,后端再base64
$check = $this->user_check($login_name, $pwd); // 安全校验
if($check){
$res = Db::name("wx_account")->field("id, wx_name, wx_login, wx_property, close_days, open_date, close_reason, fans_num, manager, add_fans, add_wx_time, flow_income, add_fans_time, add_fans_way, ad_owner, ad_owner_spend, ad_income, migration, migration_add_fans, login_email, fans_property, original_id, migration_remark, body_company, body_company_num, qr, today_income, today_first_news_amount")->select();
$back = [
"state"=>1,
"msg"=>"查询完成",
"content"=>$res,
];
}else{
$back = [
"state"=>0,
"msg"=>"安全校验失败",
"content"=>null,
];
}
return json_encode($back, JSON_UNESCAPED_UNICODE);
}
2. 然后前端把数据渲染成
<table id="backViewTable">
<tr>
<th>title</th>
</tr>
<tr>
<td scope="row">a1</td>
<td>a2</td>
</tr>
<tr>
<td scope="row">b1</td>
<td>b2</td>
</tr>
<table>
<!--开始-合成函数-->
<script>
var tablesToExcel = (function() { /*js生成excel*/
var uri = 'data:application/vnd.ms-excel;base64,';
var tmplWorkbookXML = '<?xml version="1.0"?><?mso-application progid="Excel.Sheet"?><Workbook xmlns="urn:schemas-microsoft-com:office:spreadsheet" xmlns:ss="urn:schemas-microsoft-com:office:spreadsheet">'
+ '<DocumentProperties xmlns="urn:schemas-microsoft-com:office:office"><Author>Axel Richter</Author><Created>{created}</Created></DocumentProperties>'
+ '<Styles>'
+ '<Style ss:ID="Currency"><NumberFormat ss:Format="Currency"></NumberFormat></Style>'
+ '<Style ss:ID="Date"><NumberFormat ss:Format="Medium Date"></NumberFormat></Style>'
+ '</Styles>'
+ '{worksheets}</Workbook>';
var tmplWorksheetXML = '<Worksheet ss:Name="{nameWS}"><Table>{rows}</Table></Worksheet>';
var tmplCellXML = '<Cell{attributeStyleID}{attributeFormula}><Data ss:Type="{nameType}">{data}</Data></Cell>';
var base64 = function(s) { return window.btoa(unescape(encodeURIComponent(s))) };
var format = function(s, c) { return s.replace(/{(\w+)}/g, function(m, p) { return c[p]; }) };
return function(tables, wsnames, wbname, appname) {
var ctx = "";
var workbookXML = "";
var worksheetsXML = "";
var rowsXML = "";
for (var i = 0; i < tables.length; i++) {
if (!tables[i].nodeType) tables[i] = document.getElementById(tables[i]);
// 控制要导出的行数
for (var j = 0; j < tables[i].rows.length; j++) {
rowsXML += '<Row>';
// 控制导出的列数(在本例中,最后一列为button,导出的文件会出错,所以导出到倒数第二列
for (var k = 0; k < tables[i].rows[j].cells.length-1; k++) {
var dataType = tables[i].rows[j].cells[k].getAttribute("data-type");
var dataStyle = tables[i].rows[j].cells[k].getAttribute("data-style");
var dataValue = tables[i].rows[j].cells[k].getAttribute("data-value");
dataValue = (dataValue)?dataValue:tables[i].rows[j].cells[k].innerHTML;
var dataFormula = tables[i].rows[j].cells[k].getAttribute("data-formula");
dataFormula = (dataFormula)?dataFormula:(appname=='Calc' && dataType=='DateTime')?dataValue:null;
ctx = { attributeStyleID: (dataStyle=='Currency' || dataStyle=='Date')?' ss:StyleID="'+dataStyle+'"':''
, nameType: (dataType=='Number' || dataType=='DateTime' || dataType=='Boolean' || dataType=='Error')?dataType:'String'
, data: (dataFormula)?'':dataValue
, attributeFormula: (dataFormula)?' ss:Formula="'+dataFormula+'"':''
};
rowsXML += format(tmplCellXML, ctx);
}
rowsXML += '</Row>'
}
ctx = {rows: rowsXML, nameWS: wsnames[i] || 'Sheet' + i};
worksheetsXML += format(tmplWorksheetXML, ctx);
rowsXML = "";
}
ctx = {created: (new Date()).getTime(), worksheets: worksheetsXML};
workbookXML = format(tmplWorkbookXML, ctx);
// 查看后台的打印输出
console.log(workbookXML);
var link = document.createElement("A");
link.href = uri + base64(workbookXML);
link.download = wbname || 'Workbook.xls';
link.target = '_blank';
document.body.appendChild(link);
link.click();
document.body.removeChild(link);
// 其他
alert_txt("合成完成!自动下载xls完成!", 5000);
setTimeout(function () {
$(".excel-div").remove();
setTimeout(function () {
//完成后的操作
window.close();
}, 2500)
}, 200);
}
})();
function make_excel(name) { // 开始执行合成excel
if (!name){name="未命名表格"}
tablesToExcel(['backViewTable'], ['ProductDay1'], name+'.xls', 'Excel');
}
// make_excel("test");
</script>
<!--结束-合成函数-->
合适,然后利用js整体输出excel即可。
-
<!DOCTYPE html>
<html lang="zh-cn">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0, minimum-scale=1.0, maximum-scale=1.0">
<title>excel by js生成器</title>
<script src="file/js/jquery-1.11.3.min.js" type="text/javascript"></script>
<script src="http://cdnaliyun.oss-cn-hangzhou.aliyuncs.com/js/common.js" type="text/javascript"></script>
<link href="file/css/com-page.css" rel="stylesheet"/>
<script src="file/js/public.js" type="text/javascript"></script>
<link href="file/css/common.css" rel="stylesheet"/>
<link href="file/css/public.css" rel="stylesheet"/>
</head>
<body>
<script>
var api_url = "https://www.djfans.net/wxmanage/public/?s=/";
var web_url = "https://www.djfans.net/wxmanage/view/";
</script>
==================================开始====================================
<div class="excel-div hide">
<!--开始-表格体-->
<table id="backViewTable" class="append-table-tr">
<!--头-->
<tr>
<th>id(数据记录id)</th>
<th>主公众号名</th>
<th>账号id</th>
<th>账号属性</th>
<th>封号天数</th>
<th>解封时间</th>
<th>封号原因</th>
<th>实时粉丝</th>
<th>运营者</th>
<th>出号粉丝</th>
<th>出号时间</th>
<th>流量主收益</th>
<th>今日流量主收益</th>
<th>头条阅读量</th>
<th>加粉时间</th>
<th>加粉渠道</th>
<th>是否过广告主</th>
<th>广告主消耗</th>
<th>广告收益</th>
<th>是否迁移</th>
<th>迁移加粉</th>
<th>注册邮箱</th>
<th>用户属性</th>
<th>原始id</th>
<th>迁移备注</th>
<th>主体</th>
<th>主体账号数量</th>
<th>二维码</th>
</tr>
<!--体-->
<!--<tr>
<td scope="row"></td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
</tr>-->
</table>
<!--结束-表格体-->
</div>
<!--开始-合成函数-->
<script>
var tablesToExcel = (function() { /*js生成excel*/
var uri = 'data:application/vnd.ms-excel;base64,';
var tmplWorkbookXML = '<?xml version="1.0"?><?mso-application progid="Excel.Sheet"?><Workbook xmlns="urn:schemas-microsoft-com:office:spreadsheet" xmlns:ss="urn:schemas-microsoft-com:office:spreadsheet">'
+ '<DocumentProperties xmlns="urn:schemas-microsoft-com:office:office"><Author>Axel Richter</Author><Created>{created}</Created></DocumentProperties>'
+ '<Styles>'
+ '<Style ss:ID="Currency"><NumberFormat ss:Format="Currency"></NumberFormat></Style>'
+ '<Style ss:ID="Date"><NumberFormat ss:Format="Medium Date"></NumberFormat></Style>'
+ '</Styles>'
+ '{worksheets}</Workbook>';
var tmplWorksheetXML = '<Worksheet ss:Name="{nameWS}"><Table>{rows}</Table></Worksheet>';
var tmplCellXML = '<Cell{attributeStyleID}{attributeFormula}><Data ss:Type="{nameType}">{data}</Data></Cell>';
var base64 = function(s) { return window.btoa(unescape(encodeURIComponent(s))) };
var format = function(s, c) { return s.replace(/{(\w+)}/g, function(m, p) { return c[p]; }) };
return function(tables, wsnames, wbname, appname) {
var ctx = "";
var workbookXML = "";
var worksheetsXML = "";
var rowsXML = "";
for (var i = 0; i < tables.length; i++) {
if (!tables[i].nodeType) tables[i] = document.getElementById(tables[i]);
// 控制要导出的行数
for (var j = 0; j < tables[i].rows.length; j++) {
rowsXML += '<Row>';
// 控制导出的列数(在本例中,最后一列为button,导出的文件会出错,所以导出到倒数第二列
for (var k = 0; k < tables[i].rows[j].cells.length-1; k++) {
var dataType = tables[i].rows[j].cells[k].getAttribute("data-type");
var dataStyle = tables[i].rows[j].cells[k].getAttribute("data-style");
var dataValue = tables[i].rows[j].cells[k].getAttribute("data-value");
dataValue = (dataValue)?dataValue:tables[i].rows[j].cells[k].innerHTML;
var dataFormula = tables[i].rows[j].cells[k].getAttribute("data-formula");
dataFormula = (dataFormula)?dataFormula:(appname=='Calc' && dataType=='DateTime')?dataValue:null;
ctx = { attributeStyleID: (dataStyle=='Currency' || dataStyle=='Date')?' ss:StyleID="'+dataStyle+'"':''
, nameType: (dataType=='Number' || dataType=='DateTime' || dataType=='Boolean' || dataType=='Error')?dataType:'String'
, data: (dataFormula)?'':dataValue
, attributeFormula: (dataFormula)?' ss:Formula="'+dataFormula+'"':''
};
rowsXML += format(tmplCellXML, ctx);
}
rowsXML += '</Row>'
}
ctx = {rows: rowsXML, nameWS: wsnames[i] || 'Sheet' + i};
worksheetsXML += format(tmplWorksheetXML, ctx);
rowsXML = "";
}
ctx = {created: (new Date()).getTime(), worksheets: worksheetsXML};
workbookXML = format(tmplWorkbookXML, ctx);
// 查看后台的打印输出
console.log(workbookXML);
var link = document.createElement("A");
link.href = uri + base64(workbookXML);
link.download = wbname || 'Workbook.xls';
link.target = '_blank';
document.body.appendChild(link);
link.click();
document.body.removeChild(link);
// 其他
alert_txt("合成完成!自动下载xls完成!", 5000);
setTimeout(function () {
$(".excel-div").remove();
setTimeout(function () {
//完成后的操作
window.close();
}, 2500)
}, 200);
}
})();
function make_excel(name) { // 开始执行合成excel
if (!name){name="未命名表格"}
tablesToExcel(['backViewTable'], ['ProductDay1'], name+'.xls', 'Excel');
}
// make_excel("test");
</script>
<!--结束-合成函数-->
========================================结束===============================
<script src="file/js/com-page.js" type="text/javascript"></script>
<script>
function get_excel_data() { // 渲染excel HTML排版原始数据
(function () { // 登录状态自检
// 请求数据
$.ajax({
url: api_url+"admin/statistic/out_excel",
type: "POST",
dataType: "json",
async: true,
data: { // 字典数据
login_name: login_name,
pwd: pwd,
},
success: function(data, status){
console_log("返回数据="+data);
if(typeof data === "string"){datas = JSON.parse(data);}else {datas = data;}
if (datas.state===0){
console_log(datas.msg)
}else if (datas.state===1) {
console_log(datas.msg);
var list = datas.content;
for (var x=0; x<list.length; x++){
var id = list[x]["id"];
var wx_name = list[x]["wx_name"];
var wx_login = list[x]["wx_login"];
var wx_property = list[x]["wx_property"];
var close_days = list[x]["close_days"]; //5
var open_date = list[x]["open_date"];
var close_reason = list[x]["close_reason"];
var fans_num = list[x]["fans_num"];
var manager = list[x]["manager"];
var add_fans = list[x]["add_fans"]; //10
var add_wx_time = list[x]["add_wx_time"];
var flow_income = list[x]["flow_income"];
var add_fans_time = list[x]["add_fans_time"];
var add_fans_way = list[x]["add_fans_way"];
var ad_owner = list[x]["ad_owner"]; //15
var ad_owner_spend = list[x]["ad_owner_spend"];
var ad_income = list[x]["ad_income"];
var migration = list[x]["migration"];
var migration_add_fans = list[x]["migration_add_fans"];
var login_email = list[x]["login_email"]; //20
var fans_property = list[x]["fans_property"];
var original_id = list[x]["original_id"];
var migration_remark = list[x]["migration_remark"];
var body_company = list[x]["body_company"];
var body_company_num = list[x]["body_company_num"]; // 25
var qr = list[x]["qr"];
var today_income = list[x]["today_income"];
var today_first_news_amount = list[x]["today_first_news_amount"];
if(today_first_news_amount===null){today_first_news_amount="暂无";}
$(".append-table-tr").append('<tr>' +
'<th scope="row">'+id+'</th>' +
'<td>'+wx_name+'</td>' +
'<td>'+wx_login+'</td>' +
'<td>'+wx_property+'</td>' +
'<td>'+close_days+'</td>' +
'<td>'+open_date+'</td>' +
'<td>'+close_reason+'</td>' +
'<td>'+fans_num+'</td>' +
'<td>'+manager+'</td>' +
'<td>'+add_fans+'</td>' +
'<td>'+add_wx_time+'</td>' +
'<td>'+flow_income+'</td>' +
'<td>'+today_income+'</td>' +
'<td>'+today_first_news_amount+'</td>' +
'<td>'+add_fans_time+'</td>' +
'<td>'+add_fans_way+'</td>' +
'<td>'+ad_owner+'</td>' +
'<td>'+ad_owner_spend+'</td>' +
'<td>'+ad_income+'</td>' +
'<td>'+migration+'</td>' +
'<td>'+migration_add_fans+'</td>' +
'<td>'+login_email+'</td>' +
'<td>'+fans_property+'</td>' +
'<td>'+original_id+'</td>' +
'<td>'+migration_remark+'</td>' +
'<td>'+body_company+'</td>' +
'<td>'+body_company_num+'</td>' +
'<td>'+(web_url+qr)+'</td>' +
'</tr>');
} // end-for
alert_txt("正在生成Excel文件...", "long");
setTimeout(function () {
make_excel("主公众号信息"+getNowDate()[0]+""+getNowDate()[2]+""+getNowDate()[1]);
}, 200);
}
},
error: function (xhr) {
console.log(xhr);
alert_txt("接口请求错误或者网络不通", 2500);
}
});
})();
}
</script>
<script>
var login_name = getCookie(cookie_pre+"login_name");
var pwd = getCookie(cookie_pre+"pwd");
var url_page = getThisUrlParam("", "page")*1;
if(url_page<1){url_page=1;}
(function () { // 登录状态自检
// 请求数据
$.ajax({
url: api_url+"admin/login/login",
type: "POST",
dataType: "json",
async: true,
data: { // 字典数据
login_name: login_name,
pwd: pwd,
},
success: function(data, status){
console_log("post返回数据:" + data+";status:"+status+";返回数据的类型:"+typeof data);
if(typeof data === "string"){datas = JSON.parse(data);}else {datas = data;}
if (datas.state===0){
console_log("未登录");
}else if (datas.state===1) {
console_log("已登录");
get_excel_data();
}
},
error: function (xhr) {
console.log(xhr);
alert_txt("接口请求错误或者网络不通", 2500);
}
});
})();
</script>
</body>
</html>
-进入html页面即可完成渲染-合成-下载
-office2019打开文件正常。
-