国产xxxx99真实实拍_久久不雅视频_高清韩国a级特黄毛片_嗯老师别我我受不了了小说

資訊專(zhuān)欄INFORMATION COLUMN

使用js-xlsx純前端導(dǎo)出excel

inapt / 1648人閱讀

摘要:前言最近公司需要將幾張統(tǒng)計(jì)表格導(dǎo)出到由于公司現(xiàn)有導(dǎo)出功能是前后端配合的導(dǎo)出,覺(jué)得麻煩,所以想找一個(gè)純前端導(dǎo)出的工具,最后找到了,評(píng)價(jià)還是挺高的,但是中文文檔沒(méi)找到百度也沒(méi)有找到一個(gè)比較全面的教程所以踩了很多坑,自己記錄下,方便以后使用。

前言

最近公司需要將幾張統(tǒng)計(jì)表格導(dǎo)出到excel,由于公司現(xiàn)有導(dǎo)出excel功能是前后端配合的導(dǎo)出,覺(jué)得麻煩,所以想找一個(gè)純前端導(dǎo)出的工具,最后找到了js-xlsx,評(píng)價(jià)還是挺高的,但是中文文檔沒(méi)找到,百度也沒(méi)有找到一個(gè)比較全面的教程,所以踩了很多坑,自己記錄下,方便以后使用。

環(huán)境

由于我業(yè)務(wù)只用到將table標(biāo)簽內(nèi)的內(nèi)容導(dǎo)出到excel,所以只會(huì)寫(xiě)如何將一個(gè)table元素里的內(nèi)容導(dǎo)出到excel。也可以通過(guò)json導(dǎo)出,貌似還會(huì)更簡(jiǎn)單些。

安裝

GitHub地址
npm安裝

npm install xlsx

安裝后dist文件夾下有一個(gè)文件xlsx.full.min.js,就是它了,引入到項(xiàng)目中

第一個(gè)例子

先上代碼




    
    
    
    Document


    
序號(hào) 姓名 年齡 興趣
1 張三 18 打游戲
2 李四 88 看電影
3 王五 81 睡覺(jué)

運(yùn)行效果

導(dǎo)出結(jié)果:


你可能注意到了,我這里引入了一個(gè)export.js文件,這個(gè)export.js文件里面只有2個(gè)方法,就是上面代碼用到的openDownloadDialog(sheet2blob(sheet),"下載.xlsx");
這是export.js的代碼:

// 將一個(gè)sheet轉(zhuǎn)成最終的excel文件的blob對(duì)象,然后利用URL.createObjectURL下載
function sheet2blob(sheet, sheetName) {
    sheetName = sheetName || "sheet1";
    var workbook = {
        SheetNames: [sheetName],
        Sheets: {}
    };
    workbook.Sheets[sheetName] = sheet; // 生成excel的配置項(xiàng)

    var wopts = {
        bookType: "xlsx", // 要生成的文件類(lèi)型
        bookSST: false, // 是否生成Shared String Table,官方解釋是,如果開(kāi)啟生成速度會(huì)下降,但在低版本IOS設(shè)備上有更好的兼容性
        type: "binary"
    };
    var wbout = XLSX.write(workbook, wopts);
    var blob = new Blob([s2ab(wbout)], {
        type: "application/octet-stream"
    }); // 字符串轉(zhuǎn)ArrayBuffer
    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;
    }
    return blob;
}

function openDownloadDialog(url, saveName) {
    if (typeof url == "object" && url instanceof Blob) {
        url = URL.createObjectURL(url); // 創(chuàng)建blob地址
    }
    var aLink = document.createElement("a");
    aLink.href = url;
    aLink.download = saveName || ""; // HTML5新增的屬性,指定保存文件名,可以不要后綴,注意,file:///模式下不會(huì)生效
    var event;
    if (window.MouseEvent) event = new MouseEvent("click");
    else {
        event = document.createEvent("MouseEvents");
        event.initMouseEvent("click", true, false, window, 0, 0, 0, 0, 0, false, false, false, false, 0, null);
    }
    aLink.dispatchEvent(event);
}

