首页 > 解决方案 > 单/双 Bootstrap 列取决于显示大小,在每个列中保留内容顺序,同时不浪费空间

问题描述

我有 6 个不同长度的元素,我试图提出一个引导网格布局来实现以下目标。

在中型和大型显示器中显示的两列布局:

请注意,下例中的框 3 直接在框 1 下方开始,即使框 2 比框 1 长得多。

MD+
|-----|-----|
|  1  |  2  |
|-----|     |    
|  3  |-----|
|-----|  4  |    
|  5  |-----|
|-----|  6  |
      |-----|

对于小于中型的显示器,使用以下单列布局:

XS/SM:
|-----|
|  1  |
|-----|
|  2  |
|     |
|-----|
|  3  |
|-----|
|  4  |
|-----|
|  5  |
|-----|
|  6  |
|-----|

为了彻底,我从不想要 3 列或更多列:

|-----|-----|-----|          
|  1  |  2  |  3  |
|-----|     |-----|     
|  4  |-----|  6  |
|-----|  5  |-----|
      |-----|

并且顺序必须保持 1-6,而不是 1-3 后跟 4-6

我可以使用以下代码分别实现 2 列布局和单列布局,但是当显示尺寸从 SM/MD 更改时它们都会中断,反之亦然:

适用于 XS/SM:

<div class="row">
    <div class="col-xs-12 col-md-6"> 1 </div>
    <div class="col-xs-12 col-md-6"> 2 Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nunc quis interdum diam, in tempor est. Pellentesque nulla mi, egestas et rhoncus non, rhoncus bibendum velit. Nulla facilisi. Aenean faucibus nulla rutrum elementum cursus. Nam vel varius libero, eu porttitor tortor. In et ultricies nunc. Duis volutpat posuere urna, id faucibus ante lobortis sit amet. Maecenas urna nisl, tristique eget sem vel, semper tincidunt nisi.  </div>
    <div class="col-xs-12 col-md-6"> 3 </div>
    <div class="col-xs-12 col-md-6"> 4 </div>
    <div class="col-xs-12 col-md-6"> 5 </div>
    <div class="col-xs-12 col-md-6"> 6 </div>
</div>

适用于 MD+:

<div class="row">
    <div class="col-xs-12 col-md-6">
        <div class="row">
            <div class="col-xs-12"> 1 </div>
            <div class="col-xs-12"> 3 </div>
            <div class="col-xs-12"> 5 </div>
        </div>
    </div>
    <div class="col-xs-12 col-md-6">
        <div class="row">
            <div class="col-xs-12"> 2 Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nunc quis interdum diam, in tempor est. Pellentesque nulla mi, egestas et rhoncus non, rhoncus bibendum velit. Nulla facilisi. Aenean faucibus nulla rutrum elementum cursus. Nam vel varius libero, eu porttitor tortor. In et ultricies nunc. Duis volutpat posuere urna, id faucibus ante lobortis sit amet. Maecenas urna nisl, tristique eget sem vel, semper tincidunt nisi.  </div>
            <div class="col-xs-12"> 4 </div>
            <div class="col-xs-12"> 6 </div>
        </div>
    </div>
</div>    

是否可以使用 Bootstrap 3 获得所需的布局,如果可以,如何?

标签: twitter-bootstrap-3bootstrap-grid

解决方案


我最终拼凑了一个 jquery 解决方案,该解决方案将引导网格结构的 HTML 转换为根据当前显示大小工作的布局。

为方便起见,我还编写了一个类函数,它提供了一个 dz 对象(displaySize),它不仅确定当前引导显示尺寸中的哪个是活动的(xs、sm、md 或 lg),而且还提供了一种执行自定义函数引用的方法如果重新加载后显示大小发生变化(窗口调整大小事件使用下划线去抖动),则向类注册。

这是我最终使用的代码,如果您知道如何仅使用引导网格结构和类来实现这一点,那么请发布答案,因为我宁愿这样做。

对 HTML 的唯一更改是在父 .row 元素 (.custom-layout .custom-layout-2col) 中添加了两个类名。无论您是从单列布局还是 2 列布局开始,都取决于您。只需更改第二个类名以匹配您开始的布局。从哪一个开始并不重要,因为如果需要,代码会将其更改为另一个,但您应该从与大多数用户的显示尺寸相匹配的布局开始。

下面显示了为两列布局添加的类:

<div class="row custom-layout custom-layout-2col">
    <div class="col-xs-12 col-md-6">
        <div class="row">
            <div class="col-xs-12"> 1 </div>
            <div class="col-xs-12"> 3 </div>
            <div class="col-xs-12"> 5 </div>
        </div>
    </div>
    <div class="col-xs-12 col-md-6">
        <div class="row">
            <div class="col-xs-12"> 2 Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nunc quis interdum diam, in tempor est. Pellentesque nulla mi, egestas et rhoncus non, rhoncus bibendum velit. Nulla facilisi. Aenean faucibus nulla rutrum elementum cursus. Nam vel varius libero, eu porttitor tortor. In et ultricies nunc. Duis volutpat posuere urna, id faucibus ante lobortis sit amet. Maecenas urna nisl, tristique eget sem vel, semper tincidunt nisi.  </div>
            <div class="col-xs-12"> 4 </div>
            <div class="col-xs-12"> 6 </div>
        </div>
    </div>
</div> 

的JavaScript:

// This is the dz class. Load this after jquery.
// Note that it instantiates itself, just load it on your page.
// Requires the underscore library (or just the _.restArguments, _.delay, 
// and _.debounce functions from the library if you want to copy them out
// separately. )
; (function () {
    var Def = function () { return constructor.apply(this, arguments); }
    var attr = Def.prototype;

    //attributes
    attr.currentSize = '?';
    attr.previousSize = '?';
    attr.changeHandler = [];

    //constructor
    function constructor() {
        var self = this;
        $(document).ready(function () {
            $('.wrapper-content').append('<div class="device-xs hidden-xs"></div><div class="device-sm hidden-sm"></div><div class="device-md hidden-md"></div><div class="device-lg hidden-lg"></div>');
            $(window).resize(_.debounce(function () {
                self._determineDeviceSize();
            }.bind(self), 200));
            self._determineDeviceSize();
        }.bind(self));
    }

    //methods
    attr.getCurrentSize = function () {
        return this.currentSize;
    }

    attr.getPreviousSize = function () {
        return this.previousSize;
    }

    attr.addChangehandler = function (f) {
        if (typeof f === 'function') { this.changeHandler.push(f); }
    }

    attr._determineDeviceSize = function () {
        var c = this.currentSize;
        this.currentSize = $('.device-lg').is(':hidden') ? 'lg' : ($('.device-md').is(':hidden') ? 'md' : ($('.device-sm').is(':hidden') ? 'sm' : 'xs'));
        if (c !== this.currentSize) {
            this.previousSize = c;
            // execute any registered size change handler functions
            for (i = 0; i < this.changeHandler.length; ++i) {
                this.changeHandler[i](this.currentSize, this.previousSize);
            }
        }
    }

    //unleash the class (if it hasn't already been)
    if (typeof window.dz === 'undefined') {
        window.dz = new Def();
    }
})();


// Register our function with dz for the work that needs to be done
// if the bootstrap display size changes
dz.addChangehandler(function (csz, psz) {
    $('.custom-layout').each(function () {
        var parentRow = $(this);

        // Change from 1 col to 2 col ?
        if (parentRow.is('.custom-layout-1col') && (csz == 'md' || csz == 'lg')) {
            var allDivs = parentRow.children('div');
            var mCt = allDivs.length;
            if (mCt > 0) {
                // create the new row/col structure that we will move all the existing .col-* div's into
                var id = 'custom' + (new Date).getTime();
                var id2 = id + '2';
                parentRow.after('<div class="row custom-layout custom-layout-2col"><div class="col-md-6"><div id="' + id + '" class="row"></div></div><div class="col-md-6"><div id="' + id2 + '" class="row"></div></div></div>');
                var newOddParent = $('#' + id);
                var newEvenParent = $('#' + id2);
                var idx = 0;
                while (idx < mCt) {
                    if (idx === 0 || idx % 2 === 0) {
                        // odd
                        newOddParent.append($(allDivs[idx]));
                    } else {
                        // even
                        newEvenParent.append($(allDivs[idx]));
                    }
                    idx++;
                }
                // remove the old parent from the DOM
                parentRow.remove();
            } else {
                console.log('Unable to change custom-layout -- Unable to locate any div (col-*) elements in parent: ', parentRow);
            }
        }

        // Change from 2 col to 1 col ?
        if (parentRow.is('.custom-layout-2col') && (csz == 'xs' || csz == 'sm')) {
            var childRows = parentRow.children('div').children('.row');
            if (childRows.length == 2) {
                // create the new .row div that we will move all the .col-* div's into
                var id = 'custom' + (new Date).getTime();
                parentRow.after('<div id="' + id + '" class="row custom-layout custom-layout-1col"></div>');
                var newParent = $('#' + id);
                // locate all of the col-* div's that we will be moving
                var oddRowDivs = $(childRows[0]).children('div');
                var evenRowDivs = $(childRows[1]).children('div');
                childRows = '';
                var oCt = oddRowDivs.length;
                var eCt = evenRowDivs.length;
                var mCt = Math.max(oCt, eCt);
                var idx = 0;
                // move the div's directly into the parentDiv in a staggered order
                //  starting with the odd (left side) div #1, then even (right side) div #2, etc..
                while (idx < mCt) {
                    if (idx < oCt) {
                        newParent.append($(oddRowDivs[idx]));
                    }
                    if (idx < eCt) {
                        newParent.append($(evenRowDivs[idx]));
                    }
                    idx++;
                }
                // remove the old parent from the DOM
                parentRow.remove();
            } else {
                console.log('Unable to change custom-layout -- Unable to locate the 2 child .row elements in parent: ', parentRow);
            }
        }
    });
});

如果有人感兴趣,dz 类的用法如下:

  • dz.getCurrentSize() - 返回的值将是客户端设备的当前引导显示大小:xs、sm、md 或 lg
  • dz.getPreviousSize() - 返回的值将是以前的引导显示大小或“?” 如果页面初始化后大小没有改变
  • dz.addChangehandler(functionRef) - 允许您添加自己的显示大小更改处理函数,该函数将在页面加载时以及之后显示大小更改时执行。

示例用法:

// if all you need is the current display size then use the dzCurrentSize variable
// just make sure your accessing it after jquery's $(document).ready
$(document).ready(function () {
    console.log('page size: ' + dz.getCurrentSize());
});


// using a change handler function
dz.addChangehandler(function (currentSize, previousSize) {
    // example usage scenarios:

    // always do stuff (on page initialization and when the size changes anytime afterwards)
    alert("The bootstrap display size is: " + currentSize);

    // do stuff ONLY if the size changed after page initialization
    if (previousSize !== '?') {
        console.log('The size has changed after initialization from: ' + previousSize + ' to: ' + currentSize);
    }

    // do stuff ONLY on page initialization
    if (previousSize === '?') {
        console.log('The page has just initialized with a size of: ' + currentSize);
    }

});

推荐阅读