Kendo UI框架grid的Excel導出功能改進

Kendo UI框架提供了強大的Excel導出功能,通過Grid的saveAsExcel能方便地導出Grid中的數據,而且格式美觀大方,使用起來也非常方便。但是在實際使用中不是很理想,主要有以下兩個問題:

1. 導出的列數據是原始值

Kendo UI默認導出的是該列的value值,及查出來的值,有時候我們會用template渲染一下導出的列,比如將“Y”顯示成“是”,把“N”顯示成“否”。而Kendo UI導出的卻是Y/N這種只有程序員看得懂的數據庫標識,顯然不是我們需要的,這種情況非常常見。

2. 不能靈活控制可導出的列

Kendo UI的Excel導出主要看兩點,一是該列(column)是field字段,而不是自定義的name;二是該列不是隱藏的(hidden:true)。這樣我們無法靈活導出我們需要的列。


爲了解決上面兩個問題,我查看了Kendo UI的源代碼,提取並改進了源代碼。主要更改點及使用方法請看下面源代碼。主要針對以上兩點做了更改,只需要在grid定義columns時加上isExport或exportTemplate即可:

  • 在導出數據,先看該列有沒有自定義exportTemplate(),沒有則看Kendo UI自帶的template(),再沒有才會導出查出來的值。
  • 判斷是否導出該列不再看hidden屬性,而是看列的isExport屬性,如果爲false則不導出,其它情況一律導出該列。

經過這兩個更改,基本可以應對所有業務場景,可以方便快捷地開發了!
但要注意,Kendo UI自帶的導出功能無法應用於導出大量數據,似乎是瀏覽器的jvm溢出了,建議超過5萬條的數據導出還是老老實實寫後臺導出功能吧。下篇文章將介紹使用POI導出百萬級別數據。
js代碼下載鏈接:https://download.csdn.net/download/qq_28830129/10628102

/**
 * @summary ExcelExport
 * @description 基於Kendo UI框架的Excel導出操作
 * 使用方式:
 *  1.引入該js,需在kendo ui的js之後
 *  2.定義一個grid,通過id獲取其JQuery對象
 *  3.調用saveAsExclePro()方法
 *  如:$("#Grid").saveAsExclePro()
 * grid新增column輔助屬性說明:
 *  isExport:
 *      作爲grid.column的補充屬性,爲false時該column不導出
 *      與grid.saveAsExcle()不同,hidden爲true時同樣會導出
 *  exportTemplate:
 *      類似grid.column的template屬性,是一個函數,參數爲dataItem
 *      如果不指定該屬性,將使用grid.column的template屬性的渲染值作爲導出值,也沒有就以原始Value導出
 * 注意:調用該導出方法不會觸發grid的導出Excel相關事件
 * @version 1.0
 * @author chong.luo
 */