PS: 這2個(gè)方法是網(wǎng)上當(dāng)?shù)?原文地址。作者寫(xiě)的挺好,也是從這里找到了頭緒。

如果你的table標(biāo)簽內(nèi)有合并單元格的操作,XLSX.utils.table_to_sheet(*)也能夠讀取出來(lái),并且你打印出來(lái)的結(jié)果也能夠顯示出來(lái),效果圖:


可以看到,excel中的表格也已經(jīng)合并了。
但是實(shí)際的情況,客戶覺(jué)得這行字沒(méi)有居中,他就會(huì)向你嘮叨,為啥不居中,所以我們現(xiàn)在解決文字不居中的問(wèn)題。

設(shè)置樣式(居中,文字大小顏色,背景色...)
PS:這是我踩坑最多的地方....

這里就不繞圈子了,設(shè)置樣式的話,上面的xlsx.full.min.js是無(wú)法生效的,
必須安裝xlsx-style

安裝xlsx-style

好像只有npm安裝,github我沒(méi)找到地址

npm install xlsx-style

同樣,安裝目錄下dist文件夾下有一個(gè)xlsx.full.min.js,嗯?名字一模一樣?怎么用?好吧,無(wú)從下手,只好硬著頭皮引入了,注意,我將xlsx-style的js文件放在下方:

還有btn_export()方法要變一下,加一下樣式。
具體的單元格樣式說(shuō)明可以看下這篇文章 xlsx-style單元格樣式參考表

function btn_export() {
        var table1 = document.querySelector("#table1");
        var sheet = XLSX.utils.table_to_sheet(table1);
        //這個(gè)就是修改格式的代碼
        sheet["A5"].s = { 
            font: { sz: 13, bold: true, },
            alignment: { 
                horizontal: "center", vertical: "center", wrap_text: true 
            } 
        };
        openDownloadDialog(sheet2blob(sheet),"下載.xlsx");
    }

改完之后,點(diǎn)擊運(yùn)行,果不其然,報(bào)錯(cuò)了:

原因是什么呢,原因是2個(gè)js文件暴露出來(lái)的變量都叫‘XLSX’,但是xlsx-style這個(gè)js文件里沒(méi)有XLSX.utils這個(gè)方法,而且xlsx-style這個(gè)js文件是后引入的,就把前面的XLSX給覆蓋了,所以報(bào)錯(cuò)。
XLSX.utils里面有很多可用的方法,但是按照這種方式無(wú)法進(jìn)行調(diào)用:

你可能想到把2個(gè)js文件調(diào)換一下位置,但是結(jié)果是xlsx暴露的變量覆蓋了xlsx-style暴露的變量。你的樣式還是改變不了。

注意 如果你的導(dǎo)出功能 是傳入json格式或其他格式而沒(méi)有用到XLSX.utils的話,你只需使用xlsx-style的js,下面的內(nèi)容可以忽略,下面的內(nèi)容是講如何使xlsx和xlsx-style的js一起工作的。

不用XLSX.utils的方式

由于這2個(gè)js都是加密之后的內(nèi)容,無(wú)法解讀,不能在這2個(gè)js上找到什么有用的東西。好在在xlsx dist文件夾下找到了xlsx.extendscript.js,看這個(gè)文件就像個(gè)工具類(lèi),由于我上面用到了table_to_sheet方法,在xlsx.extendscript上面的搜索了一下,果然發(fā)現(xiàn)了這個(gè)方法,二話不說(shuō),將xlsx的js引用刪除,引入xlsx.extendscript:

運(yùn)行。結(jié)果你應(yīng)該已經(jīng)猜到了,樣式并沒(méi)有發(fā)生改變。什么原因呢,xlsx.extendscript.js暴露出來(lái)的變量仍然是"XLSX",下面的變量還是覆蓋了上面的變量。

注意!!! 如果你的項(xiàng)目中使用了webpack、babel等,可以直接import,不用改變變量名

