web学习-瀑布流布局(1)

在mooc网上学习了瀑布流布局的实现,自己就记录了一下,留作一个笔记^.^

瀑布流样式

在页面中有大大小小的box,box的宽度相同,高度不同,竖直排列成N列,当滚动条向下面滚动的时候自动加载box,形成瀑布流

基本结构

(1)html结构:

<body>
<div id="warp">
 <div class='box'><div class='pic'><img></div><div> 
</div>
</body>

(2)css样式:

* {
    margin: 0;
    padding: 0;
}
warp{
    margin: 0 auto;
}
.box {
    padding: 15px 0 0 15px;
    float: left;
    position: absolute;
}
.pic {
    padding: 10px;
    border: 1px solid #ccc;
    border-right: 5px;
    box-shadow: 0 0 5px #ccc;
}
.pic img {
    width: 165px;
    height: auto;
}

瀑布流实现原理

采用js来实现

  1. 在Css中已经把box都设置成绝对定位,通过box的top,left值来计算出一个盒子该出现的位置.
  2. 在js中维护一个数组,这个数组的长度是瀑布流的列数,数组的值储存键值对应的列的高度,arr[1]指的是第一列的总高度,以此类推.
  3. 新的box应该插入在当前页面所有列中最’短’的列,在arr中值最小既是最小的列,得到该最小值对应的索引就是最’短’ 的列.

滚动加载实现的方式:

  1. 在所有的box中找到排列最后的那个box(靠下面的box都行)
  2. 计算1中box的offsetTop(距离文档顶部的距离)+offsetHeight(box的高度)/2
  3. 计算屏幕的高度,doucment.documentElement.clientHeight
  4. 计算文档距离window的高度,也就是滚动条的高度:document.documentElement.scrollTop
  5. 如果2值<=(4值+3值)的话,那么就可以判断屏幕已经显示到底部了,要加载新的box了

数据请求的时刻:

  1. 页面加载完毕的时候,ajax.send(‘action=first’)
  2. 滚动条滚动到底部的时候ajax.send(‘action=next’)

代码片段

(1)ajax请求的代码

    /**
     * [ajax description] ajax的处理
     * @param  {[string]} url  [description] ajax post的地址
     * @param {string} content [description] ajax send 
     * @return {[string]} json [description] json
     */
    function ajax(url,content,callback){
        var ajax = new XMLHttpRequest();
        ajax.open('post',url);
        ajax.setRequestHeader("Content-Type","application/x-www-form-urlencoded;charset=UTF-8");
        ajax.send(content);
            ajax.onreadystatechange = function(){
            if(ajax.readyState===4 && ajax.status ===200){
                callback(ajax.responseText);
                console.log(ajax.responseText);
            }else{
                return 'error';
            }       
        }
    }

(2)添加盒子的代码

    /**
     * [Boxs description] 在页面中插入盒子
     * @param {[document.node]}   parent   [description]    放入盒子的父节点
     * @param {[array]}   pics     [description] 储存图片地址的数组
     * @param {[int]}   total    [description] 盒子的数目
     * @param {Function} callback(img,pic,box) [description] 回调函数(图片,图片父节点div,box.div)
    */
    function Boxs(pics,total){
        this.total = total || 1;
        this.pictures = pics || null;
        this.addBoxs = function(parent,callback){
            for(var i = 0;i<total;i++){
                var box = document.createElement('div');
                box.className = 'box';
                var pic = document.createElement('div');
                pic.className = 'pic';
                var img = document.createElement('img');
                img.src = pics[i];
                pic.appendChild(img);
                box.appendChild(pic);
                parent.appendChild(box);
                img.onload = callback(img,pic,box);
            }
        }
    }

(3)一些初始化(后台地址,维护的数组,初始化列的宽度)

    const url = './ajaxTest.php';
    var boxWidthArr = [];
    var boxWidth = 0 ;

(4)在window.onload中进行ajax请求,并且计算box的位置

window.onload = function(){
        ajax(url,'action=first',function(response){
            var json = JSON.parse(response);
            boxWidth = json.width;
            var boxRowNum = Math.floor((document.getElementsByTagName('body')[0].offsetWidth) / boxWidth);
            for(var i=0;i<boxRowNum;i++){boxWidthArr[i] = 0;};
            var box = new Boxs(json.files,json.files.length);
            box.addBoxs(document.getElementById('warp'),function(img,pic,box){
                // box添加以及计算
                var minH = Math.min.apply(null,boxWidthArr);//计算储存列高度最小的那个高度
                var minIndex = 0;
                while(minIndex < boxWidthArr.length){if(boxWidthArr[minIndex] == minH) break;minIndex++;}//找到最小值的那个键值
                box.style.top = minH + 15 + 'px';// top的计算是用最小值加上15px
                box.style.left = minIndex*boxWidth + 'px';//left的值是最小值的那个索引乘上盒子的宽度
                boxWidthArr[minIndex] += box.offsetHeight;//每次添加完box要更新所在列的高度对应数组中的值
            });
        })

(5)检查是否要加载图片了,就是滚动条是否滚动到底部了

function checkScrollSlider(){
        var lasbox = document.querySelectorAll('.box')[document.querySelectorAll('.box').length-1];
        var lastBoxDis = lasbox.offsetTop + Math.floor(lasbox.offsetHeight / 2);
        var documentH = document.documentElement.clientHeight;
        var scrollTop = document.documentElement.scrollTop;
        return ((lastBoxDis <= scrollTop + documentH)?true:false);
    };

(6)在window.onscroll中检查是否要加载图片了,没当滚动条动的时候就检查一次

    if(checkScrollSlider()){
        ajax(url,'action=next',function(response){
        var json = JSON.parse(response);
        var box = new Boxs(json.files,json.files.length);
        box.addBoxs(document.getElementById('warp'),function(img,pic,box){
            // box添加以及计算
            var minH = Math.min.apply(null,boxWidthArr);
            var minIndex = 0;
            while(minIndex < boxWidthArr.length){if(boxWidthArr[minIndex] == minH) break;minIndex++;}
            box.style.top = minH + 15 + 'px';
            box.style.left = minIndex*boxWidth + 'px';
            boxWidthArr[minIndex] += box.offsetHeight;
                });
                })
            }
        }

最终的效果:

这里写图片描述

学习总结:

(1)碰到的第一个问题就是img加载的问题.我当时是想是加一张图片就计算它的位置,还是等所有图片都加载完成了在整理他们的位置.后来决定加一张图片就计算位置.当时不知道img有个onload事件,每次都是在设置img的src之后就计算位置,每次计算的都是错误的(当时img根本没有加载完)….坑了,折腾啦好长时间
(2)第二个问题就是那个ajax.send(),它能发送一个http的请求头.但是一开始不知道,不知道怎么让后台代码区分是一开始加载的,还是后面滚动条触发加载的
(3)不能把代码写的很紧密.就采用回调的方式,也不知道这个方式是好是坏

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值