!(function ($) {
    if (!window.ExcelExport) {
        ExcelExport = {
            version: '1.0'
        };

    MyExcelExporter = kendo.Class.extend({
        init: function (options) {
            options.columns = this._trimColumns(options.columns || []);
            this.allColumns = $.map(this._leafColumns(options.columns || []), this._prepareColumn);
            //---更改1---更改導出列的篩選,isExport爲false不導出
            this.columns = $.grep(this.allColumns, function (column) {
                if(column.isExport == false){
                    return false;
                }
                return true;
                //return !column.hidden;
            });
            this.options = options;
            var dataSource = options.dataSource;
            if (dataSource instanceof kendo.data.DataSource) {
                this.dataSource = new dataSource.constructor($.extend({}, dataSource.options, {
                    page: options.allPages ? 0 : dataSource.page(),
                    filter: dataSource.filter(),
                    pageSize: options.allPages ? dataSource.total() : dataSource.pageSize(),
                    sort: dataSource.sort(),
                    group: dataSource.group(),
                    aggregate: dataSource.aggregate()
                }));
                var data = dataSource.data();
                if (data.length > 0) {
                    this.dataSource._data = data;
                    var transport = this.dataSource.transport;
                    if (dataSource._isServerGrouped() && transport.options && transport.options.data) {
                        transport.options.data = null;
                    }
                }
            } else {
                this.dataSource = kendo.data.DataSource.create(dataSource);
            }
        },
        _trimColumns: function (columns) {
            var that = this;
            return $.grep(columns, function (column) {
                var result = !!column.field;
                if (!result && column.columns) {
                    result = that._trimColumns(column.columns).length > 0;
                }
                return result;
            });
        },
        _leafColumns: function (columns) {
            var result = [];
            for (var idx = 0; idx < columns.length; idx++) {
                if (!columns[idx].columns) {
                    result.push(columns[idx]);
                    continue;
                }
                result = result.concat(this._leafColumns(columns[idx].columns));
            }
            return result;
        },
        workbook: function () {
            return $.Deferred($.proxy(function (d) {
                this.dataSource.fetch().then($.proxy(function () {
                    var workbook = {
                        sheets: [{
                                columns: this._columns(),
                                rows: this._rows(),
                                freezePane: this._freezePane(),
                                filter: this._filter()
                            }]
                    };
                    d.resolve(workbook, this.dataSource.view());
                }, this));
            }, this)).promise();
        },
        _prepareColumn: function (column) {
            if (!column.field) {
                return;
            }
            var value = function (dataItem) {
                return dataItem.get(column.field);
            };
            var values = null;
            if (column.values) {
                values = {};
                $.each(column.values, function () {
                    values[this.value] = this.text;
                });
                value = function (dataItem) {
                    return values[dataItem.get(column.field)];
                };
            }
            return $.extend({}, column, {
                value: value,
                values: values,
                groupHeaderTemplate: kendo.template(column.groupHeaderTemplate || '#= title #: #= value #'),
                groupFooterTemplate: column.groupFooterTemplate ? kendo.template(column.groupFooterTemplate) : null,
                footerTemplate: column.footerTemplate ? kendo.template(column.footerTemplate) : null
            });
        },
        _filter: function () {
            if (!this.options.filterable) {
                return null;
            }
            var depth = this._depth();
            return {
                from: depth,
                to: depth + this.columns.length - 1
            };
        },
        _dataRow: function (dataItem, level, depth) {
            if (this._hierarchical()) {
                level = this.dataSource.level(dataItem) + 1;
            }
            var cells = [];
            for (var li = 0; li < level; li++) {
                cells[li] = {
                    background: '#dfdfdf',
                    color: '#333'
                };
            }
            if (depth && dataItem.items) {
                var column = $.grep(this.allColumns, function (column) {
                    return column.field == dataItem.field;
                })[0];
                var title = column && column.title ? column.title : dataItem.field;
                var template = column ? column.groupHeaderTemplate : null;
                var value = title + ': ' + dataItem.value;
                var group = $.extend({
                    title: title,
                    field: dataItem.field,
                    value: column && column.values ? column.values[dataItem.value] : dataItem.value,
                    aggregates: dataItem.aggregates
                }, dataItem.aggregates[dataItem.field]);
                if (template) {
                    value = template(group);
                }
                cells.push({
                    value: value,
                    background: '#dfdfdf',
                    color: '#333',
                    colSpan: this.columns.length + depth - level
                });
                var rows = this._dataRows(dataItem.items, level + 1);
                rows.unshift({
                    type: 'group-header',
                    cells: cells
                });
                return rows.concat(this._footer(dataItem));
            } else {
                var dataCells = [];
                for (var ci = 0; ci < this.columns.length; ci++) {
                    dataCells[ci] = this._cell(dataItem, this.columns[ci]);
                }
                if (this._hierarchical()) {
                    dataCells[0].colSpan = depth - level + 1;
                }
                return [{
                        type: 'data',
                        cells: cells.concat(dataCells)
                    }];
            }
        },
        _dataRows: function (dataItems, level) {
            var depth = this._depth(); 
            var rows = [];
            for (var i = 0; i < dataItems.length; i++) {
                rows.push.apply(rows, this._dataRow(dataItems[i], level, depth));
            }
            return rows;
        },
        _footer: function (dataItem) {
            var rows = [];
            var footer = false;
            var cells = $.map(this.columns, $.proxy(function (column) {
                if (column.groupFooterTemplate) {
                    footer = true;
                    return {
                        background: '#dfdfdf',
                        color: '#333',
                        value: column.groupFooterTemplate($.extend({}, this.dataSource.aggregates(), dataItem.aggregates, dataItem.aggregates[column.field]))
                    };
                } else {
                    return {
                        background: '#dfdfdf',
                        color: '#333'
                    };
                }
            }, this));
            if (footer) {
                rows.push({
                    type: 'group-footer',
                    cells: $.map(new Array(this.dataSource.group().length), function () {
                        return {
                            background: '#dfdfdf',
                            color: '#333'
                        };
                    }).concat(cells)
                });
            }
            return rows;
        },
        _isColumnVisible: function (column) {
            return this._visibleColumns([column]).length > 0 && (column.field || column.columns);
        },
        _visibleColumns: function (columns) {
            var that = this;
            return $.grep(columns, function (column) {
                //---更改1---更改導出列的篩選,isExport爲false不導出
                if(column.isExport == false){
                    var result = false;
                }else{
                    var result = true;
                }
                //var result = !column.hidden;
                if (result && column.columns) {
                    result = that._visibleColumns(column.columns).length > 0;
                }
                return result;
            });
        },
        _headerRow: function (row, groups) {
            var headers = $.map(row.cells, function (cell) {
                return {
                    background: '#7a7a7a',
                    color: '#fff',
                    value: cell.title,
                    colSpan: cell.colSpan > 1 ? cell.colSpan : 1,
                    rowSpan: row.rowSpan > 1 && !cell.colSpan ? row.rowSpan : 1
                };
            });
            if (this._hierarchical()) {
                headers[0].colSpan = this._depth() + 1;
            }
            return {
                type: 'header',
                cells: $.map(new Array(groups.length), function () {
                    return {
                        background: '#7a7a7a',
                        color: '#fff'
                    };
                }).concat(headers)
            };
        },
        _prependHeaderRows: function (rows) {
            var groups = this.dataSource.group();
            var headerRows = [{
                    rowSpan: 1,
                    cells: [],
                    index: 0
                }];
            this._prepareHeaderRows(headerRows, this.options.columns);
            for (var idx = headerRows.length - 1; idx >= 0; idx--) {
                rows.unshift(this._headerRow(headerRows[idx], groups));
            }
        },
        _prepareHeaderRows: function (rows, columns, parentCell, parentRow) {
            var row = parentRow || rows[rows.length - 1];
            var childRow = rows[row.index + 1];
            var totalColSpan = 0;
            var column;
            var cell;
            for (var idx = 0; idx < columns.length; idx++) {
                column = columns[idx];
                if (this._isColumnVisible(column)) {
                    cell = {
                        title: column.title || column.field,
                        colSpan: 0
                    };
                    row.cells.push(cell);
                    if (column.columns && column.columns.length) {
                        if (!childRow) {
                            childRow = {
                                rowSpan: 0,
                                cells: [],
                                index: rows.length
                            };
                            rows.push(childRow);
                        }
                        cell.colSpan = this._trimColumns(this._visibleColumns(column.columns)).length;
                        this._prepareHeaderRows(rows, column.columns, cell, childRow);
                        totalColSpan += cell.colSpan - 1;
                        row.rowSpan = rows.length - row.index;
                    }
                }
            }
            if (parentCell) {
                parentCell.colSpan += totalColSpan;
            }
        },
        _rows: function () {
            var groups = this.dataSource.group();
            var rows = this._dataRows(this.dataSource.view(), 0);
            if (this.columns.length) {
                this._prependHeaderRows(rows);
                var footer = false;
                var cells = $.map(this.columns, $.proxy(function (column) {
                    if (column.footerTemplate) {
                        footer = true;
                        var aggregates = this.dataSource.aggregates();
                        return {
                            background: '#dfdfdf',
                            color: '#333',
                            value: column.footerTemplate($.extend({}, aggregates, aggregates[column.field]))
                        };
                    } else {
                        return {
                            background: '#dfdfdf',
                            color: '#333'
                        };
                    }
                }, this));
                if (footer) {
                    rows.push({
                        type: 'footer',
                        cells: $.map(new Array(groups.length), function () {
                            return {
                                background: '#dfdfdf',
                                color: '#333'
                            };
                        }).concat(cells)
                    });
                }
            }
            return rows;
        },
        _headerDepth: function (columns) {
            var result = 1;
            var max = 0;
            for (var idx = 0; idx < columns.length; idx++) {
                if (columns[idx].columns) {
                    var temp = this._headerDepth(columns[idx].columns);
                    if (temp > max) {
                        max = temp;
                    }
                }
            }
            return result + max;
        },
        _freezePane: function () {
            var columns = this._visibleColumns(this.options.columns || []);
            var colSplit = this._visibleColumns(this._trimColumns(this._leafColumns($.grep(columns, function (column) {
                return column.locked;
            })))).length;
            return {
                rowSplit: this._headerDepth(columns),
                colSplit: colSplit ? colSplit + this.dataSource.group().length : 0
            };
        },
        _cell: function (dataItem, column) {
            //-----更改2-----導出excel的值由temple決定,如果沒有temple才取value
            if(!!column.exportTemplate){//存在自定義導出數據模板
                return { value: column.exportTemplate(dataItem)};
            }
            return { value: (!!column.template)?column.template(dataItem):column.value(dataItem) };
            //return { value: column.value(dataItem) };
        },
        _hierarchical: function () {
            return this.options.hierarchy && this.dataSource.level;
        },
        _depth: function () {
            var dataSource = this.dataSource;
            var depth = 0;
            var view, i, level;
            if (this._hierarchical()) {
                view = dataSource.view();
                for (i = 0; i < view.length; i++) {
                    level = dataSource.level(view[i]);
                    if (level > depth) {
                        depth = level;
                    }
                }
                depth++;
            } else {
                depth = dataSource.group().length;
            }
            return depth;
        },
        _columns: function () {
            var depth = this._depth();
            var columns = $.map(new Array(depth), function () {
                return { width: 20 };
            });
            return columns.concat($.map(this.columns, function (column) {
                return {
                    width: parseInt(column.width, 10),
                    autoWidth: column.width ? false : true
                };
            }));
        }
    });

    //定義一個kendo對象:Excle
    Excel = kendo.Class.extend({
        /*extend: function (proto) {
            proto.events.push('excelExport');
            proto.options.excel = $.extend(proto.options.excel, this.options);
            proto.saveAsExcel = this.saveAsExcel;
        },*/
        options: {
            proxyURL: '',
            allPages: true,
            filterable: true,
            fileName: 'list.xlsx'
        },
        saveAsExcel: function (grid) {
            //console.log("--------開始進行導出操作,時間"+ kendo.toString(new Date(), "yyyy-MM-dd HH:mm:ss") +"----------");
            var excel = grid.options.excel || {};
            var exporter = new MyExcelExporter({
                columns: grid.columns,
                dataSource: grid.dataSource,
                allPages: excel.allPages,
                filterable: excel.filterable,
                hierarchy: excel.hierarchy
            });
            exporter.workbook().then($.proxy(function (book, data) {
                /*if (!this.trigger('excelExport', {
                        workbook: book,
                        data: data
                    })) {*/
                    var workbook = new kendo.ooxml.Workbook(book);
                    kendo.saveAs({
                        dataURI: workbook.toDataURL(),
                        fileName: book.fileName || excel.fileName,
                        proxyURL: excel.proxyURL,
                        forceProxy: excel.forceProxy
                    });
                //}
            }, this));
        }
    })
    //給JQuery對象添加全局方法
    $.fn.saveAsExclePro = function(){
        //只允許Kendo UI的Grid組件調用
        if($(this).data('kendoGrid') instanceof kendo.ui.Grid){
            Excel.prototype.saveAsExcel($(this).data('kendoGrid'));
        }

    }
    }   

})(jQuery)
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章