0

0

Bootstrap Table的冻结列功能之解决高度问题

零下一度

零下一度

发布时间:2017-07-02 10:21:14

|

2854人浏览过

|

来源于php中文网

原创

这篇文章主要介绍了js 组件系列之bootstrap table的冻结列功能彻底解决高度问题,需要的朋友可以参考下

正文

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

一、问题追踪

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


aaabbbccc
dddeeefff
ggghhhiii

代码本身很简单,只是为了测试用。看到这里你可以试着猜一下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 = $([
   '

', '

', '', '
', '

'].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 = $([ '

', '

', '', '
', '

'].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 = $(''); $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测试页,还是贴出来供大家参考。

通义千问
通义千问

阿里巴巴推出的全能AI助手

下载





 
 
 
 
 



 

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 = $('');
  $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

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

相关专题

更多
C++ 高级模板编程与元编程
C++ 高级模板编程与元编程

本专题深入讲解 C++ 中的高级模板编程与元编程技术,涵盖模板特化、SFINAE、模板递归、类型萃取、编译时常量与计算、C++17 的折叠表达式与变长模板参数等。通过多个实际示例,帮助开发者掌握 如何利用 C++ 模板机制编写高效、可扩展的通用代码,并提升代码的灵活性与性能。

10

2026.01.23

php远程文件教程合集
php远程文件教程合集

本专题整合了php远程文件相关教程,阅读专题下面的文章了解更多详细内容。

27

2026.01.22

PHP后端开发相关内容汇总
PHP后端开发相关内容汇总

本专题整合了PHP后端开发相关内容,阅读专题下面的文章了解更多详细内容。

19

2026.01.22

php会话教程合集
php会话教程合集

本专题整合了php会话教程相关合集,阅读专题下面的文章了解更多详细内容。

19

2026.01.22

宝塔PHP8.4相关教程汇总
宝塔PHP8.4相关教程汇总

本专题整合了宝塔PHP8.4相关教程,阅读专题下面的文章了解更多详细内容。

10

2026.01.22

PHP特殊符号教程合集
PHP特殊符号教程合集

本专题整合了PHP特殊符号相关处理方法,阅读专题下面的文章了解更多详细内容。

11

2026.01.22

PHP探针相关教程合集
PHP探针相关教程合集

本专题整合了PHP探针相关教程,阅读专题下面的文章了解更多详细内容。

7

2026.01.22

菜鸟裹裹入口以及教程汇总
菜鸟裹裹入口以及教程汇总

本专题整合了菜鸟裹裹入口地址及教程分享,阅读专题下面的文章了解更多详细内容。

52

2026.01.22

Golang 性能分析与pprof调优实战
Golang 性能分析与pprof调优实战

本专题系统讲解 Golang 应用的性能分析与调优方法,重点覆盖 pprof 的使用方式,包括 CPU、内存、阻塞与 goroutine 分析,火焰图解读,常见性能瓶颈定位思路,以及在真实项目中进行针对性优化的实践技巧。通过案例讲解,帮助开发者掌握 用数据驱动的方式持续提升 Go 程序性能与稳定性。

9

2026.01.22

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
Bootstrap 5教程
Bootstrap 5教程

共46课时 | 3万人学习

HTML+CSS基础与实战
HTML+CSS基础与实战

共132课时 | 9.7万人学习

JS进阶与BootStrap学习
JS进阶与BootStrap学习

共39课时 | 3.2万人学习

关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号 技术交流群
PHP中文网订阅号
每天精选资源文章推送

Copyright 2014-2026 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号