好在這個(gè)xlsx.extendscript.js不是壓縮版本,可以對(duì)內(nèi)容進(jìn)行修改,就把暴露出來(lái)的變量修改為"XLSX2"吧。這樣我們只有在使用utils工具的時(shí)候才用到xlsx.extendscript.js,其余都用的是xlsx-style這個(gè)js,這樣總該可以了吧 。
修改完之后別忘了將XSLX.utils.table_to_sheet()改成XLSX2.utils.table_to_sheet()。
(不建議修改源碼,由于工作需要不修改源碼無(wú)法使用才做的修改)

function btn_export() {
        var table1 = document.querySelector("#table1");
        var sheet = XLSX2.utils.table_to_sheet(table1);
        sheet["A5"].s = {
            font: {
                sz: 13,
                bold: true,
                color: {
                    rgb: "FFFFAA00"
                }
            },
            alignment: {
                horizontal: "center",
                vertical: "center",
                wrap_text: true
            }
        };
        openDownloadDialog(sheet2blob(sheet), "下載.xlsx");
    }

運(yùn)行:

可以看到,你所做的樣式更改已經(jīng)生效了。
客戶需求增加:我想要前面幾行空出來(lái),并且寫(xiě)上打印公司名。
觀察xlsx.extendscript.js源碼,發(fā)現(xiàn)table_to_sheet,也就是parse_dom_table,并沒(méi)有設(shè)置起始行的參數(shù),下面給出parse_dom_table的代碼:

function parse_dom_table(table, _opts) {
    var opts = _opts || {};
    if(DENSE != null) opts.dense = DENSE;
    var ws = opts.dense ? ([]) : ({});
    var rows = table.getElementsByTagName("tr");
    var sheetRows = opts.sheetRows || 10000000;
    var range = {s:{r:0,c:0},e:{r:0,c:0}};
    var merges = [], midx = 0;
    var rowinfo = [];
    var _R = 0, R = 0, _C, C, RS, CS;
    for(; _R < rows.length && R < sheetRows; ++_R) {
        var row = rows[_R];
        if (is_dom_element_hidden(row)) {
            if (opts.display) continue;
            rowinfo[R] = {hidden: true};
        }
        var elts = (row.children);
        for(_C = C = 0; _C < elts.length; ++_C) {
            var elt = elts[_C];
            if (opts.display && is_dom_element_hidden(elt)) continue;
            var v = htmldecode(elt.innerHTML);
            for(midx = 0; midx < merges.length; ++midx) {
                var m = merges[midx];
                if(m.s.c == C && m.s.r <= R && R <= m.e.r) { C = m.e.c+1; midx = -1; }
            }
            /* TODO: figure out how to extract nonstandard mso- style */
            CS = +elt.getAttribute("colspan") || 1;
            if((RS = +elt.getAttribute("rowspan"))>0 || CS>1) merges.push({s:{r:R,c:C},e:{r:R + (RS||1) - 1, c:C + CS - 1}});
            var o = {t:"s", v:v};
            var _t = elt.getAttribute("t") || "";
            if(v != null) {
                if(v.length == 0) o.t = _t || "z";
                else if(opts.raw || v.trim().length == 0 || _t == "s"){}
                else if(v === "TRUE") o = {t:"b", v:true};
                else if(v === "FALSE") o = {t:"b", v:false};
                else if(!isNaN(fuzzynum(v))) o = {t:"n", v:fuzzynum(v)};
                else if(!isNaN(fuzzydate(v).getDate())) {
                    o = ({t:"d", v:parseDate(v)});
                    if(!opts.cellDates) o = ({t:"n", v:datenum(o.v)});
                    o.z = opts.dateNF || SSF._table[14];
                }
            }
            if(opts.dense) { if(!ws[R]) ws[R] = []; ws[R][C] = o; }
            else ws[encode_cell({c:C, r:R})] = o;
            if(range.e.c < C) range.e.c = C;
            C += CS;
        }
        ++R;
    }
    if(merges.length) ws["!merges"] = merges;
    if(rowinfo.length) ws["!rows"] = rowinfo;
    range.e.r = R - 1;
    ws["!ref"] = encode_range(range);
    if(R >= sheetRows) ws["!fullref"] = encode_range((range.e.r = rows.length-_R+R-1,range)); // We can count the real number of rows to parse but we don"t to improve the performance
    return ws;
}

