1. 程式人生 > >js-xlsx實現Excel的匯入匯出功能

js-xlsx實現Excel的匯入匯出功能

一:匯入功能
讀取excel的多個sheet資料

<script type="text/javascript" src="js/xlsx.core.min.js"></script>

<table style="width:80%;margin-left:10%;margin-top:30px;">
    <td align="right" style="width: 50%;">
            <h3 align="center">匯入參賽名單:</h3>
        </td>
        <td
align="left" style="width: 50%;">
<input type="file" id="uploadfile" onchange="importf(this);"/> </td> </table> <div style="width:80%;margin-left:10%;margin-top:30px;"> <div style="width:30%;height:100%;float:left;"> <table id="txtArea1" style
="width:100%;" cellspacing="0" cellpadding="0">
</table> </div> <div style="width:30%;height:100%;margin-left:5%;margin-right:5%;float:left;"> <table id="txtArea2" style="width:100%;" cellspacing="0" cellpadding="0"> </table> </div> <div style="width:30%;height:100%;float:left;"
>
<table id="txtArea3" style="width:100%;" cellspacing="0" cellpadding="0"> </table> </div> </div>

js程式碼:

<script type="text/javascript">
    // 遍歷每張表讀取
    var persons1 = [];
    var persons2 = [];
    var persons3 = [];

    function importf(obj) {
        var wb;// 讀取完成的資料
        var f = obj.files[0];

        var reader = new FileReader();
        reader.onload = function(e) {
            var data = e.target.result;
            wb = XLSX.read(data, {
                type : 'binary'
            });   // 以二進位制流方式讀取得到整份excel表格物件

            // 表格的表格範圍,可用於判斷表頭是否數量是否正確
            var fromTo = '';
            // wb.SheetNames[0]是獲取Sheets中第一個Sheet的名字
            // wb.Sheets[Sheet名]獲取第一個Sheet的資料JSON.stringify(XLSX.utils.sheet_to_json(wb.Sheets[wb.SheetNames[0]]));
            for (var i = 0; i < wb.SheetNames.length; i++) {
                if (wb.Sheets.hasOwnProperty(wb.SheetNames[i])) {
                    fromTo = wb.Sheets[wb.SheetNames[i]]['!ref']; // output: A1:D5
                    if(i==0){
                        persons1 = persons1.concat(XLSX.utils.sheet_to_json(wb.Sheets[wb.SheetNames[i]]));
                    }else if(i==1){
                        persons2 = persons2.concat(XLSX.utils.sheet_to_json(wb.Sheets[wb.SheetNames[i]]));
                    }else if(i==2){
                        persons3 = persons3.concat(XLSX.utils.sheet_to_json(wb.Sheets[wb.SheetNames[i]]));
                    }
                    //break; //如果只取第一張表,就加上這行
                }
            }
            //document.getElementById("txtArea1").innerHTML= JSON.stringify(persons1)+JSON.stringify(persons2)+JSON.stringify(persons3);
            appendTr("txtArea1",persons1);
            appendTr("txtArea2",persons2);
            appendTr("txtArea3",persons3);
        };        

        reader.readAsBinaryString(f);
    }

    function appendTr(id, array){
        if(array.length>0){
            for(var i = 0; i < array.length; i++){
                o=document.createElement("TR");  //<td align="center" width="20%" class="cx-nr"><%=orgname%></td>

                // 所屬公司
                o1=document.createElement("TD");
                o1.innerHTML=array[i].所屬公司;
                o1.setAttribute("align","center");
                o1.setAttribute("width","50%");
                o1.setAttribute("class","cx-nr");

                // 參賽人員
                o2=document.createElement("TD");
                o2.innerHTML=array[i].參賽人員;
                o2.setAttribute("align","center");
                o2.setAttribute("width","50%");
                o2.setAttribute("class","cx-nr1");

                o.appendChild(o1);
                o.appendChild(o2);
                document.getElementById(id).appendChild(o); 
            }
        }
    }
</script>

二:匯出功能

