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

来源:互联网 发布:js中top对象 编辑:程序博客网 时间:2024/04/30 01:54

在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)不能把代码写的很紧密.就采用回调的方式,也不知道这个方式是好是坏

1 0