JS元件系列——自己動手擴充套件BootstrapTable的 凍結列 功能:徹底解決高度問題
前言:一年前,博主分享過一篇關於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);bootstrap-table-fixed-columns.js
.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; }bootstrap-table-fixed-columns.css
如何使用呢?這裡博主單獨搞了一個靜態的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:相關推薦
JS元件系列——自己動手擴充套件BootstrapTable的treegrid功能
前言:上篇 JS元件系列——自己動手封裝bootstrap-treegrid元件 博主自己動手封裝了下treegrid的功能,但畢竟那個元件只是一個單獨針對樹形表格做的,適用性還比較有限。關注博主的園友應該知道,博主的部落格裡面寫了很多bootstrapTable的擴充套件,今天打算在直接在bootstra
JS元件系列——自己動手擴充套件BootstrapTable的 凍結列 功能:徹底解決高度問題
前言:一年前,博主分享過一篇關於bootstrapTable元件凍結列的解決方案 JS元件系列——Bootstrap Table 凍結列功能IE瀏覽器相容性問題解決方案 ,通過該篇,確實可以實現bootstrapTable的凍結列效果,並且可以相容ie瀏覽器。這一年的時間,不斷有園友以及群裡面的朋友問過我關
JS元件系列——自己動手封裝bootstrap-treegrid元件
前言:最近產品需要設計一套相對完整的組織架構的解決方案,由於組織架構涉及到層級關係,在表格裡面展示層級關係,自然就要用到所謂的treegrid。可惜的是,一些輕量級的表格元件本身並沒有自帶樹形表格的功能,比如bootstrapTable就沒有這個功能,怎麼辦呢?如果是jqgrid、easyUI的表格,tree
JS元件系列——又一款MVVM元件:Vue(二:構建自己的Vue元件)
前言:轉眼距離上篇 JS元件系列——又一款MVVM元件:Vue(一:30分鐘搞定前端增刪改查) 已有好幾個月了,今天打算將它撿起來,發現好久不用,Vue相關技術點都生疏不少。經過這幾個月的時間,Vue的發展也是異常迅猛,不過這好像和博主都沒什麼太大的關係,博主還是老老實實研究自己的技術吧。技術之路還很長,且行
JS元件系列——BootstrapTable 行內編輯解決方案:x-editable
前言:之前介紹bootstrapTable元件的時候有提到它的行內編輯功能,只不過為了展示功能,將此一筆帶過了,罪過罪過!最近專案裡面還是打算將行內編輯用起來,於是再次研究了下x-editable元件,遇到過一些坑,再此做個採坑記錄吧!想要了解bootstrapTable的園友可以移步 JS元件系列——表格元
JS元件系列——BootstrapTable+KnockoutJS實現增刪改查解決方案(一)
前言:出於某種原因,需要學習下Knockout.js,這個元件很早前聽說過,但一直沒嘗試使用,這兩天學習了下,覺得它真心不錯,雙向繫結的機制簡直太爽了。今天打算結合bootstrapTable和Knockout去實現一個簡單的增刪改查,來體驗一把神奇的MVVM。關於WebApi的剩餘部分,博主一定抽時間補上。
JS元件系列——BootstrapTable+KnockoutJS實現增刪改查解決方案(二)
前言:上篇 JS元件系列——BootstrapTable+KnockoutJS實現增刪改查解決方案(一) 介紹了下knockout.js的一些基礎用法,由於篇幅的關係,所以只能分成兩篇,望見諒!昨天就覺得應該快點完成下篇,要不然有點標題黨的感覺,思及此,博主心有不安,於是加班趕出了下篇。如果你也打算用ko去做
JS元件系列——BootstrapTable+KnockoutJS實現增刪改查解決方案(三):兩個Viewmodel搞定增刪改查
前言:之前博主分享過knockoutJS和BootstrapTable的一些基礎用法,都是寫基礎應用,根本談不上封裝,僅僅是避免了html控制元件的取值和賦值,遠遠沒有將MVVM的精妙展現出來。最近專案打算正式將ko用起來,於是乎對ko和bootstraptable做了一些封裝,在此分享出來供園友們參考。封裝
JS元件系列——BootstrapTable+KnockoutJS實現增刪改查解決方案(四):自定義T4模板快速生成頁面
前言:上篇介紹了下ko增刪改查的封裝,確實節省了大量的js程式碼。博主是一個喜歡偷懶的人,總覺得這些基礎的增刪改查效果能不能通過一個什麼工具直接生成頁面效果,啥程式碼都不用寫了,那該多爽。於是研究了下T4的語法,雖然沒有完全掌握,但是算是有了一個大致的瞭解,給需要自定義模板的園友們提供一個參考。於是乎有了今天
JS元件系列——分享自己封裝的Bootstrap樹形元件:jqTree
前言:之前的一篇介紹了下如何封裝自己的元件,這篇再次來體驗下自己封裝元件的樂趣。看過博主部落格的園友應該記得之前分享過一篇樹形選單的使用JS元件系列——Bootstrap 樹控制元件使用經驗分享,這篇裡面第一個Jquery Tree,只是用簡單樣式和js去實現了效果,沒有給出一個系統的封裝,這篇博主就來試試
JS元件系列——封裝自己的JS元件,你也可以
前言:之前分享了那麼多bootstrap元件的使用經驗,這篇博主打算研究下JS元件的擴充套件和封裝,我們來感受下JQuery為我們提供$.Extend的神奇,看看我們怎麼自定義自己的元件,比如我們想擴充套件一個$("#id").MyJsControl({})做我們自己的元件,我們該如何去做呢,別急,我們慢慢來
JS元件系列——在ABP中封裝BootstrapTable
前言:關於ABP框架,博主關注差不多有兩年了吧,一直遲遲沒有嘗試。一方面博主覺得像這種複雜的開發框架肯定有它的過人之處,系統的穩定性和健壯性比一般的開源框架肯定強很多,可是另一方面每每想到它繁瑣的封裝和複雜的開發流程就望而卻步,就這樣遲遲沒有行動。最近在專案裡面用到了ABP框架,沒辦法,只有硬著頭皮上了。經
JS元件系列——Bootstrap Table 凍結列功能IE瀏覽器相容性問題解決方案
前言:最近專案裡面需要用到表格的凍結列功能,所謂“凍結列”,就是某些情況下表格的列比較多,需要固定前面的幾列,後面的列滾動。遺憾的是,bootstrap table裡自帶的fixed column功能有一點bug,於是和同事討論該如何解決,於是就有了這篇文章。 一、起因回顧 第一列固定 貌似
JS元件系列——使用HTML標籤的data屬性初始化JS元件
前言:最近使用bootstrap元件的時候發現一個易用性問題,很多簡單的元件初始化都需要在JS裡面寫很多的初始化程式碼,比如一個簡單的select標籤,因為僅僅只是需要從後臺獲取資料填充到option裡面,可是從後臺取資料就需要js的初始化,所以導致頁面初始化的時候js的初始化程式碼裡面出現很多重複
JS元件系列——兩種bootstrap multiselect元件大比拼[轉載]
轉載原文地址:https://www.cnblogs.com/landeanfen/p/5013452.html 前言:今天繼續來看看bootstrap的另一個元件:multiselect。記得在專案開始之前,博主專案組幾個同事就使用哪些js元件展開過討論,其中就說到了select元件,
JS元件系列——表格元件神器:bootstrap table(三:終結篇,最後的乾貨福利)
前言:前面介紹了兩篇關於bootstrap table的基礎用法,這章我們繼續來看看它比較常用的一些功能,來個終結篇吧,毛爺爺告訴我們做事要有始有終~~bootstrap table這東西要想所有功能覆蓋似乎不太現實,博主挑選了一些自認為比較常用的功能在此分享給各位園友。原始
JS元件系列——表格元件神器:bootstrap table
前言:之前一直在忙著各種什麼效果,殊不知最基礎的Bootstrap Table用法都沒有涉及,罪過,罪過。今天補起來吧。上午博主由零開始自己從頭到尾使用了一遍Bootstrap Table ,遇到不少使用方面的問題,也做了一部分筆記,在此分享出來供需要使用的園友參考。還記得前
JS元件系列——表格元件神器:bootstrap table(二:父子表和行列調序)
前言:上篇 JS元件系列——表格元件神器:bootstrap table 簡單介紹了下Bootstrap Table的基礎用法,沒想到討論還挺熱烈的。有園友在評論中提到了父子表的用法,今天就結合Bootstrap table的父子表和行列調序的用法再來介紹下它稍微高階點的用法
JS元件系列——又一款MVVM元件:Vue(一:30分鐘搞定前端增刪改查)
正文 前言:關於Vue框架,好幾個月之前就聽說過,瞭解一項新技術之後,總是處於觀望狀態,一直在猶豫要不要系統學習下。正好最近有點空,就去官網瞭解了下,看上去還不錯的一個元件,就抽空研究了下。最近園子裡vue也確實挺火,各種入門博文眼花繚亂,博主也不敢說寫
JS元件系列——不容錯過的兩款Bootstrap Icon圖示選擇元件
前言:最近好多朋友在群裡面聊到bootstrap icon圖示的問題,比如最常見的選單管理,每個選單肯定需要一個對應的選單圖示,要是有一個視覺化的圖示選擇元件就好了,最好是直接選擇圖示,就能得到對應的class樣式。於是乎各種百度,皇天不負有心人,最後被博主找到了,感覺效果還不錯,並且支援自定義的圖示,今天就