sheetjs前段操作excel,点击合并拆分表格增删行列功能实现

         sheetjs的js-xlsx插件是专门为web前段处理excel表格开发的一款开源插件,插件的github地址是https://github.com/sheetjs/js-xlsx官网地址http://sheetjs.com/,它提供了excel表格的导入导出功能,为前段显示修改excel表格提供了可能,但是毕竟只是一个插件,无法实现excel的全部功能,比如表格的合并拆分这些基础的功能,这些都需要开发者自己来实现,本文将介绍如何用纯js实现excel表格的合并拆分表格以及动态插入删除行列。

0,基础知识

          js-xlsx导入excel表格的时候会生成一个sheet对象,这个对象包含了一个表格的具体数据,包括范围,合并的单元格,各单元格数据,基本样式等等,如下图:

其中"!ref"表示显示的范围,从A1到J35。"!merges"表示那些合并的单元格项,具体数据格式如下:

其中s表示开始单元格的坐标,c是列坐标,r是行坐标,都是从0开始,e表示结束单元格的坐标,我们通过修改这些数据完成单元格的合并与拆分。

var row_count = 0;
var colums_count = 0;
function refreshFromSheet() {

        var html = XLSX.utils.sheet_to_html(worksheet);
        document.getElementById('result').innerHTML = html;
        var ref = worksheet["!ref"];
        var s_e = ref.split(":");
        row_count = getRowFromId(s_e[1])+1;
        colums_count = getIndexFromId(s_e[1])+1;
        $("table tr:first-child td:first-child").css("font-size", 25);
        $("table tr td").css("text-align", "center");

    }
function readWorkbook(workbook) {
        var sheetNames = workbook.SheetNames; // 工作表名称集合
        worksheet = workbook.Sheets[sheetNames[0]]; // 这里我们只读取第一张sheet
        refreshFromSheet();
}

1,合并单元格

         我们要实现的是鼠标点击两个单元格,就合并两个单元格间的所有表格为一个,我们记录下两次点击选择的表格id,转为坐标,然后加入到shheet对象里,最后重新渲染下界面:

    var selected_split_grid_id = "";//选中的要拆分的单元格id
    var selected_grid_id = "";
    var selected_merge_grid_s = {};//要合并的开始单元格
    var selected_merge_grid_e = {};//要合并的结束单元格
    var selected_merge_grid_sid = "";//要合并的开始单元格id
    var selectedType = -1;// 0是选中工艺状态用于拆分,
    // 1是参数行选中状态用于编辑
    // 2是合并模式
    // 3是插入行
    // 4是插入列
    // 5是插入列
    // 6是插入列+
function mergeGrid() {

        if (selectedType == 2) {
            resetType()
        } else {
            selectedType = 2;
            $("#label").text("合并模式");
        }
        clearType();
    }
function resetType() {
        selectedType = -1;
        $("#label").text("编辑模式");
    }
function clearType() {
        if (selected_merge_grid_sid)
            $("#" + selected_merge_grid_sid).css("background", "#EEEEEE");
        if (grid_selected) {
            $("#" + selected_grid_id).css("background", "#eeeeee");
            grid_selected = false
        }
        selected_merge_grid_s = {};
        selected_merge_grid_e = {};
    }
var letters = [
        'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z',
        'AA', 'AB', 'AC', 'AD', 'AE', 'AF', 'AG', 'AH', 'AI', 'AJ', 'AK', 'AL', 'AM', 'AN', 'AO', 'AP', 'AQ', 'AR', 'AS', 'AT', 'AU', 'AV', 'AW', 'AX', 'AY', 'AZ'
    ];

    function getIndexFromId(str) {
        var reg = /([A-Z]+)/g;
        var result = reg.exec(str);
        return letters.indexOf(result[0]);
    }

    function getRowFromId(str) {
        var reg = /(\d+)/g;
        var result = reg.exec(str);
        return parseInt(result[0]) - 1;
    }
