js 前端合成excel(ThinkPHP5+html+js:比纯后端合成来的快,而且超级简单。)

思路:

因为岗位是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打开文件正常。

-

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值