您好,登錄后才能下訂單哦!
這篇文章主要為大家展示了“JS如何使用Bootstrap Table的凍結列功能徹底解決高度問題”,內容簡而易懂,條理清晰,希望能夠幫助大家解決疑惑,下面讓小編帶領大家一起研究并學習一下“JS如何使用Bootstrap Table的凍結列功能徹底解決高度問題”這篇文章吧。
一、問題追蹤
記得在之前的那篇里面介紹過,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" > <!--<div class="panel panel-default"> <div class="panel-heading">查詢條件</div> <div class="panel-body"> <form id="formSearch" class="form-horizontal"> <div class="form-group" > <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" > <button type="button" 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> <h5 class="modal-title" id="myModalLabel">操作</h5> </div> <div class="modal-body"> <div class="row" > <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" > <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" > <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" > <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" > <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的凍結列功能徹底解決高度問題”這篇文章的所有內容,感謝各位的閱讀!相信大家都有了一定的了解,希望分享的內容對大家有所幫助,如果還想學習更多知識,歡迎關注億速云行業資訊頻道!
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。