$("#result").on("tap", "table tbody tr td", function () {

                if (selectedType == 2) {//点击选择合并单元格
                    var colums = getIndexFromId($(this).attr("id"));
                    var row = getRowFromId($(this).attr("id"));
                    if (JSON.stringify(selected_merge_grid_s) == "{}") {
                        //选择合并的开始
                        selected_merge_grid_sid = $(this).attr("id");
                        selected_merge_grid_s.r = row;
                        selected_merge_grid_s.c = colums;
                        $(this).css("background", "#007aff");
                    } else {
                        //选择合并的结尾然后合并
                        selected_merge_grid_e.r = row;
                        selected_merge_grid_e.c = colums;
                        if (selected_merge_grid_s.r == selected_merge_grid_e.r && selected_merge_grid_s.c == selected_merge_grid_e.c) {
                            //如果第二次选择的单元格和第一次相同则取消第一次的选择
                            selected_merge_grid_s = {};
                            selected_merge_grid_e = {};
                            $("#" + selected_merge_grid_sid).css("background", "#EEEEEE");
                        } else
                        // if (selected_merge_grid_s.r == selected_merge_grid_e.r || selected_merge_grid_s.c == selected_merge_grid_e.c)
                        {
                            //如果后点在前点店面则交换两点位置信息
                            if (selected_merge_grid_s.r >= selected_merge_grid_e.r && selected_merge_grid_s.c >= selected_merge_grid_e.c) {
                                var tmpc = selected_merge_grid_s.c;
                                selected_merge_grid_s.c = selected_merge_grid_e.c;
                                selected_merge_grid_e.c = tmpc;
                                var tmpr = selected_merge_grid_s.r;
                                selected_merge_grid_s.r = selected_merge_grid_e.r;
                                selected_merge_grid_e.r = tmpr;
                            }


                            var table = document.getElementsByTagName("table")[0];
                            var sheet = XLSX.utils.table_to_sheet(table);
                            if (!sheet["!merges"]) sheet["!merges"] = [];
                            var merges = sheet["!merges"];
                            var merged = false;
                            //考虑到第一次选择的单元格可能是已合并的单元格,遍历已合并列表把新合并数据替换进去
                            if (merges) {
                                for (var i = 0; i < merges.length; i++) {
                                    var merge_s = merges[i].s;
                                    if (merge_s.c == selected_merge_grid_s.c && merge_s.r == selected_merge_grid_s.r) {
                                        merges[i].e = selected_merge_grid_e;
                                        merged = true;
                                    }
                                    if (merge_s.c == selected_merge_grid_e.c && merge_s.r == selected_merge_grid_e.r) {
                                        merges[i].s = selected_merge_grid_s;
                                        merged = true;
                                    }
                                }
                            } else {
                                merges = [];
                            }
                            //如果不是已合并单元格,就直接push进去
                            if (!merged) {
                                sheet["!merges"].push({
                                    "s": selected_merge_grid_s,
                                    "e": selected_merge_grid_e
                                });
                            }
                            worksheet = sheet;
                            refreshFromSheet();//刷新界面
                            selected_merge_grid_s = {};
                            selected_merge_grid_e = {};
                        }

                    }
                }
})

 

2,拆分单元格

       拆分单元格也是同理,根据点击选择的id,转为坐标然后遍历"!merges"数组,删除匹配的项目就完成已合并表格的删除

function splitGrid() {
        if (selectedType == 0) {
            resetType()
        } else {
            selectedType = 0;
            clearType();
            $("#label").text("拆分模式");
        }
    }
$("#result").on("tap", "table tbody tr td", function () {

                if (selectedType == 0) {//点击选择拆分单元格
                    if (selected_split_grid_id)
                        $("#" + selected_split_grid_id).css("background", "#eeeeee");

                    selected_split_grid_id = "";
                    var colums = getIndexFromId($(this).attr("id"));
                    var row = getRowFromId($(this).attr("id"));
                    var merges = worksheet["!merges"];
                    if (!merges) {
                        return;
                    }
                    var table = document.getElementsByTagName("table")[0];
                    var sheet = XLSX.utils.table_to_sheet(table);
                    var changed = false;
                    for (var j = 0; j < merges.length; j++) {
                        var srcmerge = sheet["!merges"][j];
                        if (srcmerge.s.c == colums && srcmerge.s.r == row) {
                            sheet["!merges"].splice(j, 1);
                            changed = true;
                            break;
                        }
                    }
                    if (changed) {
                        worksheet = sheet;
                        refreshFromSheet();
                        resetType();
                    }
                }
})

3,插入删除行和列

        首先扩展航和列,直接操作"!ref"字段,然后把所选中行列之后的数据全部后移

function insertRow() {

        if (selectedType == 3) {
            resetType()
        } else {
            selectedType = 3;
            $("#label").text("插入行模式,点击要插入的行");
        }
    }

    function insertRowReal(row) {
        var table = document.getElementsByTagName("table")[0];
        var sheet = XLSX.utils.table_to_sheet(table);
        sheet["!ref"] = "A1:" + letters[colums_count-1] + String(row_count + 1);
        for (var i = row_count; i >= row + 1; i--) {
            for (var j = 0; j <= colums_count-1; j++) {
                sheet[letters[j] + (i + 1)] = sheet[letters[j] + (i)];
            }
        }
        var merges = sheet["!merges"];
        var tomerge = [];
        if (merges) {
            for (var i = 0; i < merges.length; i++) {
                var s = merges[i].s;
                var e = merges[i].e;
                if (s.r == e.r && s.r == row) {
                    tomerge.push({s: {c: s.c, r: s.r}, e: {c: e.c, r: e.r}});
                    e.r = e.r + 1;
                    s.r = s.r + 1;
                } else {
                    if (e.r >= row) {
                        e.r = e.r + 1;
                    }
                    if (s.r > row) {
                        s.r = s.r + 1;
                    }
                }
            }
            for (var i = 0; i < tomerge.length; i++) {
                merges.push(tomerge[i]);
            }
        }
        worksheet = sheet;
        refreshFromSheet();
        resetType();
        generatexuhao();
    }

    function deleteRowReal(row) {
        var table = document.getElementsByTagName("table")[0];
        var sheet = XLSX.utils.table_to_sheet(table);
        sheet["!ref"] = "A1:" + letters[colums_count-1] + String(row_count - 1);
        for (var i = row + 1; i <= row_count; i++) {
            for (var j = 0; j <= colums_count-1; j++) {
                sheet[letters[j] + (i)] = sheet[letters[j] + (i + 1)];
            }
        }
        var merges = sheet["!merges"];
        var tomerge = [];
        if (merges) {
            for (var i = 0; i < merges.length; i++) {
                var s = merges[i].s;
                var e = merges[i].e;
                if (s.r == e.r && s.r == row) {
                    tomerge.push(i)
                } else {
                    if (e.r >= row) {
                        e.r = e.r - 1;
                    }
                    if (s.r > row) {
                        s.r = s.r - 1;
                    }
                }
            }
            for (var i = 0; i < tomerge.length; i++) {
                sheet["!merges"].splice(tomerge[i], 1);
            }
        }
        worksheet = sheet;
        refreshFromSheet();
        resetType();
        generatexuhao();

    }
