/* * @Author: 李燕南 * @Date: 2017-08-30 16:52:50 * @Last Modified by: 李燕南 * @Last Modified time: 2017-09-20 19:58:19 */ ;(function (factory){ if ( typeof define === "function" && define.amd ) { define( ["jquery"], factory ); } else if (typeof module === "object" && module.exports) { module.exports = factory( require( "jquery" ) ); } else { window.FixedTable = factory( jQuery ); try{ if(typeof define === "function"){ define(function (require){ return factory(require("jquery")); }); } }catch(e){} } })(function ($){ function FixedTable(options){ this._init(options); } FixedTable._sequence = 0; $.extend(FixedTable.prototype, { _init: function (options){ if(!options || !$.isPlainObject(options)){ throw "缺少init所需的对象!"; } this.options = { wrap: null,//生成的表格需要放到哪里,可以是选择器、dom对象、jQuery对象 type: "row-col-fixed",//表格类型,有:head-fixed、col-fixed、row-col-fixed extraClass: "",//需要添加到表格中的额外class /*表格的列的每一项配置为: { class: "", width: "150px", field: "日期",//可传递字段名称。也可以传递HTML代码,如果是HTML代码则,htmlDom必须为true htmlDom: false, fieldId: ,// fixed: false,//当前了列是否固定 fixedDirection: ""//如果是固定列,则该列的方向是在左边还是在右边 } */ fields: [],//表格的列 /*设置表格内容的最大高度,设置最大高度后可以上下滚动,它的值必须为number,如果不传递该参数则会自动计算*/ maxHeight: undefined, onHover: function (){}, hoverClass: "rowHover",//鼠标移动到每一行上时需要添加的class tableDefaultContent: "",//表格数据还未添加进来时显示的默认内容,可以是html字符串、dom对象、jQuery对象 init: function (){}//FixedTable对象初始化后所执行的函数 } $.extend(this.options, options); if(!this.options.fields || !$.isArray(this.options.fields) || this.options.fields.length == 0){ throw "必须传递表格的列数组!"; } this.wrap = $(this.options.wrap); this.fixedTableClass = { left: "fixed-table_fixed-left", right: "fixed-table_fixed-right" } /*固定列的下标,数组的内容必须是一个对象,且对象格式为 { index: 0,//下标 direction: "left"//固定列方向 } */ this.fixedIndex = {}; if(this.options.type != "head-fixed"){ var fields = this.options.fields, that = this; $.each(fields, function (index, item){ if(item.fixed){ if(!that.fixedIndex.left){//存储左边固定栏索引 that.fixedIndex.left = []; } if(!that.fixedIndex.right){//存储右边固定栏索引 that.fixedIndex.right = []; } var direction = (!item.fixedDirection ? "left" : item.fixedDirection).toLowerCase(); that.fixedIndex[direction].push({ index: index, direction: direction }); } }); } this.isIE = FixedTable.isIE(); this._renderFixedTable(); if(({}).toString.call(this.options["init"]) == "[object Function]"){ this.options["init"].call(this); } }, _renderFixedTable: function (){ /*渲染fixed-table-box*/ var that = this, id = "Lyn_FixedTable_" + (FixedTable._sequence ++), fixedTableBox = this.fixedTableBox = this.build.buildFixedTableBox(), fixedTableHeader = this.fixedTableHeader = this.build.buildFixedTableHeader(), fixedTableBody = this.fixedTableBody = this.build.buildFixedTableBody(); this._id = id; //设置显示类型及需额外添加的class fixedTableBox.attr("id", id).addClass(this.options.type).addClass(this.options.extraClass); fixedTableHeader.attr("data-parentid", id); fixedTableBody.attr("data-parentid", id); //添加表格数据还未添加进来时显示的默认内容 if(this.options.tableDefaultContent){ this.tableDefaultContent = $(this.options.tableDefaultContent); fixedTableBody.append(this.tableDefaultContent); } fixedTableHeader.children(".fixed-table_header").children("thead").append(this.build.buildTableTitle(this.options.fields)); fixedTableBox.append(fixedTableHeader).append(fixedTableBody); this.wrap.append(fixedTableBox); //计算table的宽度,否则table的宽度为auto,fixedTableBody就不会出现滚动条了 if(this.options.type != "head-fixed"){ var tableW = FixedTable.calTableWidth(fixedTableHeader); fixedTableHeader.find("table").data("data-width", tableW).width(tableW); fixedTableBody.find("table").data("data-width", tableW).width(tableW); } }, _sequence: 0, build: { buildFixedTableBox: function (type, sequence){ /*创建包裹table的父盒子*/ return $('
'); }, buildFixedTableHeader: function (){ /*创建表头*/ var html = ''; html += '
'; html += ' '; html += ' '; html += ' '; html += '
'; html += '
'; return $(html); }, buildFixedTableBody: function (){ /*创建表格的主体内容*/ var html =''; html += '
'; html += ' '; html += ' '; html += '
'; html += '
'; return $(html); }, buildFixedTable: function (){ /*创建固定的列盒子*/ return $('
'); }, buildTableTitle: function (data){ /*创建表格标题*/ if(!data || !$.isArray(data) || data.length == 0){return;} var html = ['']; $.each(data, function (index, item){ var attr = [], th = ''; if(item["class"]){ attr.push('class="' + item["class"] + '"'); } if(item.width){ attr.push('style="width: ' + item.width + ';"'); } if(item.fieldId){ attr.push('data-fieldid="' + item.fieldId + '"'); } if(item.fixed){ attr.push('data-fixed="' + item.fixed + '"'); if(item.fixedDirection){ attr.push('data-fixeddirection="' + item.fixedDirection + '"'); }else{ attr.push('data-fixeddirection=left'); } } //如果传递的field已经是html字符串则直接使用即可 if(item.htmlDom){ html.push(item.field); }else{ html.push('
' + item.field + '
'); } }); html.push(''); return $(html.join("")); } }, getRow: function (row){ /*根据指定任意地方的行的索引、dom对象、jquery对象获取表格中表格主体、两侧固定列对应的行*/ var rowDom = null, rowIndex = undefined, returnVal = { bodyRow: undefined, leftFixedRow: undefined, rightFixedRow: undefined }; if(typeof row != "number"){ rowDom = $(row); if(rowDom.length == 0){return;} rowIndex = rowDom.index(); }else if(typeof row == "number"){ rowIndex = row; } if(rowIndex == undefined){return this;} returnVal.index = rowIndex; returnVal.bodyRow = this.fixedTableBody.find("tbody tr").eq(rowIndex); if(this.fixedIndex.left){ returnVal.leftFixedRow = this.fixedTableBox.find(".fixed-table_fixed-left tbody tr").eq(rowIndex); } if(this.fixedIndex.right){ returnVal.rightFixedRow = this.fixedTableBox.find(".fixed-table_fixed-right tbody tr").eq(rowIndex); } return returnVal; }, deleteRow: function (row, cb){ /*删除行,参数row可以是行的索引、dom对象、jquery对象*/ var rows = this.getRow(row); if(!rows || !rows.bodyRow){return this;} rows.bodyRow.remove(); if(this.fixedIndex.left && rows.leftFixedRow){ rows.leftFixedRow.remove(); } if(this.fixedIndex.right && rows.rightFixedRow){ rows.rightFixedRow.remove(); } this._calFixedColHeight(); if(cb && ({}).toString.call(cb) == "[obejct Function]"){ cb.call(this); } return this; }, addRow: function (htmlDom, cb){ /*添加行,fn必须返回HTML字符串或jQuery对象*/ var returnVal = undefined, rowDoms = undefined, that = this; if(!htmlDom){return this;} if(({}).toString.call(htmlDom) == "[object Function]"){ returnVal = htmlDom(); }else{ returnVal = htmlDom; } if(!returnVal){return this;} rowDoms = $(returnVal); if(rowDoms.length == 0){return this;} if(this.tableDefaultContent){ this.tableDefaultContent.remove(); } this.fixedTableBody.find("tbody").append(rowDoms); if(this.options.type == "head-fixed"){return this;} if(this.fixedIndex.left || this.fixedIndex.right){ //设置固定的列 this._setFixedCol(rowDoms); //计算固定列的高度 if (this.isIE) { //在IE浏览器中连续多次计算固定列的时候会计算出负值的情况,为了避免这个情况需加个定时器 setTimeout(function (){ that._calFixedColHeight(); }, 50); }else{ that._calFixedColHeight(); } } this.rowHover(this.options.onHover); if(cb && ({}).toString.call(cb) == "[obejct Function]"){ cb.call(this); } return this; }, empty: function (cb){ /*清空表格里的所有内容*/ this.fixedTableBody.find('tbody').html(""); if(this.fixedIndex.left || this.fixedIndex.left){ this.fixedTableBox.find(".fixed-table_fixed").height(0).find('tbody').html(""); } if(cb && ({}).toString.call(cb) == "[obejct Function]"){ cb.call(this); } return this; }, rowHover: function (cb){ /*鼠标hover在每一行后所处理业务*/ var that = this, rowHover = this.options.hoverClass, bodyTrs = this.fixedTableBody.find("tr"); bodyTrs.off("mouseenter.rowHover").off("mouseleave.rowHover"); bodyTrs.on("mouseenter.rowHover", _process).on("mouseleave.rowHover", _process); if(this.fixedIndex.left){ var leftTrs = this.fixedTableBox.find(".fixed-table_fixed-left .fixed-table_body-wraper tr"); leftTrs.off("mouseenter.rowHover").off("mouseleave.rowHover"); leftTrs.on("mouseenter.rowHover", _process).on("mouseleave.rowHover", _process); } if(this.fixedIndex.right){ var rihtTrs = this.fixedTableBox.find(".fixed-table_fixed-right .fixed-table_body-wraper tr"); rihtTrs.off("mouseenter.rowHover").off("mouseleave.rowHover"); rihtTrs.on("mouseenter.rowHover", _process).on("mouseleave.rowHover", _process); } function _process(){ var $this = $(this), rows = that.getRow($this.index()); if(!rows.bodyRow){return;} rows.bodyRow.toggleClass(rowHover); rows.leftFixedRow.toggleClass(rowHover); rows.rightFixedRow.toggleClass(rowHover); if(cb && ({}).toString.call(cb) == "[obejct Function]"){ cb.call(that.fixedTableBox[0]); } } return this; }, _syncScroll: function (){ /*同步滚动*/ if(!this.fixedIndex.left || !this.fixedIndex.right){return;} var that = this, fixedTableHeader = this.fixedTableHeader, fixedCols = this.fixedTableBox.find(".fixed-table_fixed .fixed-table_body-wraper"); this.fixedTableBody.on("scroll", function (){ var $this = $(this); fixedTableHeader.scrollLeft($this.scrollLeft()); fixedCols.scrollTop($this.scrollTop()); }); }, _calFixedColHeight: function (){ if(!this.fixedIndex.left || !this.fixedIndex.right){return;} /*计算固定列的高度*/ var maxHeight = this.options.maxHeight, hasCrosswiseScroll = true,//用于判断固定列的高度是否要减去滚动条的宽度,这样才不会遮住水平滚动条 hasVerticalScroll = false,//用于判断右侧的固定列的right值是否需要加上滚动条的宽度,这样才能显示出垂直滚动条 $fixedTableBody = this.fixedTableBody, fixedTableBody = $fixedTableBody[0], scrollWidth = 0, scrollWidth2 = 0, fixedTableBodyTable = $fixedTableBody.children('table'); if(typeof maxHeight != "number"){ if(this.isIE){//IE浏览器 /*在IE浏览器中this.fixedTableBox.height()、this.fixedTableBox[0].offsetHeight获取的高度 都为0,不知道为什么,但this.fixedTableBox[0].clientHeight和this.fixedTableBox[0].scrollHeight都有值, 为了保证两边的固定列能出来,所以就使用了这种解决方案*/ maxHeight = this.fixedTableBox.height() || this.fixedTableBox[0].clientHeight || this.fixedTableBox[0].scrollHeight; }else{ maxHeight = this.fixedTableBox.height(); } } if(fixedTableBody.scrollWidth > fixedTableBody.clientWidth || fixedTableBody.offsetWidth > fixedTableBody.clientWidth){ hasCrosswiseScroll = true; }else{ hasCrosswiseScroll = false; } /*如果有水平滚动条fixedTableBody.offsetHeight会把水平滚动条的高度也计算进去,因此这里需要减去水平滚动条的高度*/ if(fixedTableBody.scrollHeight > fixedTableBody.clientHeight || (fixedTableBody.offsetHeight - FixedTable.getScrollWidth()) > fixedTableBody.clientHeight){ hasVerticalScroll = true; }else{ hasVerticalScroll = false; } if(hasCrosswiseScroll){ scrollWidth = FixedTable.getScrollWidth(); } if(hasVerticalScroll){ scrollWidth2 = FixedTable.getScrollWidth(); if(this.fixedTableBox.find(".fixed-table-box_fixed-right-patch").length == 0){ var rightPatch = $('
'), height = this.fixedTableHeader.height(); rightPatch.css({ width: scrollWidth2, height: height-2 }); this.fixedTableBox.append(rightPatch); } }else{ if(this.fixedTableBox.find(".fixed-table-box_fixed-right-patch").length == 0){ this.fixedTableBox.find(".fixed-table-box_fixed-right-patch").remove(); } } var height = maxHeight - scrollWidth, fixedTable = this.fixedTableBox.find(".fixed-table_fixed"); if(fixedTable.height() != Math.abs(height)){ fixedTable.height(maxHeight - scrollWidth); } this.fixedTableBox.find(".fixed-table_fixed.fixed-table_fixed-right").css("right", (scrollWidth2-1) < 0 ? 1 : (scrollWidth2 - 1)); }, _setFixedCol: function (rowDoms){ /*设置需要固定的列*/ var that = this, fixedIndex = this.fixedIndex, first = true,//用来判断是否生成tr leftFixedTableWrap = undefined,//左边固定栏 leftFixedTableHeader = undefined, leftFixedTableBody = undefined, rightFixedTableWrap = undefined,//右边固定栏 rightFixedTableHeader = undefined, rightFixedTableBody = undefined; if(fixedIndex.left || fixedIndex.right){//有固定列 if(fixedIndex.left && !this.fixedColCreated){//有左边固定列,并且是第一次添加数据 leftFixedTableWrap = that.build.buildFixedTable().addClass(this.fixedTableClass["left"]); leftFixedTableHeader = that.build.buildFixedTableHeader(); leftFixedTableBody = that.build.buildFixedTableBody(); }else if(fixedIndex.left && this.fixedColCreated){//有左边固定列,并且不是第一次添加数据 leftFixedTableWrap = that.fixedTableBox.find(".fixed-table_fixed-left"); leftFixedTableHeader = leftFixedTableWrap.find(".fixed-table_header-wraper"); leftFixedTableBody = leftFixedTableWrap.find(".fixed-table_body-wraper"); } if(fixedIndex.right && !this.fixedColCreated){//有右边固定列 rightFixedTableWrap = that.build.buildFixedTable().addClass(this.fixedTableClass["right"]);//右边固定栏 rightFixedTableHeader = that.build.buildFixedTableHeader(); rightFixedTableBody = that.build.buildFixedTableBody(); }else if(fixedIndex.right && this.fixedColCreated){ rightFixedTableWrap = that.fixedTableBox.find(".fixed-table_fixed-right"); rightFixedTableHeader = rightFixedTableWrap.find(".fixed-table_header-wraper"); rightFixedTableBody = rightFixedTableWrap.find(".fixed-table_body-wraper"); } }else{//无固定列 leftFixedTableWrap = that.fixedTableBox.find(".fixed-table_fixed-left"); leftFixedTableHeader = leftFixedTableWrap.find(".fixed-table_header-wraper"); leftFixedTableBody = leftFixedTableWrap.find(".fixed-table_body-wraper"); rightFixedTableWrap = that.fixedTableBox.find(".fixed-table_fixed-right"); rightFixedTableHeader = rightFixedTableWrap.find(".fixed-table_header-wraper"); rightFixedTableBody = rightFixedTableWrap.find(".fixed-table_body-wraper"); } //计算固定列的表头,表头只计算一遍 if(!this.titleFixeded){ var outerFixedTableCols = this.fixedTableHeader.find('.fixed-table_header th'), leftCloneThead = [], rightCloneThead = [], leftCount = 0, rightCount = 0, leftTr = $(""), rightTr = $(""); outerFixedTableCols.each(function(index, ele) { if(fixedIndex.left){ $.each(fixedIndex.left, function(index2, item) { if(index == item.index){ leftCloneThead.push($(ele).clone(true)); if(leftCount != 0){ //移动原来的表头列到对应位置 if(index2 != 0){ var ths = that.fixedTableHeader.find('.fixed-table_header th') //每次替换位置后需重新获取一下,否则位置会出错 ths.eq(item.index).insertAfter(ths.eq(index2-1)); } } leftCount++; } }); } if(fixedIndex.right){ $.each(fixedIndex.right, function(index2, item) { if(index == item.index){ rightCloneThead.push($(ele).clone(true)); var ths = that.fixedTableHeader.find('.fixed-table_header th'); if(index2 != ths.length - 1){ /*每次替换位置后需重新获取一下,否则位置会出错*/ outerFixedTableCols.eq(item.index).insertAfter(that.fixedTableHeader.find('.fixed-table_header th').eq(outerFixedTableCols.length - 1)); rightCount++; } } }); } }); leftFixedTableHeader && leftFixedTableHeader.find(".fixed-table_header thead").append(leftTr.append(leftCloneThead)); rightFixedTableHeader && rightFixedTableHeader.find(".fixed-table_header thead").append(rightTr.append(rightCloneThead)); this.titleFixeded = true; } var leftCloneBody = [], rightCloneBody = [], rowDomsClone = rowDoms.clone(true), leftCount = 0, rightCount = 0; //计算固定列的内容 rowDomsClone.each(function(index, ele) { var $this = $(this), leftTr = $(ele).clone(true).html(""), rightTr = $(ele).clone(true).html(""); $this.children('td').each(function (index2, td){ if(fixedIndex.left){ $.each(fixedIndex.left, function (index3, item){ if(index2 == item.index){ leftTr.append($(td).clone(true)); leftCloneBody.push(leftTr); leftCount++; } }); } if(fixedIndex.right){ $.each(fixedIndex.right, function(index3, item) { if(index2 == item.index){ rightTr.append($(td).clone(true)); rightCloneBody.push(rightTr); } }); } }); }); //移动表格数据中的列,以让其与固定列对应 rowDoms.each(function(index, el) { var $this = $(this), curTd = $this.children('td'); curTd.each(function(index2, td) { var $td = $(td); if(fixedIndex.left){ $.each(fixedIndex.left, function (index3, item){ if(index2 == item.index){ if(index3 != 0){ $td.insertAfter($this.children('td').eq(index3 -1)); } } }); } if(fixedIndex.right){ $.each(fixedIndex.right, function(index3, item) { if(index2 == item.index){ if(index3 != curTd.length - 1){ $td.insertAfter($this.children('td').eq(curTd.length - 1)); } } }); } }); }); if(leftFixedTableWrap){ leftFixedTableBody.find("tbody").append(leftCloneBody); if(!this.fixedColCreated){ leftFixedTableWrap.append(leftFixedTableHeader).append(leftFixedTableBody); this.fixedTableBox.append(leftFixedTableWrap); } } if(rightFixedTableWrap){ rightFixedTableBody.find("tbody").append(rightCloneBody); if(!this.fixedColCreated){ rightFixedTableWrap.append(rightFixedTableHeader).append(rightFixedTableBody); this.fixedTableBox.append(rightFixedTableWrap); } } if(!this.fixedColCreated){ this._syncScroll(); } this.fixedColCreated = true; } }); /*获取元素滚动条的宽度*/ FixedTable.getScrollWidth = function (){ var div = document.createElement("div"), w1 = 0, w2 = 0; document.body.appendChild(div); div.style.position = "fixed"; div.style.left = "-2000px"; div.style.width = "200px"; div.style.height = "200px"; w1 = div.clientWidth; div.style.overflow = "scroll"; w2 = div.clientWidth; document.body.removeChild(div); return w1-w2; } /*计算表格的真实宽度*/ FixedTable.calTableWidth = function (fixedTableHeader){ var cloneTable = $(fixedTableHeader).clone(true), width = 0; cloneTable.css({ position: "fixed", left: "-2000px", width: "auto" }); $("body").append(cloneTable); width = cloneTable.width(); cloneTable.remove(); return width; } /*判断浏览器是否为IE浏览器*/ FixedTable.isIE = function (){ var ua = navigator.userAgent.toLowerCase(); if(/msie \d/g.test(ua) || ((/trident\/\d/g.test(ua)) && /like gecko/g.test(ua))){ return true; }else{ return false; } } return FixedTable; });