JS 组件系列之Bootstrap Table的冻结列功能彻底解决高度问题


Posted in Javascript onJune 30, 2017

正文

前言:一年前,博主分享过一篇关于bootstrapTable组件冻结列的解决方案  JS组件系列——Bootstrap Table 冻结列功能IE浏览器兼容性问题解决方案 ,通过该篇,确实可以实现bootstrapTable的冻结列效果,并且可以兼容ie浏览器。这一年的时间,不断有园友以及群里面的朋友问过我关于固定高度之后,冻结列页面效果不能对齐的问题,奈何博主太忙,一直没有抽空将这个问题优化。最近项目里面也不断有人提过这个bug,这下子不能再推了,必须要直面“惨淡的bug”,于是昨天利用一天的时间将原来的扩展做了一下修改,能够完美解决固定高度之后冻结列的问题,并且,博主还加了一些特性,比如右侧列的冻结、冻结列的选中等等,有需要的朋友可以捧个场。相信通过此篇,老板再也不用担心我的冻结列不能固定高度了~~

一、问题追踪

记得在之前的那篇里面介绍过,bootstrapTable组件自带的冻结列扩展,不能兼容ie浏览器,即使最新版本的ie也会无法使用,这是一般的系统不能忍受的,所以在那篇里面给出过解决方案,但并未分析ie浏览器不能兼容的原因,昨天博主花了点时间特意调试了下源码,原来在ie里面,使用jquery的clone()方法和谷歌等浏览器有所区别。为了展示这个区别,这里先抛个砖。比如有如下代码:

<table id="tbtest">
 <tr><td>aaa</td><td>bbb</td><td>ccc</td></tr>
 <tr><td>ddd</td><td>eee</td><td>fff</td></tr>
 <tr><td>ggg</td><td>hhh</td><td>iii</td></tr>
</table>
<script type="text/javascript">
 var $tr = $('#tbtest tr:eq(0)').clone();
 var $tds = $tr.find('td');
 $tr.html('');
 alert($tds.eq(0).html());
</script>

代码本身很简单,只是为了测试用。看到这里你可以试着猜一下alert的结果。

算了,不考大家了,直接贴出来吧,有图有真相!

JS 组件系列之Bootstrap Table的冻结列功能彻底解决高度问题

JS 组件系列之Bootstrap Table的冻结列功能彻底解决高度问题

相信不用我过多的解释哪个是ie,哪个是谷歌了吧。

两者的区别很明显,谷歌里面得到“aaa”,而ie里面得到空字符串。这是为什么呢?

其实如果你用值类型和引用类型的区别来解释这个差别你就不难理解了,在谷歌浏览器里面,$tr变量是一个引用类型,当你清空了它里面的内容,只是清除了$tr这个变量的“指针”,或者叫指向,$tds变量仍然指向了$tr的原始内容,所以调用$tds.eq(0).html()的时候仍然能得到结果aaa;同样的代码在ie浏览器里面,$tr变量就是一个值类型,你清空了它里面的内容之后,$tds的内容也被清空了。如果你有更好的解释,欢迎赐教哈。

之所以组件原生的js不能兼容ie浏览器,就是因为它使用了clone()这个方法,导致在不同的浏览器看到不同的结果。相信bootstrapTable组件的作者应该是知道这个区别的,只不过没有太在意这些,从作者做的很多功能的兼容性能够看出,他做的功能很多没有太多的考虑ie浏览器的效果。

二、效果预览

还是老规矩,说了这个多,没图怎么行,小二,上图!

没有固定高度的情况:单列冻结。

JS 组件系列之Bootstrap Table的冻结列功能彻底解决高度问题

多列冻结。

JS 组件系列之Bootstrap Table的冻结列功能彻底解决高度问题

 固定任意高度效果

JS 组件系列之Bootstrap Table的冻结列功能彻底解决高度问题

JS 组件系列之Bootstrap Table的冻结列功能彻底解决高度问题

ie浏览器也没有问题,这里就不再重复上图了。

三、源码解析

源码没啥说的,有兴趣可以自己看看,主要的原理还是重写bootstrapTable构造器的事件,来达到想要的效果。