那自己加一個(gè)吧
可以看到,里面的R變量 這是控制起始行的關(guān)鍵所在,好吧,我們?cè)僮鲆幌滦薷?

var _R = 0, R = _opts.rowIndex || 0, _C, C, RS, CS;

這里我們給_opts增加一個(gè)屬性rowIndex,在調(diào)用table_to_sheet方法的時(shí)候傳入這個(gè)屬性。下面是變更后的代碼:

function btn_export() {
        var table1 = document.querySelector("#table1");
        var opt = {
            rowIndex: 4
        }; //開(kāi)頭空4行
        var sheet = XLSX2.utils.table_to_sheet(table1, opt);
        sheet["A1"] = {
            t: "s",
            v: "三鹿集團(tuán)有限公司"
        }; //給A1單元格賦值
        sheet["A1"].s = {
            font: {
                name: "宋體",
                sz: 24,
                bold: true,
                underline: true,
                color: {
                    rgb: "FFFFAA00"
                }
            },
            alignment: { horizontal: "center", vertical: "center", wrap_text: true },
            fill: {
                bgColor: { rgb: "ffff00" }
            }
        };
        //["!merges"]這個(gè)屬性是專(zhuān)門(mén)用來(lái)進(jìn)行單元格合并的 
        sheet["!merges"].push({//如果不為空push 為空 = 賦值
            //合并單元格 index都從0開(kāi)始
            s: { //s開(kāi)始
                c: 0, //開(kāi)始列
                r: 0 //開(kāi)始行
            },
            e: { //e結(jié)束
                c: 3, //結(jié)束列
                r: 2 //結(jié)束行
            }
        });
        sheet["A9"].s = { //樣式
            font: {
                sz: 13,
                bold: true,
                color: {
                    rgb: "FFFFAA00"
                }
            },
            alignment: {
                horizontal: "center",
                vertical: "center",
                wrap_text: true
            }
        };
        openDownloadDialog(sheet2blob(sheet), "下載.xlsx");
    }

運(yùn)行結(jié)果:

可以看到,你所做的更改生效了。

客戶又提新需求了,要加上2個(gè)字段,身份證號(hào)和手機(jī)號(hào)。
這還不簡(jiǎn)單?加上2個(gè)字段不就好了。2分鐘搞定,導(dǎo)出:

???
身份證號(hào)怎么變成了科學(xué)計(jì)數(shù)法,什么鬼(后來(lái)發(fā)現(xiàn)百分比也會(huì)直接給你換算成0~1的小數(shù),統(tǒng)計(jì)沒(méi)法搞)
怎么回事?還是parse_dom_table的杰作!
注意這一行:

else if(!isNaN(fuzzynum(v))) o = {t:"n", v:fuzzynum(v)};

意思是只要從td的text里讀取到的值,只要轉(zhuǎn)換之后是一個(gè)number,(不管你是string類(lèi)型),都會(huì)給你來(lái)一個(gè)fuzzynum(v),轉(zhuǎn)換成一個(gè)number類(lèi)型。
做下修改,結(jié)果:

function parse_dom_table(table, _opts) {
    var opts = _opts || {};
    if(DENSE != null) opts.dense = DENSE;
    var ws = opts.dense ? ([]) : ({});
    var rows = table.getElementsByTagName("tr");
    var sheetRows = opts.sheetRows || 10000000;
    var range = {s:{r:0,c:0},e:{r:0,c:0}};
    var merges = [], midx = 0;
    var rowinfo = [];
    var _R = 0, R = _opts.rowIndex || 0, _C, C, RS, CS;
    for(; _R < rows.length && R < sheetRows; ++_R) {
        var row = rows[_R];
        if (is_dom_element_hidden(row)) {
            if (opts.display) continue;
            rowinfo[R] = {hidden: true};
        }
        var elts = (row.children);
        for(_C = C = 0; _C < elts.length; ++_C) {
            var elt = elts[_C];
            if (opts.display && is_dom_element_hidden(elt)) continue;
            var v = htmldecode(elt.innerHTML);
            for(midx = 0; midx < merges.length; ++midx) {
                var m = merges[midx];
                if(m.s.c == C && m.s.r <= R && R <= m.e.r) { C = m.e.c+1; midx = -1; }
            }
            /* TODO: figure out how to extract nonstandard mso- style */
            CS = +elt.getAttribute("colspan") || 1;
            if((RS = +elt.getAttribute("rowspan"))>0 || CS>1) merges.push({s:{r:R,c:C},e:{r:R + (RS||1) - 1, c:C + CS - 1}});
            var o = {t:"s", v:v};
            var _t = elt.getAttribute("t") || "";
            if(v != null) {
                if(v.length == 0) o.t = _t || "z";
                else if(opts.raw || v.trim().length == 0 || _t == "s"){}
                else if(v === "TRUE") o = {t:"b", v:true};
                else if(v === "FALSE") o = {t:"b", v:false};
        //else if(!isNaN(fuzzynum(v))) o = {t:"n", v:fuzzynum(v)};
        else if(!isNaN(fuzzynum(v))) o = {t:"s", v:v};//不自動(dòng)格式化number類(lèi)型
                else if(!isNaN(fuzzydate(v).getDate())) {
                    o = ({t:"d", v:parseDate(v)});
                    if(!opts.cellDates) o = ({t:"n", v:datenum(o.v)});
                    o.z = opts.dateNF || SSF._table[14];
                }
            }
            if(opts.dense) { if(!ws[R]) ws[R] = []; ws[R][C] = o; }
            else ws[encode_cell({c:C, r:R})] = o;
            if(range.e.c < C) range.e.c = C;
            C += CS;
        }
        ++R;
    }
    if(merges.length) ws["!merges"] = merges;
    if(rowinfo.length) ws["!rows"] = rowinfo;
    range.e.r = R - 1;
    ws["!ref"] = encode_range(range);
    if(R >= sheetRows) ws["!fullref"] = encode_range((range.e.r = rows.length-_R+R-1,range)); // We can count the real number of rows to parse but we don"t to improve the performance
    return ws;
}

將轉(zhuǎn)換的語(yǔ)句注釋掉,重寫(xiě)這行代碼,如果是number類(lèi)型,不做任何修改,該是什么值還是什么值。
現(xiàn)在再重新運(yùn)行,結(jié)果:
可以看到,數(shù)字能夠正常顯示了。但是這個(gè)單元格好像并不會(huì)自動(dòng)展開(kāi),永遠(yuǎn)都這么大,xlsx-style 也提供了控制單元格寬度的方法:

sheet["!cols"] = [{
            wpx: 70
        }, {
            wpx: 70
        }, {
            wpx: 70
        }, {
            wpx: 70
        }, {
            wpx: 150
        }, {
            wpx: 120
        }]; //單元格列寬

注意,設(shè)置單元格列寬要從第一行開(kāi)始設(shè)置
結(jié)果:

完整前端代碼:





    
    
    
    Document



    
序號(hào) 姓名 年齡 興趣 身份證號(hào) 手機(jī)號(hào)
1 張三 18 打游戲 320322184087562589 1374569821
2 李四 88 看電影 420322184087562589 2374569821
3 王五 81 睡覺(jué) 520322184087562589 3374569821
這是一個(gè)合并單元格
demo源碼

github地址 完整實(shí)例

總結(jié)

不是特殊情況不建議修改源碼

因?yàn)楫吘剐薷牧舜a,所以這種方法只能面向小眾

聽(tīng)過(guò)收費(fèi)版功能很全,建議如果有需要的話還是購(gòu)買(mǎi)收費(fèi)版本,但是地址沒(méi)找到...