function insertColums() {
        if (selectedType == 4) {
            resetType()
        } else {
            selectedType = 4;
            $("#label").text("插入列模式,点击要插入的列");
        }
    }

    function deleteRow() {
        if (selectedType == 5) {
            resetType()
        } else {
            selectedType = 5;
            $("#label").text("删除行模式,点击要删除的行");
        }
    }

    function deleteColums() {
        if (selectedType == 6) {
            resetType()
        } else {
            selectedType = 6;
            $("#label").text("删除列模式,点击要删除的列");
        }
    }

    function insertColumsReal(colums) {
        var table = document.getElementsByTagName("table")[0];
        var sheet = XLSX.utils.table_to_sheet(table);
        sheet["!ref"] = "A1:" + letters[colums_count ] + String(row_count);
        for (var i = colums_count ; i >= colums; i--) {
            for (var j = 0; j <= row_count; j++) {
                sheet[letters[i + 1] + (j)] = sheet[letters[i] + (j)];
            }
        }
        var merges = sheet["!merges"];
        var tomerge = [];
        if (merges) {
            for (var i = 0; i < merges.length; i++) {
                var s = merges[i].s;
                var e = merges[i].e;
                if (s.c == e.c && s.c == colums) {
                    tomerge.push({s: {c: s.c, r: s.r}, e: {c: e.c, r: e.r}});
                    e.c = e.c + 1;
                    s.c = s.c + 1;
                } else {
                    if (e.c >= colums) {
                        e.c = e.c + 1;
                    }
                    if (s.c > colums) {
                        s.c = s.c + 1;
                    }
                }
            }
            for (var i = 0; i < tomerge.length; i++) {
                merges.push(tomerge[i]);
            }
        }
        worksheet = sheet;
        refreshFromSheet();
        resetType();
    }

    function deleteColumsReal(colums) {
        var table = document.getElementsByTagName("table")[0];
        var sheet = XLSX.utils.table_to_sheet(table);
        sheet["!ref"] = "A1:" + letters[colums_count - 2] + String(row_count);
        for (var i = colums; i < colums_count-1; i++) {
            for (var j = 0; j <= row_count; j++) {
                sheet[letters[i] + (j)] = sheet[letters[i + 1] + (j)];
            }
        }
        var merges = sheet["!merges"];
        var tomerge = [];
        if (merges) {
            for (var i = 0; i < merges.length; i++) {
                var s = merges[i].s;
                var e = merges[i].e;
                if (s.c == e.c && s.c == colums) {
                    tomerge.push(i);

                } else {
                    if (e.c >= colums) {
                        e.c = e.c - 1;
                    }
                    if (s.c > colums) {
                        s.c = s.c - 1;
                    }
                }
            }
            for (var i = 0; i < tomerge.length; i++) {
                sheet["!merges"].splice(tomerge[i], 1);
            }
        }
        worksheet = sheet;
        refreshFromSheet();
        resetType();
    }
 $("#result").on("tap", "table tbody tr td", function () {
if (selectedType == 3) {
                    var row = getRowFromId($(this).attr("id"));
                    insertRowReal(row);
                } else if (selectedType == 4) {
                    var colums = getIndexFromId($(this).attr("id"));
                    insertColumsReal(colums);
                } else if (selectedType == 5) {
                    var row = getRowFromId($(this).attr("id"));
                    deleteRowReal(row);
                } else if (selectedType == 6) {
                    var colums = getIndexFromId($(this).attr("id"));
                    deleteColumsReal(colums);
                } 
})

excel导入到web前端然后导出到后台的话会丢失大量样式,我们可以在后端操作excel(java有相关类库),把前段返回的excel表格里的数据填入原excel文件里,这样即保留原文件的样式又获得了前端返回的数据。

猜你喜欢

转载自blog.csdn.net/andylou_1/article/details/88221448
今日推荐