(function ($) {
 'use strict';
 $.extend($.fn.bootstrapTable.defaults, {
  fixedColumns: false,
  fixedNumber: 1
 });
 var BootstrapTable = $.fn.bootstrapTable.Constructor,
  _initHeader = BootstrapTable.prototype.initHeader,
  _initBody = BootstrapTable.prototype.initBody,
  _resetView = BootstrapTable.prototype.resetView;
 BootstrapTable.prototype.initFixedColumns = function () {
  this.$fixedHeader = $([
   '<div class="fixed-table-header-columns">',
   '<table>',
   '<thead></thead>',
   '</table>',
   '</div>'].join(''));
  this.timeoutHeaderColumns_ = 0;
  this.$fixedHeader.find('table').attr('class', this.$el.attr('class'));
  this.$fixedHeaderColumns = this.$fixedHeader.find('thead');
  this.$tableHeader.before(this.$fixedHeader);
  this.$fixedBody = $([
   '<div class="fixed-table-body-columns">',
   '<table>',
   '<tbody></tbody>',
   '</table>',
   '</div>'].join(''));
  this.timeoutBodyColumns_ = 0;
  this.$fixedBody.find('table').attr('class', this.$el.attr('class'));
  this.$fixedBodyColumns = this.$fixedBody.find('tbody');
  this.$tableBody.before(this.$fixedBody);
 };
 BootstrapTable.prototype.initHeader = function () {
  _initHeader.apply(this, Array.prototype.slice.apply(arguments));
  if (!this.options.fixedColumns) {
   return;
  }
  this.initFixedColumns();
  var that = this, $trs = this.$header.find('tr').clone();
  $trs.each(function () {
   $(this).find('th:gt(' + (that.options.fixedNumber - 1) + ')').remove();
  });
  this.$fixedHeaderColumns.html('').append($trs);
 };
 BootstrapTable.prototype.initBody = function () {
  _initBody.apply(this, Array.prototype.slice.apply(arguments));
  if (!this.options.fixedColumns) {
   return;
  }
  var that = this,
   rowspan = 0;
  this.$fixedBodyColumns.html('');
  this.$body.find('> tr[data-index]').each(function () {
   var $tr = $(this).clone(),
    $tds = $tr.find('td');
   //$tr.html('');这样存在一个兼容性问题,在IE浏览器里面,清空tr,$tds的值也会被清空。
   //$tr.html('');
   var $newtr = $('<tr></tr>');
   $newtr.attr('data-index', $tr.attr('data-index'));
   $newtr.attr('data-uniqueid', $tr.attr('data-uniqueid'));
   var end = that.options.fixedNumber;
   if (rowspan > 0) {
    --end;
    --rowspan;
   }
   for (var i = 0; i < end; i++) {
    $newtr.append($tds.eq(i).clone());
   }
   that.$fixedBodyColumns.append($newtr);
   if ($tds.eq(0).attr('rowspan')) {
    rowspan = $tds.eq(0).attr('rowspan') - 1;
   }
  });
 };
 BootstrapTable.prototype.resetView = function () {
  _resetView.apply(this, Array.prototype.slice.apply(arguments));
  if (!this.options.fixedColumns) {
   return;
  }
  clearTimeout(this.timeoutHeaderColumns_);
  this.timeoutHeaderColumns_ = setTimeout($.proxy(this.fitHeaderColumns, this), this.$el.is(':hidden') ? 100 : 0);
  clearTimeout(this.timeoutBodyColumns_);
  this.timeoutBodyColumns_ = setTimeout($.proxy(this.fitBodyColumns, this), this.$el.is(':hidden') ? 100 : 0);
 };
 BootstrapTable.prototype.fitHeaderColumns = function () {
  var that = this,
   visibleFields = this.getVisibleFields(),
   headerWidth = 0;
  this.$body.find('tr:first-child:not(.no-records-found) > *').each(function (i) {
   var $this = $(this),
    index = i;
   if (i >= that.options.fixedNumber) {
    return false;
   }
   if (that.options.detailView && !that.options.cardView) {
    index = i - 1;
   }
   that.$fixedHeader.find('th[data-field="' + visibleFields[index] + '"]')
    .find('.fht-cell').width($this.innerWidth());
   headerWidth += $this.outerWidth();
  });
  this.$fixedHeader.width(headerWidth).show();
 };
 BootstrapTable.prototype.fitBodyColumns = function () {
  var that = this,
   top = -(parseInt(this.$el.css('margin-top'))),
   // the fixed height should reduce the scorll-x height
   height = this.$tableBody.height() - 18;
  debugger;
  if (!this.$body.find('> tr[data-index]').length) {
   this.$fixedBody.hide();
   return;
  }
  if (!this.options.height) {
   top = this.$fixedHeader.height()- 1;
   height = height - top;
  }
  this.$fixedBody.css({
   width: this.$fixedHeader.width(),
   height: height,
   top: top + 1
  }).show();
  this.$body.find('> tr').each(function (i) {
   that.$fixedBody.find('tr:eq(' + i + ')').height($(this).height() - 0.5);
   var thattds = this;
   debugger;
   that.$fixedBody.find('tr:eq(' + i + ')').find('td').each(function (j) {
    $(this).width($($(thattds).find('td')[j]).width() + 1);
   });
  });
  // events
  this.$tableBody.on('scroll', function () {
   that.$fixedBody.find('table').css('top', -$(this).scrollTop());
  });
  this.$body.find('> tr[data-index]').off('hover').hover(function () {
   var index = $(this).data('index');
   that.$fixedBody.find('tr[data-index="' + index + '"]').addClass('hover');
  }, function () {
   var index = $(this).data('index');
   that.$fixedBody.find('tr[data-index="' + index + '"]').removeClass('hover');
  });
  this.$fixedBody.find('tr[data-index]').off('hover').hover(function () {
   var index = $(this).data('index');
   that.$body.find('tr[data-index="' + index + '"]').addClass('hover');
  }, function () {
   var index = $(this).data('index');
   that.$body.find('> tr[data-index="' + index + '"]').removeClass('hover');
  });
 };
})(jQuery);
.fixed-table-header-columns,
.fixed-table-body-columns {
 position: absolute;
 background-color: #fff;
 display: none;
 box-sizing: border-box;
 overflow: hidden;
}
 .fixed-table-header-columns .table,
 .fixed-table-body-columns .table {
  border-right: 1px solid #ddd;
 }
  .fixed-table-header-columns .table.table-no-bordered,
  .fixed-table-body-columns .table.table-no-bordered {
   border-right: 1px solid transparent;
  }
 .fixed-table-body-columns table {
  position: absolute;
  animation: none;
 }
