复杂grid 支持多表头,固定表头,冻结列,合并行

34 篇文章 0 订阅

该组件支持三种渲染形态,因为有些简单的表格没必要去做太复杂的处理。

支持自适应页面宽度和可以设置固定宽度,理论上是所有浏览器都支持,但是因为我引用了一些工具类,处理数组的filter、map 所以向前兼容可以自己实现这些方法

第一种:不需要固定头和列,纯普通表格。

第二种:只需要固定头,滚动内容区域 

第三种:需要固定列。

本身想采用虚拟DOM来常渲染,因为这种组件对性能消耗挺大,后面想了一下本来就是来提供大家一个思路的例子没必要写的太复杂,现在的话写的还算比较简单只有几百行,如果代码量很多对于一个想研究这类组件的同学可能压力很多。



     require(['yg'], function () {


                    (function () {


                        function FTable(columns)
                        {
                            this.columns = columns;
                            this.unionColumns = concatColumn(columns);
                            
                            this.colgroup = null;
                            this.thead = null;
                            this.tbody = null;
                            this.wrapper = $('<div>');
                            this.element = $('<table class="fx-table">').appendTo(this.wrapper);
                            this.initColgroup();


                        }


                        FTable.prototype.getFixedColumns=function()
                        {
                            return Yg._.filter(this.unionColumns, { fixed: true })
                        }
                        FTable.prototype.forColumnWidth = function (viewWidth,callback) {
                            var unionColumns = this.unionColumns, count = unionColumns.length, totalWidth = 0, surplusWidth, columnWidth;
                            function getValue(value) {
                                value = parseInt(value);
                                return String(value).indexOf('%') != -1 ? value / 100 * viewWidth : value;
                            }
                            for (var i = 0; i < count; i++) {
                                if (callback(unionColumns[i])===true) {
                                    totalWidth += getValue(unionColumns[i].width);


                                }
                            }
                            return totalWidth;
                        }
                        FTable.prototype.getColumnWidth = function (viewWidth) {
                            return Math.max(this.forColumnWidth(viewWidth, function (c) { return Yg._.has(c, 'width');}), viewWidth)
                        }
                        FTable.prototype.getFixedColumnWidth = function (viewWidth) {
                            return this.forColumnWidth(viewWidth, function (c) { return Yg._.has(c, 'width')&&c.fixed; });
                        }
                        FTable.prototype.getHeight=function()
                        {
                            return this.element.outerHeight();
                        }
                        FTable.prototype.getWidth = function () {
                            return this.element.outerWidth();
                        }


                        FTable.prototype.setWidth = function (width)
                        {
                            this.element.width(width);
                        }
                        FTable.prototype.setHeight = function (height) {
                            this.element.height(height);
                        }
                        FTable.prototype.setOuterWidth = function (width) {
                            this.wrapper.width(width);
                        }
                        FTable.prototype.setOuterHeight = function (height) {
                            this.wrapper.height(height);
                        }


                        FTable.prototype.setStyle=function(styles)
                        {
                            this.element.css(styles);
                        }
                        FTable.prototype.clone=function()
                        {
                            return new FTable(this.columns);
                        }
    
                        FTable.prototype.initColgroup=function()
                        {
                            this.colgroup = new Colgroup(this.unionColumns);
                        }
                        FTable.prototype.setHead = function (thead)
                        {
                            this.thead = thead;
                        }
                        FTable.prototype.initHead = function (visibleNoFixed)
                        {
                            this.thead = new FTHead(this.columns, visibleNoFixed);
                        }
                        FTable.prototype.initBody = function (visibleNoFixed) {
                            this.tbody = new FTBody(this.unionColumns, visibleNoFixed);
                        }
                        FTable.prototype.renderData=function(data)
                        {
                            this.tbody.renderData(data);
                            this.trigger('onRenderData',data);
                        }
       
                        FTable.prototype.render=function(parent)
                        {
                            this.colgroup.render(this.element);
                            this.thead && this.thead.render(this.element);
                            this.tbody && this.tbody.render(this.element);
                            parent.append(this.wrapper);


                        }
                        Yg.extend(FTable.prototype, Yg.Events);
                        function Colgroup(columns)
                        {
                            this.element = $('<colgroup>');
                            Yg.each(columns, Yg.bind(this.addCol, this));
                        }
                        Colgroup.prototype.addCol = function (column) {
                            var col = $('<col>');
                            if (column.hasOwnProperty('width')) {
                                col.css({ width: column.width });
                            }
                            col.appendTo(this.element);
                        }
                        Colgroup.prototype.render=function(parent)
                        {


                            parent.append(this.element);
                        }
                        function FTHead(columns, visibleNoFixed)
                        {
                            this.visibleNoFixed = visibleNoFixed;
                            this.element = $('<thead>');
                            this.addRow(columns);
                        }
                        FTHead.prototype.rowDepth = function (columns, len)
                        {
                            var childColumns = [];
                            for (var i = 0, length = columns.length; i < length; i++) {
                                if (Yg._.has(columns[i], 'columns') && columns[i].columns.length > 0)
                                {
                                    childColumns = childColumns.concat(columns[i].columns);
                                }
                            }
                            if(childColumns.length>0)
                            {
                                return this.rowDepth(childColumns,len+1);
                            }
                            return len;
                        }
                        FTHead.prototype.colDepth = function (columns, len) {
                            var childColumns = [], length = columns.length;
                            for (var i = 0; i < length; i++) {
                                if (Yg._.has(columns[i], 'columns') && columns[i].columns.length > 0) {
                                    childColumns = childColumns.concat(columns[i].columns);
                                }
                            }
                            if (childColumns.length > 0) {
                                return this.colDepth(childColumns, len +length-1);
                            }
                            return len + length;
                        }
                        FTHead.prototype.addRow = function (columns) {
                            var tr = $('<tr>'), childColumns = [], that = this, rowSpan = this.rowDepth(columns,1);
                            Yg.each(columns, function (column) {
                                that.addCell(tr, column, rowSpan);
                                if (Yg._.has(column, 'columns'))
                                {
                                    childColumns = childColumns.concat(column.columns);
                                }
                            });
                            this.element.append(tr);
                            if(childColumns.length>0)
                            {
                                this.addRow(childColumns);
                            }
                        }


                        FTHead.prototype.addCell = function (parent, column, rowSpan) {
                            var cell = $('<th>'), crowSpan = 0, attrs = {};
                            if (Yg._.has(column, "headFormat"))
                            {
                                var template = Yg._.isFunction(column.headFormat) ? column.headFormat : Yg._.template(column.headFormat)
                                cell.html(template(column));
                            } else {
                                cell.text(column.title);
                            }
                            if (Yg._.has(column, "headAttrs")) {
                                attrs = Yg.extend(attrs, column.headAttrs);
                            }
                            if (Yg._.has(column, 'columns') && column.columns.length>0)
                            {
                                attrs.colspan = this.colDepth(column.columns, 0);
                                crowSpan = this.rowDepth(column.columns, 1)
                            }
                            if (this.visibleNoFixed && !column.fixed) {
                                cell.addClass('fx-hidden');
                            }
                            rowSpan -= crowSpan;
                            if (rowSpan > 1)
                            {
                                attrs.rowspan = rowSpan;
                            }
                            cell.attr(attrs);
                            parent.append(cell);
                        }
                        FTHead.prototype.render = function (parent)
                        {
                            parent.append(this.element);
                        }


                        function concatColumn(unionColumns)
                        {
                            var column, columns=[];
                            for (var i = 0, len = unionColumns.length; i < len; i++) {
                                column = unionColumns[i];
                                if (Yg._.has(column, 'columns')) {
                                   Yg.each(column.columns,function(c){
                                        c.fixed=column.field;
                                    });
                                   columns.push.apply(columns,concatColumn(column.columns));
                                } else {
                                    columns.push(column);
                                }
                            }
                            return columns;
                        }


                        function FTBody(columns, visibleNoFixed)
                        {
                            Yg.bindAll(this, 'addRow');
                            this.visibleNoFixed = visibleNoFixed;
                            this.columns = columns;
                            this.element = $('<tbody>');
                        }
                        FTBody.prototype.addRow = function (rowData) {
                            var that=this, tr = $('<tr>'), columns=this.columns;
                            Yg.each(columns, function (column) {
                                that.addCell(tr, column,rowData);
                            });
                            this.element.append(tr);
                        }


                        FTBody.prototype.addCell = function (parent, column, rowData) {
                            var cell = $('<td>'), attrs = {};
                            if (Yg._.has(column, "format")) {
                                var template = Yg._.isFunction(column.format) ? column.format : Yg._.template(column.format)
                                cell.html(template(rowData, column));
                            } else {
                                cell.text(rowData[column.field]);
                            }
                            if (Yg._.has(column, "attrs")) {
                                attrs = Yg.extend(attrs, column.attrs);
                            }
                            if (this.visibleNoFixed &&!column.fixed)
                            {
                                cell.addClass('fx-hidden');
                            }
                            cell.attr(attrs);
                            if (Yg._.has(column, "rowSpan")) {
                                var rowSpan = column.rowSpan(rowData, column),isNumber=typeof rowSpan=="number";
                                if (isNumber && rowSpan > 1)
                                {
                                    cell.attr('rowspan', rowSpan);
                                } else if (isNumber && rowSpan < 0) {
                                    return;
                                }                             
                              
                            }
                            parent.append(cell);
                        }
                        FTBody.prototype.renderData = function (data) {
                            data = data || [];
                            this.element.empty();
                            Yg.each(data, this.addRow);
                        }
                        FTBody.prototype.render = function (parent)
                        {
                            parent.append(this.element);
                        }


  
                        function getStyleValue(value,defaultValue)
                        {
                            return value != 'auto' && value != null ?parseInt(value):defaultValue;
                        }


                        var defaultOptions = {
                            columns: [],
                            dataSource: null,
                            autobind: true,
                            width: 'auto',
                            height: 'auto'
                        };


                        var Grid = function (element,options) {
                            this.options = $.extend({}, defaultOptions, options);
                            this.container = $(element).addClass('fx-table-container');
                            this.contentTable = null;
                            this.wrapper = $('<div class="fx-table-wrapper"><div class="fx-head"></div><div class="fx-body"></div></div>').appendTo(this.container);
                            this.initViewSize();
                            this.init();
                        }
                        Grid.prototype.initViewSize = function () {
                            var viewWidth = this.container.width(), options = this.options;
      
                            this._width = getStyleValue(options.width, 0);
                            this._height = getStyleValue(options.height, 0);
                            this.isScroll = this._width > 0 || this._height > 0;
                            this.viewWidth = viewWidth;
                            if (this._width > 0) {
                                this.container.css({
                                    width: this._width
                                });
                            }
                        }                      
                        Grid.prototype.init=function()
                        {
                            var options = this.options;
                            Yg.bindAll(this, '_successHandler','_failHandler');
                            this.dataSource = Yg.parseDataSource(this.options.dataSource);
                            this.dataSource.then(this._successHandler, this._failHandler);
                            this.render();
                            if (options.autobind) {
                                this.dataSource.read();
                            }
                        }
                        Grid.prototype._successHandler=function(data)
                        {
                            this.contentTable.renderData(data);
                        }
                        Grid.prototype._failHandler = function () {


                        }
                        Grid.prototype.initTable= function () {
                            this.contentTable = new FTable(this.options.columns);
                            this.isFixedColumn = this.contentTable.getFixedColumns().length > 0;
                        }
                        Grid.prototype.initBody = function () {
                           
                        }
                        Grid.prototype._setHeadStyle=function(element)
                        {
                            element.addClass('fx-head-table fx-hidden-scroll');
                        }
                        Grid.prototype._setBodyStyle = function (element) {
                            element.addClass('fx-body-table fx-body-scroll');
                        }
                        Grid.prototype._setFixedHeadStyle = function (element) {
                            element.addClass('fx-head-table fx-head-fixed fx-hidden-scroll');
                        }
                        Grid.prototype._setFixedBodyStyle = function (element) {
                            element.addClass('fx-body-table fx-hidden-scroll fx-body-fixed');
                        }
                      
                        Grid.prototype.initFixedTable=function()
                        {
                            var that = this, options = that.options,
                                viewWidth=that.viewWidth,
                                width = that._width,
                                height = that._height,
                                contentTable = that.contentTable, isFixedColumn = that.isFixedColumn,
                                elFxHead = that.wrapper.children('.fx-head'),
                                elFxBody = that.wrapper.children('.fx-body'),
                                 fHead = contentTable.clone(),
                                     fixedBody, fixedHead, isScrollY = false, isScrollX=false;
                           
       
                            fHead.wrapper.addClass('fx-head-table fx-hidden-scroll');
                            contentTable.wrapper.addClass('fx-body-table fx-body-scroll');
                            //获取表格宽度
                            var tableWidth = contentTable.getColumnWidth(width);
                            var fixedWidth = contentTable.getFixedColumnWidth(width);


                            function setTableLayout()
                            {                               
                                if (width > 0) {
               
                                    // 设置固定宽度        
                                    fHead.setWidth(tableWidth);
                                    fHead.setOuterWidth(width);
                                    contentTable.setWidth(tableWidth);
                                    contentTable.setOuterWidth(width);
                                }
                                if (height > 0&&width>0 && isScrollY)
                                {
                                    fHead.setOuterWidth(width-17);
                                    contentTable.setOuterHeight(height);
                                } else if (height > 0 && isScrollY) {
                                    fHead.wrapper.css("marginRight",'17px');
                                    contentTable.setOuterHeight(height);
                                }
                  
                                if(isFixedColumn)
                                {
                                    fixedHead.setOuterWidth(fixedWidth);
                                    fixedHead.setWidth(tableWidth);
                                    fixedBody.setOuterWidth(fixedWidth);
                                    fixedBody.setWidth(tableWidth);
                                    contentTable.wrapper.css({
                                        width: (width - fixedWidth) + 'px',
                                        marginLeft: fixedWidth+'px'
                                    });
                                    contentTable.element.css({
                                        marginLeft: (-fixedWidth) + 'px'
                                    });
                                }
                                if (isFixedColumn && height > 0 && isScrollX) {


                                    fixedBody.setOuterHeight(height-17);
                                }                          
                            }
                            if (isFixedColumn) {
                                fixedHead = contentTable.clone();
                                fixedHead.initHead(true);
                                fixedBody = contentTable.clone();
                                fixedBody.initBody(true);
                                fixedHead.render(elFxHead);
                                fixedBody.render(elFxBody);
                                fixedHead.wrapper.addClass('fx-head-table fx-head-fixed fx-hidden-scroll');
                                fixedBody.wrapper.addClass('fx-body-table fx-hidden-scroll fx-body-fixed');
                            }
                       //     setTableLayout();
                            // 初始化
                            contentTable.initBody();
                            fHead.initHead();
                            // 渲染
                            fHead.render(elFxHead);
                            contentTable.render(elFxBody);


          
                            contentTable.on('onRenderData', function (data) {
                                if (isFixedColumn)
                                {
                                    fixedBody.renderData(data);
                                }
                                // 设置 布局
                                isScrollX = contentTable.wrapper[0].scrollWidth > width
                                isScrollY = contentTable.wrapper[0].scrollHeight > height
                                setTableLayout();
                            });
                            contentTable.wrapper.on('scroll', function () {         
                                fHead&&(fHead.wrapper[0].scrollLeft = this.scrollLeft);
                                fixedBody && (fixedBody.wrapper[0].scrollTop = this.scrollTop);
                            });
                        }
                        
                
                        Grid.prototype.render=function()
                        {
                            var that = this;
                            this.initTable();
                            if (this.isFixedColumn || this.isScroll) {
                                this.initFixedTable();
                            } else {
                                this.contentTable.initHead();
                                this.contentTable.initBody();
                                this.contentTable.render({
                                    append: function (child) {
                                        that.wrapper.html(child);
                                    }
                                });
                            }


                        }
                       


                        




                        new Grid('#grid', {
                            dataSource: {
                                data: [{
                                    name: "李三",
                                    rowspan:3,
                                    age: 43,
                                    work: '北京',
                                    work2: '上海'
                                }, {
                                    name: "",
                                    rowspan:-1,
                                    age: 43,
                                    work: '北京',
                                    work2: '上海'
                                }, {
                                    name: "",
                                    rowspan:-1,
                                    age: 43,
                                    work: '北京',
                                    work2: '上海'
                                }, {
                                    name: "李四",
                                    age: 43,
                                    work: '北京',
                                    work2: '上海'
                                }, {
                                    name: "李三",
                                    age: 43,
                                    work: '北京',
                                    work2: '上海'
                                }, {
                                    name: "李四",
                                    age: 43,
                                    work: '北京',
                                    work2: '上海'
                                }, {
                                    name: "李三",
                                    age: 43,
                                    work: '北京',
                                    work2: '上海'
                                }, {
                                    name: "李四",
                                    age: 43,
                                    work: '北京',
                                    work2: '上海'
                                }, {
                                    name: "李三",
                                    age: 43,
                                    work: '北京',
                                    work2: '上海'
                                }, {
                                    name: "李四",
                                    age: 43,
                                    work: '北京',
                                    work2: '上海'
                                }, {
                                    name: "李三",
                                    age: 43,
                                    work: '北京',
                                    work2: '上海'
                                }, {
                                    name: "李四",
                                    age: 43,
                                    work: '北京',
                                    work2: '上海'
                                }]
                            },
                           width:700,
                           height:150,
                            columns: [
                                {
                                    title: '姓名',
                                    field: 'name',
                                    fixed: true,
                                    width: '200px',
                                    headAttrs: {
                                        style: 'text-align:center'
                                    },
                                    rowSpan:function(row,c)
                                    {
                                        return row.rowspan;
                                    }
                                },
                                 {
                                     title: '年龄',
                                     field: 'age',
                                     width: 100,
                                  //   fixed: ,
                                     headAttrs: {
                                         style: 'text-align:center'
                                     }
                                 }
                                 ,
                                 {
                                     title: '工作经历',
                                     headAttrs: {
                                         style: 'text-align:center'
                                     },
                                     columns: [        
                                         {
                                             title: '工作经历2',
                                             headAttrs: {
                                                 style: 'text-align:center'
                                             },
                                             columns: [
                                       {
                                           title: '工作经历2',
                                           field: 'work',
                                           width: 100,


                                       }, {
                                           title: '工作经历5',
                                           field: 'work2',
                                           width: 200,




                                       }]
                                         }, {
                                             title: '工作经历5',
                                             field: 'work2',
                                             width: 300,
                                         }
                                     ]
                                 },
                                  {
                                      title: '呵呵',
                                      field: 'age',
                                      headAttrs: {
                                          style: 'text-align:center'
                                      },
                                      width: 100,
                                  }
                            ]
                        });
                    }());


                    //$('#scrollBody').on('scroll', function () {


                    //    $('#scrollHead')[0].scrollLeft = this.scrollLeft;
                    //    $('#scrollBodyY')[0].scrollTop = this.scrollTop;
                    //});
                });

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值