JS 实现瀑布流

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 ,就意味着,我们必须要能够满足能够滑动的事件,说的再通俗一点,就是初始的图片要高于当前浏览器可见的高度。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值