.bootstrap-table .table-hover > tbody > tr.hover > td {
 background-color: #f5f5f5;
}

如何使用呢?这里博主单独搞了一个静态的html测试页,还是贴出来供大家参考。

<!DOCTYPE html>
<html lang="en" xmlns="http://www.w3.org/1999/xhtml">
<head>
 <meta charset="utf-8" />
 <title></title>
 <!--必须的css引用-->
 <link href="Content/bootstrap/css/bootstrap.min.css" rel="stylesheet" />
 <link href="Content/bootstrap-table/bootstrap-table.min.css" rel="stylesheet" />
<link href="Content/bootstrap-table/extensions/fixed-column/bootstrap-table-fixed-columns.css" rel="stylesheet" />
</head>
<body>
 <div class="panel-body" style="padding-bottom:0px;">
  <!--<div class="panel panel-default">
   <div class="panel-heading">查询条件</div>
   <div class="panel-body">
    <form id="formSearch" class="form-horizontal">
     <div class="form-group" style="margin-top:15px">
      <label class="control-label col-sm-1" for="name">员工姓名</label>
      <div class="col-sm-3">
       <input type="text" class="form-control" id="name">
      </div>
      <label class="control-label col-sm-1" for="address">家庭住址</label>
      <div class="col-sm-3">
       <input type="text" class="form-control" id="address">
      </div>
      <div class="col-sm-4" style="text-align:left;">
       <button type="button" style="margin-left:50px" id="btn_query" class="btn btn-primary">查询</button>
      </div>
     </div>
    </form>
   </div>
  </div>-->
  <div id="toolbar" class="btn-group">
   <button id="btn_add" type="button" class="btn btn-success">
    <span class="glyphicon glyphicon-plus" aria-hidden="true"></span>新增
   </button>
  </div>
  <table id="tb_user"></table>
 </div>
 <!--新增或者编辑的弹出框-->
 <div class="modal fade" id="myModal" tabindex="-1" role="dialog" aria-labelledby="myModalLabel">
  <div class="modal-dialog" role="document">
   <div class="modal-content">
    <div class="modal-header">
     <button type="button" class="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">×</span></button>
     <h4 class="modal-title" id="myModalLabel">操作</h4>
    </div>
    <div class="modal-body">
     <div class="row" style="padding:10px;">
      <label class="control-label col-xs-2">姓名</label>
      <div class="col-xs-10">
       <input type="text" name="Name" class="form-control" placeholder="姓名">
      </div>
     </div>
     <div class="row" style="padding:10px;">
      <label class="control-label col-xs-2">年龄</label>
      <div class="col-xs-10">
       <input type="text" name="Age" class="form-control" placeholder="年龄">
      </div>
     </div>
     <div class="row" style="padding:10px;">
      <label class="control-label col-xs-2">学校</label>
      <div class="col-xs-10">
       <input type="text" name="School" class="form-control" placeholder="学校">
      </div>
     </div>
     <div class="row" style="padding:10px;">
      <label class="control-label col-xs-2">家庭住址</label>
      <div class="col-xs-10">
       <input type="text" name="Address" class="form-control" placeholder="学校">
      </div>
     </div>
     <div class="row" style="padding:10px;">
      <label class="control-label col-xs-2">备注</label>
      <div class="col-xs-10">
       <textarea class="form-control" placeholder="备注" name="Remark"></textarea>
      </div>
     </div>
    </div>
    <div class="modal-footer">
     <button type="button" class="btn btn-default" data-dismiss="modal"><span class="glyphicon glyphicon-remove" aria-hidden="true"></span>关闭</button>
     <button type="submit" class="btn btn-primary"><span class="glyphicon glyphicon-floppy-disk" aria-hidden="true"></span>保存</button>
    </div>
   </div>
  </div>
 </div>
  <!--必须的js文件-->
  <script src="Content/jquery-1.9.1.min.js"></script>
  <script src="Content/bootstrap/js/bootstrap.min.js"></script>
  <script src="Content/bootstrap-table/bootstrap-table.min.js"></script>
  <script src="Content/bootstrap-table/locale/bootstrap-table-zh-CN.min.js"></script>
