javascript - 怎么在瀑布流中内嵌一个元素,而且不影响布局

查看:87
本文介绍了javascript - 怎么在瀑布流中内嵌一个元素,而且不影响布局的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

问 题

想图片这样瀑布流中出现内嵌块

解决方案

这有两种方法,
(注:下面的尺寸均为示例,仅用于理清逻辑,具体以实际案例为准)

方法1:用CSS实现的瀑布流

  • 整个瀑布流区域,固定宽度(比如500px),每一小块,宽度,固定116px,小块之间的宽度固定为12px

  • 这样,如果横向四小块的地方,是116px × 4 + 12px × 3 = 500px

  • 大块,宽度为两小块的宽度加上一个横向间隔宽度,即116px × 2 + 12px = 244px

  • 所以,如果横向2小块1大块,是116px × 2 + 244px × 1 + 12px × 2 = 500px

  • 这样,只要让所有大块小块全左浮动或者右浮动,就可以堆成这样的瀑布流

  • 但是,需要注意的是,实际上瀑布流区域在操作的时候,宽度是500px + 12px,具体原因见下图

  • 其中,黄色部分为大框或小框的margin(假设所有的都设置上边距和左边距),那么4个小框其实是有4个宽度间距而并非是3个(有一个在这一排的左侧),所以总宽度应该加上一个12px。

方法2:用JS处理

  • 这个不详细讲了,因为思路是和上面类似,只是是用JS动态去计算出那500px + 12px的值(但其实,只需要算500的值即可,由于瀑布块是绝对定位,不需要用边距将位置空开,空开的区域是通过计算后偏移所得)

  • 对于每一个元素,都相对于瀑布流的外层元素绝对定位,用JS放到对应的位置上去

  • 如果是大元素堆上去的时候,看一下是否处于第四列,如果处于第四列,就强制堆叠在第一列的位置(因为第四列向右只可以堆一列,大块占两列的宽度,所以会堆出屏幕区)

  • 至于如何判断该堆在哪一列,可以用一个长度为4的数组,表示这四列最后一个元素的y值(相对于瀑布流外层元素而言,即绝对定位时的top加上outerHeight)

  • 下一个堆叠的上去的瀑布流元素,查找这个长度为4的数组中最小的一个值,进行附加,然后更新对应数组项的值

  • 不过注意,如果你堆叠大块的时候,需要将下一个项的对应数组值也设置为大框的底部偏移量(假设在第一列插入大框,则需要更新第一列和第二列对应的Y偏移值)

  • 另外,由于很难保证在堆叠大框的时候,大框上面对应两列的元素底边都在同一条上,所以,一般大框都是堆叠在瀑布流最开始的一行(因为这里能保证堆叠时两列的Y偏移量都为0)

  • 此外还有一点要注意,堆叠大框时,判断从哪一列开始堆叠,由偏移量最小的值决定,但是同时也需要考虑到最小Y偏移量的列两侧的偏移,如下图:

  • 此处,Y偏移量第二列虽然是最小,但是第二列周围两列(第一列和第三列),和第二列的落差太大了,但第三第四列反而比较平整,所以大块应该堆叠在第三第四列上

  • 所以,堆叠大块优先判断顺序为:相邻两块的平整性(即下部Y偏移差绝对值最小)> 下部Y偏移最小

其他

大块定位和小块定位有些许区别:

  • 不能从最后一列开始(因为右边没有第二列,强行定位就会偏离瀑布流)

  • 优先要考虑上边缘尽量平整(Math.abs(Y2 - Y1)最小)

  • 在考虑平整的情况下,才考虑上边缘Y偏移最小(主要是为了让元素补全最短的一栏,但是大块需要优先考虑相邻两列平整)

  • 需要同时更新两列的下边缘偏移量

  • 当然,上面没有说的一点是,有个略复杂的办法,解决拼接上边缘不平整的情况,就是先不管边缘是否平整,直接拼接,然后遇到高度适合的小块,再将此小块拼到大块上面,补全缺口(下图中,绿色小块是后来补上去的,而并非在大块定位之前添加好的)。这个方法可能需要两组Y偏移量数据(大块和小块的底边偏移)

最后放上一个之前写的JS瀑布流方法(不含大块定位,但是思路类似,基于jQuery)

$(function(){
    $('.tile-box').each(function(){
        // 获取配置
        var $offset = $(this).attr('offset') || '0,0', // 左上角偏移量(横向,纵向)
            $blocks = $(this).attr('blocks') || '', // 宽度配置(宽度1|宽度2|宽度3|...)
            $margin = $(this).attr('margin') || '0,0'; // 块与块之间的边距(横向,纵向);

        // 解析变量
        // 解析左上角偏移
        $offset = $offset.split(',');
        $offsetX = $offset[0] ? $offset[0] : 0;
        $offsetY = $offset[1] ? $offset[1] : 0;
        
        // 解析区块宽度配置
        $blocks = $blocks.split('|');
        
        // 解析边距配置
        $margin = $margin.split(',');
        $marginX = $margin[0] ? $margin[0] : 0;
        $marginY = $margin[1] ? $margin[1] : 0;
        
        // 初始化位移变量
        var $posX = [], $posY = [];
        for(var i = 0; i < $blocks.length; i++){
            // X粥初始化
            if($posX[i - 1] && $blocks[i - 1]){ // 第二列开始
                $posX.push(parseFloat($posX[i - 1]) + parseFloat($blocks[i - 1]) + parseFloat($marginX));
            }
            else{ // 第一列
                $posX.push(parseFloat($offsetX));
            }
            // Y轴初始化
            $posY.push(parseFloat($offsetY) - parseFloat($marginY));
        }
        
        // 定义所需元素
        var $tilebox = $(this), // 自身
            $tiles = $(this).children(); // 用以排列的元素
            
        // 给父元素加上相对定位(为了子元素可以实现绝对定位)
        $tilebox.css('position', 'relative');
        
        // 遍历需要排列的元素
        $tiles.each(function(){
            // 选择底部偏移最小的列
            var $minIndex = 0;
            for(var i = 1; i < $posY.length; i++){
                if($posY[$minIndex]){
                    if($posY[$minIndex] > $posY[i]){
                        $minIndex = i;
                    }
                }
            }
            
            // 设置当前排列块的定位
            $(this).css({
                'position': 'absolute',
                'width': $blocks[$minIndex],
                'top': $posY[$minIndex] + parseFloat($marginY),
                'left': $posX[$minIndex]
            });
            
            // 设置新的纵向偏移
            $posY[$minIndex] += ($(this).outerHeight(true) ? $(this).outerHeight(true) : $(this).height()) + parseFloat($marginY);
        });
        
        // 选择底部偏移最大的列
        var $maxIndex = 0;
        for(var i = 1; i < $posY.length; i++){
            if($posY[$maxIndex]){
                if($posY[$maxIndex] < $posY[i]){
                    $maxIndex = i;
                }
            }
        }
        
        // 设置父元素的高度
        $tilebox.css('height', $posY[$maxIndex]);
    });
});

这篇关于javascript - 怎么在瀑布流中内嵌一个元素,而且不影响布局的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
相关文章
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