var json;
var tmpdata;//?
var tmpdata1 = [];
var tmpdata2 = [];
var tmpdata3 = [];
var outputPos1;
var outputPos2;
var outputPos3;
var json1;
var json2;
var json3;
function getJson(num){
    var tabLen = document.getElementById("jinji"+num);
    var jsonStr = "[";
    for (var i = 1; i < tabLen.rows.length; i++) {
        jsonStr += '{"十六強":"' + tabLen.rows[i].cells[0].innerHTML + '","八強":"' + tabLen.rows[i].cells[1].innerHTML + '","四強":"' + tabLen.rows[i].cells[2].innerHTML + '"},'
    }
    jsonStr= jsonStr.substr(0, jsonStr.length - 1);
    jsonStr += "]";
    if(num==1) json1 = JSON.parse(jsonStr);  //將json字串轉換為json陣列
    if(num==2) json2 = JSON.parse(jsonStr);  //將json字串轉換為json陣列
    if(num==3) json3 = JSON.parse(jsonStr);  //將json字串轉換為json陣列
}

function getTmpdataOutputPos(num){
    if(num==1){json=json1; tmpdata = json1[0]; json1.unshift({});}
    if(num==2){json=json2; tmpdata = json2[0]; json2.unshift({});}
    if(num==3){json=json3; tmpdata = json3[0]; json3.unshift({});}
    //var tmpdata = json[0];
    //json.unshift({});
    var keyMap = []; //獲取keys
    for (var k in tmpdata) {
        keyMap.push(k);
        json[0][k] = k;
    }
    if(num==1){
        tmpdata1 = [];//用來儲存轉換好的json 
        json.map((v, i) => keyMap.map((k, j) => Object.assign({}, {
            v: v[k],
            position: (j > 25 ? getCharCol(j) : String.fromCharCode(65 + j)) + (i + 1)
        }))).reduce((prev, next) => prev.concat(next)).forEach((v, i) => tmpdata1[v.position] = {
            v: v.v
        });
        outputPos1 = Object.keys(tmpdata1); //設定區域,比如表格從A1D10
    }else if(num==2){
        tmpdata2 = [];//用來儲存轉換好的json 
        json.map((v, i) => keyMap.map((k, j) => Object.assign({}, {
            v: v[k],
            position: (j > 25 ? getCharCol(j) : String.fromCharCode(65 + j)) + (i + 1)
        }))).reduce((prev, next) => prev.concat(next)).forEach((v, i) => tmpdata2[v.position] = {
            v: v.v
        });
        outputPos2 = Object.keys(tmpdata2); //設定區域,比如表格從A1D10
    }else if(num==3){
        tmpdata3 = [];//用來儲存轉換好的json 
        json.map((v, i) => keyMap.map((k, j) => Object.assign({}, {
            v: v[k],
            position: (j > 25 ? getCharCol(j) : String.fromCharCode(65 + j)) + (i + 1)
        }))).reduce((prev, next) => prev.concat(next)).forEach((v, i) => tmpdata3[v.position] = {
            v: v.v
        });
        outputPos3 = Object.keys(tmpdata3); //設定區域,比如表格從A1D10
    }

}

var tmpDown; //匯出的二進位制物件
function PromotionTeamToExcel(type) {
    getJson(1);  //女單
    getJson(2);  //男單
    getJson(3);  //混雙
    var uploadfile2 = document.getElementById("uploadfile2").value;
    var filename = uploadfile2.substring(uploadfile2.lastIndexOf("\\")+1);
    document.getElementById("hf").download=filename;

    getTmpdataOutputPos(1);  //json1
    getTmpdataOutputPos(2);  //json2
    getTmpdataOutputPos(3);  //json3
    var tmpWB = {
        SheetNames: ['女單晉級','男單晉級','混雙晉級'], //儲存的表標題
        Sheets: {
            '女單晉級': Object.assign({},
                tmpdata1, //內容
                {
                    '!ref': outputPos1[0] + ':' + outputPos1[outputPos1.length - 1] //設定填充區域
                }),
            '男單晉級': Object.assign({},
                tmpdata2, //內容
                {
                    '!ref': outputPos2[0] + ':' + outputPos2[outputPos2.length - 1] //設定填充區域
                }),
            '混雙晉級': Object.assign({},
                tmpdata3, //內容
                {
                    '!ref': outputPos3[0] + ':' + outputPos3[outputPos3.length - 1] //設定填充區域
                })
        }
    };
    tmpDown = new Blob([s2ab(XLSX.write(tmpWB, 
        {bookType: (type == undefined ? 'xlsx':type),bookSST: false, type: 'binary'}//這裡的資料是用來定義匯出的格式型別
        ))], {
        type: ""
    }); //建立二進位制物件寫入轉換好的位元組流
    var href = URL.createObjectURL(tmpDown); //建立物件超連結
    document.getElementById("hf").href = href; //繫結a標籤
    document.getElementById("hf").click(); //模擬點選實現下載
    setTimeout(function() { //延時釋放
        URL.revokeObjectURL(tmpDown); //用URL.revokeObjectURL()來釋放這個object URL
    }, 100);
}

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;
}
// 將指定的自然數轉換為26進製表示。對映關係:[0-25] -> [A-Z]。
function getCharCol(n) {
    let temCol = '',
    s = '',
    m = 0
    while (n > 0) {
        m = n % 26 + 1
        s = String.fromCharCode(m + 64) + s
        n = (n - m) / 26
    }
    return s
}