<script src="Content/bootstrap-table/extensions/fixed-column/bootstrap-table-fixed-columns.js"></script>
  <script type="text/javascript">
   //页面加载完成之后
   var data = [
    { Id: 1, Name: 'Jim', Age: 30, School: '光明小学', Address: '北京市光明小学旁', Remark: 'My Name is Jim Green' },
    { Id: 2, Name: 'Kate', Age: 30, School: '光明小学', Address: '深圳市', Remark: 'My Name is Jim Green' },
    { Id: 3, Name: 'Lucy', Age: 30, School: '光明小学', Address: '广州天河机场', Remark: 'My Name is Jim Green' },
    { Id: 4, Name: 'Lilei', Age: 30, School: '光明小学', Address: '北京市光明小学旁', Remark: 'My Name is Jim Green' },
    { Id: 5, Name: 'Lintao', Age: 30, School: '光明小学', Address: '北京市光明小学旁', Remark: 'My Name is Jim Green' },
    { Id: 6, Name: 'Lily', Age: 30, School: '光明小学', Address: '北京市光明小学旁', Remark: 'My Name is Jim Green' },
    { Id: 7, Name: 'Hanmeimei', Age: 30, School: '光明小学', Address: '北京市光明小学旁', Remark: 'My Name is Jim Green' },
    { Id: 8, Name: '张三', Age: 46, School: '光明小学', Address: '北京市光明小学旁', Remark: 'My Name is Jim Green' },
    { Id: 9, Name: '李四', Age: 23, School: '光明小学', Address: '北京市光明小学旁', Remark: 'My Name is Jim Green' },
    { Id: 10, Name: '王五', Age: 33, School: '光明小学', Address: '北京市光明小学旁', Remark: 'My Name is Jim Green' },
    { Id: 11, Name: '赵六', Age: 22, School: '光明小学', Address: '北京市光明小学旁', Remark: 'My Name is Jim Green' },
    { Id: 12, Name: 'Polly', Age: 300, School: '光明小学', Address: '北京市光明小学旁', Remark: 'My Name is Jim Green' },
    { Id: 13, Name: 'Uncle', Age: 50, School: '光明小学', Address: '北京市光明小学旁', Remark: 'My Name is Jim Green' },
   ];
   var childData = [
    { SourceField: 'A', BackField: 'BB' },
    { SourceField: 'CC', BackField: 'UU' },
    { SourceField: 'DD', BackField: 'J' },
   ];
   $(function () {
    //表格的初始化
    $('#tb_user').bootstrapTable({
     data: data,       //直接从本地数据初始化表格
     method: 'get',      //请求方式(*)
     toolbar: '#toolbar',    //工具按钮用哪个容器
     striped: true,      //是否显示行间隔色
     cache: false,      //是否使用缓存,默认为true,所以一般情况下需要设置一下这个属性(*)
     pagination: true,     //是否显示分页(*)
     sortable: false,      //是否启用排序
     sortOrder: "asc",     //排序方式
     queryParams: function (params) {
      return params;
     },         //传递参数(*)
     sidePagination: "client",   //分页方式:client客户端分页,server服务端分页(*)
     pageNumber: 1,      //初始化加载第一页,默认第一页
     pageSize: 5,      //每页的记录行数(*)
     pageList: [10, 25, 50, 100],  //可供选择的每页的行数(*)
     search: true,      //是否显示表格搜索,此搜索是客户端搜索,不会进服务端,所以,个人感觉意义不大
     strictSearch: true,
     showColumns: true,     //是否显示所有的列
     showRefresh: true,     //是否显示刷新按钮
     minimumCountColumns: 2,    //最少允许的列数
     height:400,
   selectItemName: 'parentItem',
     fixedColumns: true,
     fixedNumber: 6,
     //注册加载子表的事件。注意下这里的三个参数!
     onExpandRow: function (index, row, $detail) {
      InitSubTable(index, row, $detail);
     },
     columns: [{
      checkbox: true
     }, {
      field: 'Name',
      title: '姓名',
width:200
     }, {
      field: 'Age',
      title: '年龄',
width:200
     }, {
      field: 'School',
      title: '毕业院校',
width:200
     }, {
      field: 'Address',
      title: '家庭住址',
width:100
     }, {
      field: 'Remark',
      title: '备注',
width:100
     }, 
 {
      field: 'Remark',
      title: '备注',
width:100
     }, {
      field: 'Remark',
      title: '备注',
width:100
     }, {
      field: 'Remark',
      title: '备注',
width:100
     }, {
      field: 'Remark',
      title: '备注',
width:100
     }, {
      field: 'Remark',
      title: '备注',
width:100
     },{
      field: 'Remark',
      title: '备注',
width:100
     },{
      field: 'Remark',
      title: '备注',
width:100
     },{
      field: 'Remark',
      title: '备注',
width:100
     },{
      field: 'Remark',
      title: '备注',
width:100
     },{
      field: 'Remark',
      title: '备注',
width:100
     },{
      field: 'Remark',
      title: '备注',
width:100
     },{
      field: 'Remark',
      title: '备注',
width:100
     },{
      field: 'Remark',
      title: '备注',
width:100
     },{
      field: 'Remark',
      title: '备注',
width:100
     },{
      field: 'Remark',
      title: '备注',
width:100
     },{
      field: 'Remark',
      title: '备注',
width:100
     },{
      field: 'Remark',
      title: '备注',
width:100
     },{
      field: 'Remark',
      title: '备注',
width:100
     },{
      field: 'Remark',
      title: '备注',
width:100
     },{
      field: 'Remark',
      title: '备注',
width:100
     },{
      field: 'Remark',
      title: '备注',
width:100
     },{
      field: 'Remark',
      title: '备注',
width:100
     },{
      field: 'Remark',
      title: '备注',
width:100
     },{
      field: 'Remark',
      title: '备注',
width:100
     },{
      field: 'Remark',
      title: '备注',
width:100
     },{
      title: '操作',
width:200,
      formatter: function (value, row, index) {//这里的三个参数:value表示当前行当前列的值;row表示当前行的数据;index表示当前行的索引(从0开始)。
       var html = '<button type="button" onclick="editModel('+row.Id+')" class="btn btn-primary"><span class="glyphicon glyphicon-pencil" aria- hidden="true" ></span >编辑</button >  ' +
          '<button type="button" onclick="deleteModel(' + row.Id + ')" class="btn btn-danger"><span class="glyphicon glyphicon-remove" aria- hidden="true" ></span >删除</button >';
       return html;
      }
     }],
     onEditableSave: function (field, row, oldValue, $el) {
      alert("更新保存事件,原始值为" + oldValue);
      //$.ajax({
      // type: "post",
      // url: "/Editable/Edit",
      // data: row,
      // dataType: 'JSON',
      // success: function (data, status) {
      //  if (status == "success") {
      //   alert('提交数据成功');
      //  }
      // },
      // error: function () {
      //  alert('编辑失败');
      // },
      // complete: function () {
      // }
      //});
     }
    });
    //新增事件
    $("#btn_add").on('click', function () {
$('#tb_user').bootstrapTable("resetView");
     //弹出模态框
     $("#myModal").modal();
     //给弹出框里面的各个文本框赋值
     $("#myModal input").val("");
     $("#myModal textarea").val("");
    });
   });
   //加载子表
   var InitSubTable = function (index, row, $detail) {
    var parentid = row.MENU_ID;
    var cur_table = $detail.html('<table></table>').find('table');
    //子表的初始化和父表完全相同
    $(cur_table).bootstrapTable({
     //url: '/api/MenuApi/GetChildrenMenu',
     data: childData,
     method: 'get',
     queryParams: { strParentID: parentid },
     ajaxOptions: { strParentID: parentid },
     clickToSelect: true,
     uniqueId: "MENU_ID",
     pageSize: 10,
     pageList: [10, 25],
   selectItemName: 'childItem'+index,
   checkboxHeader:false,
     columns: [{
      checkbox: true
     }, {
       field: 'SourceField',
      title: '源端字段'
     }, {
      field: 'BackField',
      title: '备端字段'
     }, {
      field: 'BackField',
      title: '备端字段'
     }, {
      field: 'BackField',
      title: '备端字段'
     }, {
      field: 'BackField',
      title: '备端字段'
     }, {
      field: 'BackField',
      title: '备端字段'
     }, {
      field: 'BackField',
      title: '备端字段'
     }, {
      field: 'BackField',
      title: '备端字段'
     }, {
      field: 'BackField',
      title: '备端字段'
     }, {
      field: 'BackField',
      title: '备端字段'
     }, {
      field: 'BackField',
      title: '备端字段'
     }, {
      field: 'BackField',
      title: '备端字段'
     }, {
      field: 'BackField',
      title: '备端字段'
     }, {
      field: 'BackField',
      title: '备端字段'
     }, {
      field: 'BackField',
      title: '备端字段'
     }, {
      field: 'BackField',
      title: '备端字段'
     }, {
      field: 'BackField',
      title: '备端字段'
     }, {
      field: 'BackField',
      title: '备端字段'
     }, {
      field: 'BackField',
      title: '备端字段'
     }, {
      field: 'BackField',
      title: '备端字段'
     }, {
      field: 'BackField',
      title: '备端字段'
     }, {
      field: 'BackField',
      title: '备端字段'
     }, {
      field: 'BackField',
      title: '备端字段'
     }, {
      field: 'BackField',
      title: '备端字段'
     }, {
      field: 'BackField',
      title: '备端字段'
     }, {
      field: 'BackField',
      title: '备端字段'
     }],
     //无线循环取子表,直到子表里面没有记录
     onExpandRow: function (index, row, $Subdetail) {
      //oInit.InitSubTable(index, row, $Subdetail);
     }
    });
   };
   //编辑事件
   var editModel = function (id) {
    //根据当前行的id获取当前的行数据
    var row = $("#tb_user").bootstrapTable('getRowByUniqueId', id);
    //弹出模态框
    $("#myModal").modal();
    //给弹出框里面的各个文本框赋值
    $("#myModal input[name='Name']").val(row.Name);
    $("#myModal input[name='Age']").val(row.Age);
    $("#myModal input[name='School']").val(row.School);
    $("#myModal input[name='Address']").val(row.Address);
    $("#myModal textarea[name='Remark']").val(row.Remark);
   }
   //删除事件
   var deleteModel = function (id) {
    alert("删除id为" + id + "的用户");
   }
  </script>
