JS 实现瀑布流

作者: ghwaphon | 来源:发表于2016-09-14 23:18 被阅读2025次

    在极客学院下载的 JS 基础视屏中提到了瀑布流效果,花了一下午的时间去学习,到现在终于也算有所理解了,自己也动手实现了这么一个效果,来看一下吧。

    demo.gif

    我个人感觉这个效果还是比较好看的,下面我们就来看看怎么实现吧。

    HTML 代码

    其实 HTML 的编码是极其简单的,我们去除重复的部分,来看看核心代码

    <div id="container">
        <div class="box">
            <div class="box_img">
                <img src="imgs/1.jpg">
            </div>
        </div>
    </div>
    

    其实在 container 内部不止一个 div 标签,这里是为了简单,所以将其他的代码都省略了。 这里为什么要设置双层 div 包含住 img 标签呢,这里是为了在后面的 JS 代码中设置 position 属性,到后面自然而然就明白了。

    CSS 代码

    * {
        margin: 0px;
        padding: 0px;
    }
    
    #container {
        position: relative;
    }
    
    .box {
        float: left;
        padding: 15px 0 0 15px;
    }
    
    .box .box_img {
        padding: 10px;
        border: 1px solid #cccccc;
        border-radius: 5px;
        box-shadow: 0px 0px 6px #cccccc;
    }
    
    .box_img img {
        width: 172px;
        height: auto;
    }
    

    * 选择器的使用可以说是遭受非议的,有人认为它的杀伤力太大了,不可以轻易的使用,但是作为初学者的我来说,还是十分喜欢使用其去除外边距和内边距。 这里我们为了好看,也是为图片设置了内边距,边框和阴影属性,值得一提的是为了保持所有的图片具有共同的宽度,我们将其设置为统一的 172px,为什么设置为 172px 呢?我随便设的,你可以自己指定,高度的话我们设置成 auto , 建议不要自己指定,不然你还实现什么瀑布流啊?图片的高度宽度都相同,还有什么瀑布流可言,顺序排列不就可以了吗?

    我刚开始看瀑布流教学视屏的时候,是非常开心的,为什么呢?因为 HTML 代码和 CSS 代码真的好少哦。可是看到 JS 代码就不开心了,真的好长。好了,不吐槽了,来看看 JS 代码吧。

    JS 代码

    由于 JS 代码过长,所以我们逐段来分析,下面来看第一段。

    function location(parent, child) {
       1  var vparent = document.getElementById(parent);
       2  var childArray = getChild(vparent, child);
       3  var imgWidth = childArray[0].offsetWidth;
       4  var cols = Math.floor(document.documentElement.clientWidth / imgWidth); // 计算每行能容纳多少列
       5  vparent.style.cssText = "width : " + imgWidth * cols + "px;margin:0 auto;";
    
       6  var boxHeightArray = [];
       7  for (var i = 0; i < childArray.length; i++) {
       8    if (i < cols) {
       9        boxHeightArray[i] = childArray[i].offsetHeight;
       10    } else {
       11        var minHeight = Math.min.apply(null, boxHeightArray);
       12        var minIndex = getIndex(boxHeightArray, minHeight);
    
       13        childArray[i].style.position = "absolute";
       14        childArray[i].style.top = minHeight + "px";
       15        childArray[i].style.left = childArray[minIndex].offsetLeft + "px";
       16        boxHeightArray[minIndex] = boxHeightArray[minIndex] + childArray[i].offsetHeight;
            }
        }
    }
    

    分析一个函数之前,我们首先要知道这个函数要实现的功能是什么?方法的名称叫做 location , 所以该方法肯定要实现一个定位功能?给谁定位?当然是给图片定位!

    • 第 1 - 3 行 : 获取当前 页面中 有多少张图片要展示并且获取图片的宽度。
    • 第 4 行 : 计算当前一行能容纳多少列,也即一行能容纳多少个图片的展示。
    • 第 5 行 : 将承载图片的父节点(其实这个时候就是 container)设置为指定行,并且居中显示。
    • 第 9 行 :将第一行图片的距离页面顶端的高度记录在一个数组中。
    • 第 10 - 16 行 : 获取到第一行中高度最小的那张图片,将其在数组中的下标获取到,然后将下一行的图片放置到高度最小的图片的下方,更新高度值。其实这很像一个计数功能,当我们知道了一行放置多少图片之后,当我们放满了第一行,将高度值存放在数组中,从第二行开始,寻找数组中最小的那个值,然后将图片放在这一列,更新数组值。

    在以上代码中我们用到了 两个自定义的方法,分别是 getChild()getIndex(),很容易理解,这里 只粘贴代码,就不在解释。

    function getIndex(boxHeightArray, mingHeight) {
        for (var i = 0; i < boxHeightArray.length; i++) {
            if (boxHeightArray[i] == mingHeight) {
                return i;
            }
        }
    }
    
    function getChild(parent, child) {
        var contentArray = [];
        var allcontent = parent.getElementsByTagName("*");
        for (var i = 0; i < allcontent.length; i++) {
            if (allcontent[i].className == child) {
                contentArray.push(allcontent[i]);
            }
        }
        return contentArray;
    }
    

    其实,通过上述方法,我们就实现了一个瀑布流效果,但是我们还想实现另一个效果,就是我们可以不断下拉,那么这个功能该怎么实现呢?既然想实现下拉动态加载效果,那么我们至少应该在什么时候开始动态加载吧?下面就来实现这么一个功能。

    function check() {
        var parent = document.getElementById("container");
        var child = getChild(parent, "box");
    
        var lastContentHeight = child[child.length - 1].offsetTop;
        var scrollTop = document.documentElement.scrollTop || document.body.scrollTop;
        var pageHeight = document.documentElement.clientHeight || document.body.clientHeight;
    
        if (lastContentHeight <= scrollTop + pageHeight) {
            return true;
        }
    }
    

    lastContentHeight 的值是最后一张图片到页面顶部的距离。 scrollTop 的值是当前正在显示的之前隐藏的部分。什么意思呢?举个例子来说,当我们进入一个网页,这个网页右垂直滚动条,那么刚进去时显示的肯定是网页的一部分,还有一部分处于隐藏状态,那么 scrollTop 的值就是从当前可见页面的底部开始从 0 计数的,往下拉,这个值就会递增。 pageHeight 的值就是当前可见页面的高度。那么最后的 if 条件判断是什么意思呢?这个判断语句的意思就是,当我们下拉到最后一张图片的顶部的时候,开始动态加载图片。好了,下面我们去看看加载图片的逻辑代码。

    window.onscroll = function () {
        var imgData = {
            "data": [
                {"src": "1.jpg"},
                {"src": "2.jpg"},
                {"src": "3.jpg"},
                {"src": "4.jpg"},
                {"src": "5.jpg"},
                {"src": "6.jpg"},
                {"src": "7.jpg"},
                {"src": "8.jpg"}]
        };
    
        if (check()) {
            var parent = document.getElementById("container");
            for (var i = 0; i < imgData.data.length; i++) {
    
                var box = document.createElement("div");
                box.className = "box";
                parent.appendChild(box);
    
                var boximg = document.createElement("div");
                boximg.className = "box_img";
                box.appendChild(boximg);
    
                var img = document.createElement("img");
                img.src = "imgs/" + imgData.data[i].src;
                boximg.appendChild(img);
            }
    
            location("container", "box");
        }
    }
    

    其实这段逻辑代码反而好懂,意思就是当我们的页面滑动了,而且符合我们对动态加载图片的判断,即开始创建节点,和我们在 HTML 代码中创建的结构相同,这样我们才可以复用 CSS代码。在底部别忘了调用 location() 函数,不然的话我们在新加载的图片中是无法看到瀑布流效果的。还有一个值得注意的地方,就是这里我们也看到了我们使用的是 window.scroll ,就意味着,我们必须要能够满足能够滑动的事件,说的再通俗一点,就是初始的图片要高于当前浏览器可见的高度。

    好了,瀑布流的效果就介绍到这里,大家中秋快乐。

    相关文章

      网友评论

      • Keyesu:没有浏览器适配吧。打开格式都不一样了
      • kidd_hlt:还好看懂了!!!有收获!
        ghwaphon:@kidd_hlt 很高兴帮助到你
      • 西泽大大:给个链接
        ghwaphon:@西泽大大 https://pan.baidu.com/s/1i45ZUUL
      • 一棵树的时光:没看懂,代码看不全呢
        ghwaphon:@一棵树的时光 中午我会将代码共享到百度云,会给你发送链接地址
        一棵树的时光: @千里追风 谢谢。什么链接呢?
        ghwaphon: @一棵树的时光 你好,你可以给我一个链接,我会在午饭时间将验证代码发送给你

      本文标题:JS 实现瀑布流

      本文链接:https://www.haomeiwen.com/subject/tmzvettx.html