補充1:合併單元格,但是設定單元格樣式無效

<!DOCTYPE html>
<html> 
<head> 
    <meta charset="UTF-8"> 
    <title></title> 
</head> 
<body> 
<script src="http://oss.sheetjs.com/js-xlsx/xlsx.full.min.js"></script> 
<script> 
    //如果使用 FileSaver.js 就不要同時使用以下函式 
    function saveAs(obj, fileName) {
        //當然可以自定義簡單的下載檔案實現方式 
        var tmpa = document.createElement("a"); 
        tmpa.download = fileName || "下載"; 
        tmpa.href = URL.createObjectURL(obj); //繫結a標籤 
        tmpa.click(); //模擬點選實現下載 
        setTimeout(function () { //延時釋放 
            URL.revokeObjectURL(obj); //用URL.revokeObjectURL()來釋放這個object URL 
        }, 100); 
    } 
    var json = [{ //測試資料 
        "分組": 1,//A 
        "所屬公司": "aa",
        "參賽人員": "bb"
    }, { 
        "分組": 2, 
        "所屬公司": "cc", 
        "參賽人員": "dd"
    }, { 
        "分組": 3, 
        "所屬公司": "ee", 
        "參賽人員": "ff"
    }];

    const wopts = { bookType: 'xlsx', bookSST: true, type: 'binary' };//這裡的資料是用來定義匯出的格式型別 
    function downloadExl(type) {
        var wb = { SheetNames: ['Sheet1'], Sheets: {}, Props: {} }; 
        //wb.Sheets['Sheet1'] = XLSX.utils.json_to_sheet(json);//通過json_to_sheet轉成單頁(Sheet)資料 
        json = XLSX.utils.json_to_sheet(json); 
        json["A2"] = { t: "s", v: "A組" }; 
        json["!merges"] = [{//合併第一列資料[A2,A3,A4,A5] 
            s: {//s為開始 
                c: 0,//開始列 
                r: 1//開始行
            }, e: {//e結束 
                c: 0,//結束列 
                r: 4//結束行
            } 
        }]; 
        wb.Sheets['Sheet1'] = json; 
        saveAs(
        new Blob([s2ab(XLSX.write(wb, wopts))], { type: "application/octet-stream"}), 
        "這裡是下載的檔名" + '.' + (wopts.bookType == "biff2" ? "xls" : wopts.bookType)); 
    } 
    function s2ab(s) { 
        if (typeof ArrayBuffer !== 'undefined') { 
            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; 
        } else { 
            var buf = new Array(s.length); 
            for (var i = 0; i != s.length; ++i) buf[i] = s.charCodeAt(i) & 0xFF; 
            return buf; 
        } 
    } 
</script> 
<button onclick="downloadExl()">匯出</button> 
</body> 
</html>

補充2:合併單元格,可以設定單元格的寬度、居中、字型、顏色等
下載protobi/js-xlsx:https://github.com/protobi/js-xlsx
將js-xlsx-master\dist\xlsx.full.min.js放到js目錄中