</body>
</html>
bootstrapTableFixColumns.html

代码释疑:

JS 组件系列之Bootstrap Table的冻结列功能彻底解决高度问题

1、源码各个方法解释

  • BootstrapTable.prototype.initFixedColumns :当初始化的时候配置了fixedColumns: true时需要执行的冻结列的方法。
  • BootstrapTable.prototype.initHeader:重写组件的的初始化表头的方法,加入冻结的表头。
  • BootstrapTable.prototype.initBody:重写组件的初始化表内容的方法,加入冻结的表内容。 
  • BootstrapTable.prototype.resetView:重写“父类”的resetView方法,通过setTimeout去设置冻结的表头和表体的宽度和高度。
  • BootstrapTable.prototype.fitHeaderColumns:设置冻结列的表头的宽高。
  • BootstrapTable.prototype.fitBodyColumns :设置冻结列的表体的宽高,以及滚动条和主体表格的滚动条同步。

 2、对于上述抛出的ie和谷歌的兼容性问题的解析

查看BootstrapTable.prototype.initBody方法,你会发现里面写有部分注释。

this.$body.find('> tr[data-index]').each(function () {
  var $tr = $(this).clone(),
  $tds = $tr.find('td');
  //$tr.html('');这样存在一个兼容性问题,在IE浏览器里面,清空tr,$tds的值也会被清空。
  //$tr.html('');
  var $newtr = $('<tr></tr>');
  $newtr.attr('data-index', $tr.attr('data-index'));
  $newtr.attr('data-uniqueid', $tr.attr('data-uniqueid'));
  var end = that.options.fixedNumber;
  if (rowspan > 0) {
  --end;
  --rowspan;
  }
  for (var i = 0; i < end; i++) {
  $newtr.append($tds.eq(i).clone());
  }
  that.$fixedBodyColumns.append($newtr);
  if ($tds.eq(0).attr('rowspan')) {
  rowspan = $tds.eq(0).attr('rowspan') - 1;
  }
 });

