1. 程式人生 > >JS元件系列——自己動手擴充套件BootstrapTable的 凍結列 功能:徹底解決高度問題

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">&times;</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: 
            
           

相關推薦

no