<script type="text/javascript" src="js/xlsx.full.min.js"></script>
<input type="button" onclick="PromotionTeamToExcel();" value="匯出為Excel"/>
    var resGroup = ["A組","B組","C組","D組","E組","F組","G組","H組"];
    function saveAs(obj, fileName) {
        var tmpa = document.createElement("a");
        tmpa.download = fileName || "下載";
        tmpa.href = URL.createObjectURL(obj);
        tmpa.click();
        setTimeout(function () {
            URL.revokeObjectURL(obj);
        }, 100);
    }        

    const wopts = { bookType: 'xlsx', bookSST: true, type: 'binary', cellStyles: true };        
    function PromotionTeamToExcel(type) {
        var jsonStr = "[";
        for (var i = 0; i < result.length; i++) {
            jsonStr += '{"分組":"","所屬公司":"' + $('#t'+i+'-1').text() + '","參賽人員":"' + $('#t'+i+'-2').text() + '"},'
        }
        jsonStr= jsonStr.substr(0, jsonStr.length - 1);
        jsonStr += "]";
        var json = JSON.parse(jsonStr);  //將json字串轉換為json陣列

        var tmpdata = json[0];
        json.unshift({});            
        var keyMap = []; //獲取keys
        for (var k in tmpdata) {
            keyMap.push(k);
            json[0][k] = k;
        }            
        var tmpdata = [];//用來儲存轉換好的json 
        json.map((v, i) => keyMap.map((k, j) => Object.assign({}, {v: v[k], position: (j > 25 ? getCharCol(j) : String.fromCharCode(65 + j)) + (i + 1)
        }))).reduce((prev, next) => prev.concat(next)).forEach((v, i) => tmpdata[v.position] = {v: v.v});            
        var outputPos = Object.keys(tmpdata); //設定區域,比如表格從A1到D10

        //t = [[2,5],[6,9],[10,13],[14,17],[18,21],[22,25],[26,28],[29,31]];
        //t = [[2,5],[6,9],[10,13],[14,17],[18,21],[22,24],[25,27],[28,30]];
        //t = [[2,5],[6,9],[10,13],[14,17],[18,20],[21,23],[24,26],[27,29]];
        //t = [[2,5],[6,9],[10,13],[14,16],[17,19],[20,22],[23,25],[26,28]];
        //t = [[2,5],[6,9],[10,12],[13,15],[16,18],[19,21],[22,24],[25,27]];
        //t = [[2,5],[6,8],[9,11],[12,14],[15,17],[18,20],[21,23],[24,26]];
        var end = 0;
        var t = [];
        for(var i = 0; i < 8; i++){
            // 分組
            if(end < ((result.length%8)*4+1)){
                end = 4*(i+1)+1;
                t[i] = [end-3,end];
            }else{
                end = end+3;
                t[i] = [end-2,end];
            }
        }

        //列的寬度
        tmpdata["!cols"] = [{wpx: 80}, {wpx: 160}, {wpx: 160}];

        //合併單元格
        var merges=[];
        for(var i = 0; i < 8; i++){
            merges.push({s: {c: 0, r: t[i][0]-1}, e: {c: 0, r: t[i][1]-1}});
        }
        tmpdata["!merges"] = merges;

        //每個合併單元格的資料
        for(var i = 0; i < 8; i++){
            tmpdata["A"+t[i][0]] = { t: "s", v: resGroup[i], s: {alignment: {horizontal: "center", vertical: "center"} } };
        }

        //設定單元格居中顯示
        for(var i = 0; i < result.length; i++){
            var ii=i+2;
            tmpdata["B"+ii].s = {alignment: {horizontal: "center", vertical: "center"} };
            tmpdata["C"+ii].s = {alignment: {horizontal: "center", vertical: "center"} };
        }

        //設定標題字型、加粗、居中
        tmpdata["A1"].s = {font: { sz: 13, bold: true, }, alignment: {horizontal: "center", vertical: "center", wrap_text:true} };//<====設定xlsx單元格樣式
        tmpdata["B1"].s = {font: { sz: 13, bold: true, }, alignment: {horizontal: "center", vertical: "center", wrap_text:true} };//<====設定xlsx單元格樣式
        tmpdata["C1"].s = {font: { sz: 13, bold: true, }, alignment: {horizontal: "center", vertical: "center", wrap_text:true} };//<====設定xlsx單元格樣式

        var tmpWB = {
            SheetNames: ['sheet1'], //儲存的表標題
            Sheets: {
                'sheet1': Object.assign({}, tmpdata, {                            
                    '!ref': outputPos[0] + ':' + outputPos[outputPos.length - 1] //設定填充區域
                })
            }
        };
        tmpDown = new Blob([s2ab(XLSX.write(tmpWB, { bookType: (type == undefined ? 'xlsx' : type), bookSST: false, type: 'binary' }))], {type: ""});
        saveAs(tmpDown, title + '.' + (wopts.bookType == "biff2" ? "xls" : wopts.bookType));
    }        

    function getCharCol(n) {            
        let temCol = '',
            s = '',
            m = 0
        while (n > 0) {
            m = n % 26 + 1
            s = String.fromCharCode(m + 64) + s
            n = (n - m) / 26
        }            
        return s;
    }
    function s2ab(s) {
        if (typeof ArrayBuffer !== 'undefined') {               
            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;
        } else {                
            var buf = new Array(s.length);                
            for (var i = 0; i != s.length; ++i) buf[i] = s.charCodeAt(i) & 0xFF;                
            return buf;
        }
    }