这一段做了部分修改,有兴趣可以调适细看。

3、项目中的使用

 最近在研究学习abp的相关源码,将bootstrapTable融入abp里面去了,贴出表格冻结的一些效果图。

JS 组件系列之Bootstrap Table的冻结列功能彻底解决高度问题

JS 组件系列之Bootstrap Table的冻结列功能彻底解决高度问题

4、扩展

除此之外,还特意做了右边操作列的冻结。

JS 组件系列之Bootstrap Table的冻结列功能彻底解决高度问题

和左边列的冻结一样,最右边列的冻结也是可以做的,最不同的地方莫过于右边列有一些操作按钮,如果在点击冻结列上面的按钮时触发实际表格的按钮事件是难点。如果有这个需求,可以看看。

bootstrap-table-fixed-columns.js
 bootstrap-table-fixed-columns.css

需要说明的是,由于时间问题,右侧固定列的代码和上述解决高度的代码并未合并,所以如果你既想要解决冻结列的高度,又想要右侧列的冻结,需要自己花点时间合并下代码。

以上所述是小编给大家介绍的JS 组件系列之Bootstrap Table的冻结列功能彻底解决高度问题,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对三水点靠木网站的支持!

Javascript 相关文章推荐
Moment.js 不容错过的超棒Javascript日期处理类库
Apr 15 Javascript
javascript 日期时间 转换的方法
Feb 21 Javascript
input输入框的自动匹配(原生代码)
Mar 19 Javascript
JavaScript 实现打印,打印预览,打印设置
Dec 30 Javascript
JavaScript实现LI列表数据绑定的方法
Aug 04 Javascript
学习JavaScript设计模式(策略模式)
Nov 26 Javascript
node.js require() 源码解读
Dec 13 Javascript
BootStrap智能表单实战系列(七)验证的支持
Jun 13 Javascript
jQuery Easyui Tabs扩展根据自定义属性打开页签
Aug 15 Javascript
原生JS实现的放大镜效果实例代码
Oct 15 Javascript
JavaScript中${pageContext.request.contextPath}取值问题及解决方案
Dec 08 Javascript
让微信小程序支持ES6中Promise特性的方法详解
Jun 13 Javascript
MUI实现上拉加载和下拉刷新效果
Jun 30 #Javascript
js实现京东轮播图效果
Jun 30 #Javascript
jquery实现一个全局计时器(商城可用)
Jun 30 #jQuery
Vue和Bootstrap的整合思路详解
Jun 30 #Javascript
JavaScript原型继承_动力节点Java学院整理
Jun 30 #Javascript
JavaScript之排序函数_动力节点Java学院整理
Jun 30 #Javascript
JavaScript操作文件_动力节点Java学院整理
Jun 30 #Javascript
You might like
一个php作的文本留言本的例子(五)
2006/10/09 PHP
用ODBC的分页显示
2006/10/09 PHP
PHP操作XML作为数据库的类
2010/12/19 PHP
ThinkPHP公共配置文件与各自项目中配置文件组合的方法
2014/11/24 PHP
PHP抓取网页、解析HTML常用的方法总结
2015/07/01 PHP
CI(Codeigniter)的Setting增强配置类实例
2016/01/06 PHP
PHP实现动态删除XML数据的方法示例
2018/03/30 PHP
Javascript中Eval函数的使用
2010/03/23 Javascript
原生js 秒表实现代码
2012/07/24 Javascript
jquery使用ColorBox弹出图片组浏览层实例演示
2013/03/14 Javascript
探讨JavaScript中声明全局变量三种方式的异同
2013/12/03 Javascript
Javascript学习笔记之 函数篇(一) : 函数声明和函数表达式
2014/06/24 Javascript
浅析webapp框架AngularUI的demo
2014/12/21 Javascript
用Move.js配合创建CSS3动画的入门指引
2015/07/22 Javascript
jquery实现带渐变淡入淡出并向右依次展开的多级菜单效果实例
2015/08/22 Javascript
js中获取键盘事件的简单实现方法
2016/10/10 Javascript
使用yeoman构建angular应用的方法
2017/08/14 Javascript
JavaScript比较同一天的时间大小实例代码
2018/02/09 Javascript
vue路由对不同界面进行传参及跳转的总结
2019/04/20 Javascript
vue-calendar-component 封装多日期选择组件的实例代码
2020/12/04 Vue.js
[01:00:52]2018DOTA2亚洲邀请赛 4.4 淘汰赛 EG vs LGD 第一场
2018/04/05 DOTA
Python获取apk文件URL地址实例
2013/11/01 Python
Python数据类型详解(三)元祖:tuple
2016/05/08 Python
python实现log日志的示例代码
2018/04/28 Python
python用win32gui遍历窗口并设置窗口位置的方法
2019/07/26 Python
keras实现图像预处理并生成一个generator的案例
2020/06/17 Python
详解Html5页面实现下载文件(apk、txt等)的三种方式
2018/10/22 HTML / CSS
Lacoste(法国鳄鱼)加拿大官网:以标志性的POLO衫而闻名
2019/05/15 全球购物
Joseph官网:英国小众奢侈品牌
2019/05/17 全球购物
娇韵诗Clarins意大利官方网站:法国天然护肤品牌
2020/03/11 全球购物
预备党员党校学习自我评价分享
2013/11/12 职场文书
中层干部竞聘演讲稿
2014/05/15 职场文书
党员年度个人总结
2015/02/14 职场文书
党支部培养考察意见
2015/06/02 职场文书
2015年工会工作总结范文
2015/07/23 职场文书
68句权威创业名言
2019/08/26 职场文书