可以根據(jù)自己需求對(duì)xlsx源碼進(jìn)行修改,以便滿足自己工作的需求。但是這樣較難以維護(hù),如何取舍還是自行斟酌。

我這里只列取了我實(shí)際工作中所需要的功能,xlsx的功能很豐富,有空可以多琢磨琢磨。

文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請(qǐng)注明本文地址:http://specialneedsforspecialkids.com/yun/105428.html

相關(guān)文章

  • 前端實(shí)現(xiàn)excel表格導(dǎo)入導(dǎo)出

    摘要:使用時(shí),前端可以將后端返回的數(shù)據(jù)拼接成自己需要導(dǎo)出的格式,下載到電腦中,完全不依賴后端。 前言 github: https://github.com/stardew516... 以往做excel表格下載功能的時(shí)候,都是后端生成好表格后,存儲(chǔ)在某個(gè)地方,然后給前端一個(gè)鏈接,前端使用a標(biāo)簽加download下載,或者使用node。其實(shí)純前端也是可以做表格下載的,有一個(gè)很好用的javascr...

    CoyPan 評(píng)論0 收藏0
  • [SheetJS] js-xlsx模塊學(xué)習(xí)指南

    摘要:簡(jiǎn)介是前端操作以及類(lèi)似的二維表的最佳選擇之一而是它的社區(qū)版本將注意力集中到了數(shù)據(jù)轉(zhuǎn)換和導(dǎo)出上所以它支持相當(dāng)多種類(lèi)的數(shù)據(jù)解析和導(dǎo)出不僅僅局限于支持格式支持的導(dǎo)入格式支持的導(dǎo)出格式它可以解析符合格式的數(shù)據(jù)導(dǎo)出符合格式的數(shù)據(jù)利用中間層操作數(shù)據(jù) 簡(jiǎn)介 SheetJS是前端操作Excel以及類(lèi)似的二維表的最佳選擇之一,而js-xlsx是它的社區(qū)版本. js-xlsx將注意力集中到了數(shù)據(jù)轉(zhuǎn)換和導(dǎo)出...

    zhaot 評(píng)論0 收藏0
  • 使用js-xlsx前端導(dǎo)出excel

    摘要:前言最近公司需要將幾張統(tǒng)計(jì)表格導(dǎo)出到由于公司現(xiàn)有導(dǎo)出功能是前后端配合的導(dǎo)出,覺(jué)得麻煩,所以想找一個(gè)純前端導(dǎo)出的工具,最后找到了,評(píng)價(jià)還是挺高的,但是中文文檔沒(méi)找到百度也沒(méi)有找到一個(gè)比較全面的教程所以踩了很多坑,自己記錄下,方便以后使用。 前言 最近公司需要將幾張統(tǒng)計(jì)表格導(dǎo)出到excel,由于公司現(xiàn)有導(dǎo)出excel功能是前后端配合的導(dǎo)出,覺(jué)得麻煩,所以想找一個(gè)純前端導(dǎo)出的工具,最后找到了...

    Cheriselalala 評(píng)論0 收藏0
  • 使用js-xlsx前端導(dǎo)出excel

    摘要:前言最近公司需要將幾張統(tǒng)計(jì)表格導(dǎo)出到由于公司現(xiàn)有導(dǎo)出功能是前后端配合的導(dǎo)出,覺(jué)得麻煩,所以想找一個(gè)純前端導(dǎo)出的工具,最后找到了,評(píng)價(jià)還是挺高的,但是中文文檔沒(méi)找到百度也沒(méi)有找到一個(gè)比較全面的教程所以踩了很多坑,自己記錄下,方便以后使用。 前言 最近公司需要將幾張統(tǒng)計(jì)表格導(dǎo)出到excel,由于公司現(xiàn)有導(dǎo)出excel功能是前后端配合的導(dǎo)出,覺(jué)得麻煩,所以想找一個(gè)純前端導(dǎo)出的工具,最后找到了...

    LeanCloud 評(píng)論0 收藏0

發(fā)表評(píng)論

0條評(píng)論

最新活動(dòng)
閱讀需要支付1元查看
<