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

正文

前言:一年前,博主分享过一篇关于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的结果。

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

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

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

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

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

二、效果预览

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

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

多列冻结。

固定任意高度效果

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

代码释疑:

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里面去了,贴出表格冻结的一些效果图。

4、扩展

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

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

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

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

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

(0)

相关推荐

  • JS实现点击Radio动态更新table数据

    tbody定义一个标签 当上面变化的,在js里面做拼接就行了,拼接结束 tbody.html(XXX) <script type="text/javascript"> $(function(){ var quotas = { 1:{name:"工商银行",oneTime:1000}, 2:{name:"农业银行",oneTime:800}, 3:{name:"中国银行",oneTime:2000}, 4:{name

  • jquery.tableSort.js表格排序插件使用方法详解

    本文实例为大家分享了jquery.tableSort.js表格排序的具体代码,供大家参考,具体内容如下 1.一定要引jQuery包,所有jq插件都是基于jQuery包的 2.如果想指定哪一栏不排序这样写 $("#mytable").tablesorter({headers:{5:{sorter:false}}}); 第5列的sorter为false就OK了 参考:http://www.jb51.net/article/105217.htm <!DOCTYPE html> &

  • js操作table元素实现表格行列新增、删除技巧总结

    本文实例讲述了js操作table元素实现表格行列新增.删除的方法.分享给大家供大家参考,具体如下: /************ TableTool.js ****************************************************************************************************************** **********************************************************

  • 详解PHP中的 input属性(隐藏 只读 限制)

    隐藏 <input type="hidden"> 只读 <input type="text" readonly> 失效 <input type="text" disabled> 限制 <input type="text" maxlength="1"> ENTER键让光标移到下一个输入框 <input onkeydown="if(event.ke

  • angularJs中datatable实现代码

    本文介绍了angularJs中datatable实现,有需要的小伙伴可以参考下 html引用derective: 复制代码 代码如下: <table datatable dtOptions="dtOptionsExample2" class="table table-striped m-b-none"></table> controller设置: $scope.dtOptions = { "bProcessing": tr

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

    正文 前言:一年前,博主分享过一篇关于bootstrapTable组件冻结列的解决方案  JS组件系列--Bootstrap Table 冻结列功能IE浏览器兼容性问题解决方案 ,通过该篇,确实可以实现bootstrapTable的冻结列效果,并且可以兼容ie浏览器.这一年的时间,不断有园友以及群里面的朋友问过我关于固定高度之后,冻结列页面效果不能对齐的问题,奈何博主太忙,一直没有抽空将这个问题优化.最近项目里面也不断有人提过这个bug,这下子不能再推了,必须要直面"惨淡的bug",于

  • JS 组件系列之Bootstrap Table 冻结列功能IE浏览器兼容性问题解决方案

    前言:最近项目里面需要用到表格的冻结列功能,所谓"冻结列",就是某些情况下表格的列比较多,需要固定前面的几列,后面的列滚动.遗憾的是,bootstrap table里自带的fixed column功能有一点bug,于是和同事讨论该如何解决,于是就有了这篇文章. 一.起因回顾 最近项目里面有一个表格需求,该表格列是动态产生的,而且列的数量操作一定值以后就会出现横向滚动条,滚动的时候需要前面几列固定.也就是所谓的excel的冻结列功能.该如何实现呢?不用多说,当然是查文档,于是找到了这篇h

  • JS组件系列之Bootstrap table表格组件神器【二、父子表和行列调序】

    Bootstrap Table是轻量级的和功能丰富的以表格的形式显示的数据,支持单选,复选框,排序,分页,显示/隐藏列,固定标题滚动表,响应式设计,Ajax加载JSON数据,点击排序的列,卡片视图等.今天就结合Bootstrap table的父子表和行列调序的用法再来介绍下它稍微高级点的用法. bootstrap table系列: JS表格组件神器bootstrap table详解(基础版) JS组件系列之Bootstrap table表格组件神器[终结篇] JS组件系列之Bootstrap t

  • JS组件系列之Bootstrap table表格组件神器【终结篇】

    bootstrap table系列: JS表格组件神器bootstrap table详解(基础版) JS组件系列之Bootstrap table表格组件神器[终结篇] JS组件系列之Bootstrap table表格组件神器[二.父子表和行列调序] Bootstrap Table是轻量级的和功能丰富的以表格的形式显示的数据,支持单选,复选框,排序,分页,显示/隐藏列,固定标题滚动表,响应式设计,Ajax加载JSON数据,点击排序的列,卡片视图等.那么本文给大家介绍JS组件系列之Bootstrap

  • JS 组件系列之 bootstrap treegrid 组件封装过程

    正文 前言:最近产品需要设计一套相对完整的组织架构的解决方案,由于组织架构涉及到层级关系,在表格里面展示层级关系,自然就要用到所谓的treegrid.可惜的是,一些轻量级的表格组件本身并没有自带树形表格的功能,比如bootstrapTable就没有这个功能,怎么办呢?如果是jqgrid.easyUI的表格,treegrid的效果可以说是轻而易举就能解决,而项目目前用的就是bootstrapTable,不可能这个时候因为这个需求去换组件吧.博主分析了下,无非就两种解决方案:一种就是扩展bootst

  • JS组件系列之Bootstrap Icon图标选择组件

    前言:最近好多朋友在群里面聊到bootstrap icon图标的问题,比如最常见的菜单管理,每个菜单肯定需要一个对应的菜单图标,要是有一个可视化的图标选择组件就好了,最好是直接选择图标,就能得到对应的class样式.于是乎各种百度,皇天不负有心人,最后被博主找到了,感觉效果还不错,并且支持自定义的图标,今天就拿出来分享下,绝对的干货哦! 一.Bootstrap icon picker组件 这个组件是在github上面搜索的时候找到的,初初看上去,确实是很不错的,并且是基于bootstrap风格的

  • JS 组件系列之BootstrapTable的treegrid功能

    上篇给大家介绍了JS 组件系列之 bootstrap treegrid 组件封装过程,下面重点给大家介绍JS 组件系列之BootstrapTable的treegrid功能,需要的的朋友一起学习吧! 一.效果预览 全部折叠 展开一级 全部展开 二.代码示例 怎么样?效果还行吧.给出js的源码供大家参考. (function ($) { 'use strict'; var sprintf = function (str) { var args = arguments, flag = true, i

  • JS组件系列之MVVM组件构建自己的Vue组件

    正文 前言:转眼距离上篇 JS组件系列--又一款MVVM组件:Vue(一:30分钟搞定前端增删改查) 已有好几个月了,今天打算将它捡起来,发现好久不用,Vue相关技术点都生疏不少.经过这几个月的时间,Vue的发展也是异常迅猛,不过这好像和博主都没什么太大的关系,博主还是老老实实研究自己的技术吧.技术之路还很长,且行且研究吧. 一.为什么组件很重要 前两天,看到一篇关于 汇总vue开源项目 的文章,资源非常丰富,不得不感叹开源社区的强大.随便点进去看了几个UI组件,基本都不是原生的html用法,如

  • JS组件系列之使用HTML标签的data属性初始化JS组件

    前言:最近使用bootstrap组件的时候发现一个易用性问题,很多简单的组件初始化都需要在JS里面写很多的初始化代码,比如一个简单的select标签,因为仅仅只是需要从后台获取数据填充到option里面,可是从后台取数据就需要js的初始化,所以导致页面初始化的时候js的初始化代码里面出现很多重复的代码,看着很闹心.于是想起bootstrap table里面的data属性来,如果能够直接在html里面使用data-*这种方式来初始化简单的组件,那该多爽.我们先来看看bootstrap table的

  • Bootstrap Table 在指定列中添加下拉框控件并获取所选值

    背景 最近在使用Bootstrap table ,有一个在某一列添加一个下拉列表,并且通过 "getAllSelections"方法获取所选行的需求,在实现这个功能的时,走了一些弯路,遇到了一些坑.所以今天总结出来,既是自己的学习,也分享给大家,希望能够有些帮助. 如何解决 添加这个下拉列表有以下两种方法: 利用Column options 中的 formatter 将数据转换成下拉列表的形式 使用bootstrap-table拓展中的editable插件 这次主要介绍第一种,基本的思

随机推荐