js瀑布流效果

js瀑布流效果,宽度自适应,当滚动条滚动到一定的位置按需要加载更多图片,

把最新取得的图片动态从中间散开铺向应有的位置。

一打开网页,刷新的效果,当浏览器窗口宽度只能容纳三张图片的时候:

当浏览器窗口宽度可以容纳4张图片的时候:

js瀑布流效果制作分析

(附件)

完整代码:

<!--
Author: XiaoWen
Create a file: 2016-12-06 14:56:55
Last modified: 2017-01-12 18:29:28
Start to work:
Finish the work:
Other information:
-->
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>瀑布流</title>
  <script src="js/tween.js"></script>
  <script src="js/time_move.js"></script>
  <style>
    *{
      margin: 0;
      padding: 0;
    }
    img{
      border: none;
      width: 220px;
      vertical-align: bottom;
      border-radius:8px;
      box-shadow:0 0 8px #ccc;
      margin: 10px;
      padding: 10px;
    }
    #box{
      position: relative;
      margin:20px auto 0;
    }
    .nv{
      float: left;
      position: absolute;
    }
  </style>
</head>
<body>
<div id="box">
  <div class="nv"><img src="img/1.jpg"></div>
  <div class="nv"><img src="img/2.jpg"></div>
  <div class="nv"><img src="img/3.jpg"></div>
  <div class="nv"><img src="img/4.jpg"></div>
  <div class="nv"><img src="img/5.jpg"></div>
  <div class="nv"><img src="img/6.jpg"></div>
  <div class="nv"><img src="img/7.jpg"></div>
  <div class="nv"><img src="img/8.jpg"></div>
  <div class="nv"><img src="img/9.jpg"></div>
  <div class="nv"><img src="img/10.jpg"></div>
  <div class="nv"><img src="img/11.jpg"></div>
  <div class="nv"><img src="img/12.jpg"></div>
  <div class="nv"><img src="img/13.jpg"></div>
  <div class="nv"><img src="img/14.jpg"></div>
  <div class="nv"><img src="img/15.jpg"></div>
  <div class="nv"><img src="img/16.jpg"></div>
  <div class="nv"><img src="img/17.jpg"></div>
  <div class="nv"><img src="img/18.jpg"></div>
  <div class="nv"><img src="img/19.jpg"></div>
  <div class="nv"><img src="img/20.jpg"></div>
</div>
<script>
window.onload=function(){

//////// 布局
  var yx=document.documentElement.clientWidth;
  var yz=document.documentElement.clientHeight;
  var xw=260; //图片宽度
  var oImgw=220; //图片实际宽度
  var num=Math.floor(yx/xw); //把可视区域的宽/图片宽度=该有几张图 ,不足1张时向下取整
  var amet=box.getElementsByTagName('div');
  box.style.width=xw*num+'px';
  var n=[]; //保存第一行第张图片的高度
  for(var i=0;i<amet.length;i++){
    if(i<num){ //第一行
      amet[i].style.top=0;
      amet[i].style.left=i*xw+'px'; //下标*宽度
      n.push(amet[i].offsetHeight); //保存到数组
    }else{
      var iMin=Math.min.apply(false,n); //获取所有图片中的最小高度
      m=getkey(n,iMin); //返回最小值的下标
      amet[i].style.top=iMin+'px'; //下一张的top=高度最小的那张图片的高度
      amet[i].style.left=(m*xw)+'px'; //下一张的位置=高度最小的那张图片的下标*他的宽度
      n[m]+=amet[i].offsetHeight;
      //把新加上的图片和之前最高度小的图片,让他们两张的高度加起来
      //用这样的方式把最小值改变,否则每次取到的最小值都是一样的
    }
  }
  function getkey(a,b){
    var ikey=0;
    for(var i=0;i<a.length;i++){
      if(a[i]==b){
        ikey=i;
        break
      }
    }
    return ikey
  }

//////// 滚动加载
  var bopen=true; //运行结束才进行请求
  window.onscroll=function(){
    var yy=document.documentElement.scrollTop||document.body.scrollTop;
    var olist=amet[amet.length-1]; //最后一张图片
    //当上次运行结束,并用当页面滚动到最后一张图高度的一半以上才开始加载
    if(bopen&&yy+yz>olist.offsetHeight/2+olist.offsetTop){
      bopen=false;
      var xhr=new XMLHttpRequest();;
      xhr.open('get','waterfall.php',true);
      xhr.send();
      xhr.onreadystatechange=function(){
        if(xhr.readyState==4&&xhr.status==200){
          var alist=JSON.parse(xhr.responseText); //获取数据,转换text为json
          for(var i=0;i<alist.length;i++){ //获取每个对象
            var iMin=Math.min.apply(false,n); //获取最小数
            var m=getkey(n,iMin); //最小数在数组中的下标
            var oImg=document.createElement('img'); //创建img标签
            oImg.src=alist[i].url;
            oImg.style.height=oImgw/alist[i].width*alist[i].height;
            var op=document.createElement('div');
            op.className='nv';
            op.appendChild(oImg); //把 img 插入 div 中
            box.appendChild(op); //把 div 插入 #box
            op.style.top=yz+yy+'px';
            op.style.left=(yz-xw)/2+'px';
            //////// 让合并到一起的对象对象从四周散开
            timeMove(op,{
              left:m*xw,
              top:iMin
            },Tween.Sine.easeOut,1000);
            n[m]+=op.offsetHeight;
          }
          bopen=true; //运动完成
        }
      }
    }
  }
}
</script>
</body>
</html>

动作插件1

js/Tween.js

/*Tween动画算法,来源于FLASH中的ActionScript Tween类
命名空间Tween
整理:CJ(挂个名)
参数说明
curTime:当前时间,即动画已经进行了多长时间,开始时间为0
start:开始值
dur:动画持续多长时间
alter:总的变化量

Elastic中的参数
extent:正弦波的幅度
cycle:正弦波的周期

Back中的s,过冲量,此处数值越大,过冲越大

相对应的下面还分easeIn,easeOut,easeInOut方法
easeIn() 加速度运动,初始速度为0
easeOut() 减速度运动,结束速度为0
easeInOut() 先加速后减速,开始与结束时速度都为0
具体参见ActionScript 3.0 语言和组件参考   
*/
var Tween = {
    Linear:function (start,alter,curTime,dur) {return start+curTime/dur*alter;},//最简单的线性变化,即匀速运动
    Quad:{//二次方缓动
        easeIn:function (start,alter,curTime,dur) {
            return start+Math.pow(curTime/dur,2)*alter;
        },
        easeOut:function (start,alter,curTime,dur) {
            var progress =curTime/dur;
            return start-(Math.pow(progress,2)-2*progress)*alter;
        },
        easeInOut:function (start,alter,curTime,dur) {
            var progress =curTime/dur*2;
            return (progress<1?Math.pow(progress,2):-((--progress)*(progress-2) - 1))*alter/2+start;
        }
    },
    Cubic:{//三次方缓动
        easeIn:function (start,alter,curTime,dur) {
            return start+Math.pow(curTime/dur,3)*alter;
        },
        easeOut:function (start,alter,curTime,dur) {
            var progress =curTime/dur;
            return start-(Math.pow(progress,3)-Math.pow(progress,2)+1)*alter;
        },
        easeInOut:function (start,alter,curTime,dur) {
            var progress =curTime/dur*2;
            return (progress<1?Math.pow(progress,3):((progress-=2)*Math.pow(progress,2) + 2))*alter/2+start;
        }
    },
    Quart:{//四次方缓动
        easeIn:function (start,alter,curTime,dur) {
            return start+Math.pow(curTime/dur,4)*alter;
        },
        easeOut:function (start,alter,curTime,dur) {
            var progress =curTime/dur;
            return start-(Math.pow(progress,4)-Math.pow(progress,3)-1)*alter;
        },
        easeInOut:function (start,alter,curTime,dur) {
            var progress =curTime/dur*2;
            return (progress<1?Math.pow(progress,4):-((progress-=2)*Math.pow(progress,3) - 2))*alter/2+start;
        }
    },
    Quint:{//五次方缓动
        easeIn:function (start,alter,curTime,dur) {
            return start+Math.pow(curTime/dur,5)*alter;
        },
        easeOut:function (start,alter,curTime,dur) {
            var progress =curTime/dur;
            return start-(Math.pow(progress,5)-Math.pow(progress,4)+1)*alter;
        },
        easeInOut:function (start,alter,curTime,dur) {
            var progress =curTime/dur*2;
            return (progress<1?Math.pow(progress,5):((progress-=2)*Math.pow(progress,4) +2))*alter/2+start;
        }
    },
    Sine :{//正弦曲线缓动
        easeIn:function (start,alter,curTime,dur) {
            return start-(Math.cos(curTime/dur*Math.PI/2)-1)*alter;
        },
        easeOut:function (start,alter,curTime,dur) {
            return start+Math.sin(curTime/dur*Math.PI/2)*alter;
        },
        easeInOut:function (start,alter,curTime,dur) {
            return start-(Math.cos(curTime/dur*Math.PI/2)-1)*alter/2;
        }
    },
    Expo: {//指数曲线缓动
        easeIn:function (start,alter,curTime,dur) {
            return curTime?(start+alter*Math.pow(2,10*(curTime/dur-1))):start;
        },
        easeOut:function (start,alter,curTime,dur) {
            return (curTime==dur)?(start+alter):(start-(Math.pow(2,-10*curTime/dur)+1)*alter);
        },
        easeInOut:function (start,alter,curTime,dur) {
            if (!curTime) {return start;}
            if (curTime==dur) {return start+alter;}
            var progress =curTime/dur*2;
            if (progress < 1) {
                return alter/2*Math.pow(2,10* (progress-1))+start;
            } else {
                return alter/2* (-Math.pow(2, -10*--progress) + 2) +start;
            }
        }
    },
    Circ :{//圆形曲线缓动
        easeIn:function (start,alter,curTime,dur) {
            return start-alter*Math.sqrt(-Math.pow(curTime/dur,2));
        },
        easeOut:function (start,alter,curTime,dur) {
            return start+alter*Math.sqrt(1-Math.pow(curTime/dur-1));
        },
        easeInOut:function (start,alter,curTime,dur) {
            var progress =curTime/dur*2;
            return (progress<1?1-Math.sqrt(1-Math.pow(progress,2)):(Math.sqrt(1 - Math.pow(progress-2,2)) + 1))*alter/2+start;
        }
    },
    Elastic: {//指数衰减的正弦曲线缓动
        easeIn:function (start,alter,curTime,dur,extent,cycle) {
            if (!curTime) {return start;}
            if ((curTime==dur)==1) {return start+alter;}
            if (!cycle) {cycle=dur*0.3;}
            var s;
            if (!extent || extent< Math.abs(alter)) {
                extent=alter;
                s = cycle/4;
            } else {s=cycle/(Math.PI*2)*Math.asin(alter/extent);}
            return start-extent*Math.pow(2,10*(curTime/dur-1)) * Math.sin((curTime-dur-s)*(2*Math.PI)/cycle);
        },
        easeOut:function (start,alter,curTime,dur,extent,cycle) {
            if (!curTime) {return start;}
            if (curTime==dur) {return start+alter;}
            if (!cycle) {cycle=dur*0.3;}
            var s;
            if (!extent || extent< Math.abs(alter)) {
                extent=alter;
                s =cycle/4;
            } else {s=cycle/(Math.PI*2)*Math.asin(alter/extent);}
            return start+alter+extent*Math.pow(2,-curTime/dur*10)*Math.sin((curTime-s)*(2*Math.PI)/cycle);
        },
        easeInOut:function (start,alter,curTime,dur,extent,cycle) {
            if (!curTime) {return start;}
            if (curTime==dur) {return start+alter;}
            if (!cycle) {cycle=dur*0.45;}
            var s;
            if (!extent || extent< Math.abs(alter)) {
                extent=alter;
                s =cycle/4;
            } else {s=cycle/(Math.PI*2)*Math.asin(alter/extent);}
            var progress = curTime/dur*2;
            if (progress<1) {
                return start-0.5*extent*Math.pow(2,10*(progress-=1))*Math.sin( (progress*dur-s)*(2*Math.PI)/cycle);
            } else {
                return start+alter+0.5*extent*Math.pow(2,-10*(progress-=1)) * Math.sin( (progress*dur-s)*(2*Math.PI)/cycle);
            }
        }
    },
    Back:{
        easeIn: function (start,alter,curTime,dur,s){
            if (typeof s == "undefined") {s = 1.70158;}
            return start+alter*(curTime/=dur)*curTime*((s+1)*curTime - s);
        },
        easeOut: function (start,alter,curTime,dur,s) {
            if (typeof s == "undefined") {s = 1.70158;}
            return start+alter*((curTime=curTime/dur-1)*curTime*((s+1)*curTime + s) + 1);
        },
        easeInOut: function (start,alter,curTime,dur,s){
            if (typeof s == "undefined") {s = 1.70158;}
            if ((curTime/=dur/2) < 1) {
                return start+alter/2*(Math.pow(curTime,2)*(((s*=(1.525))+1)*curTime- s));
            }
            return start+alter/2*((curTime-=2)*curTime*(((s*=(1.525))+1)*curTime+ s)+2);
        }
    },
    Bounce:{
        easeIn: function(start,alter,curTime,dur){
            return start+alter-Tween.Bounce.easeOut(0,alter,dur-curTime,dur);
        },
        easeOut: function(start,alter,curTime,dur){
            if ((curTime/=dur) < (1/2.75)) {
                return alter*(7.5625*Math.pow(curTime,2))+start;
            } else if (curTime < (2/2.75)) {
                return alter*(7.5625*(curTime-=(1.5/2.75))*curTime + .75)+start;
            } else if (curTime< (2.5/2.75)) {
                return alter*(7.5625*(curTime-=(2.25/2.75))*curTime + .9375)+start;
            } else {
                return alter*(7.5625*(curTime-=(2.625/2.75))*curTime + .984375)+start;
            }
        },
        easeInOut: function (start,alter,curTime,dur){
            if (curTime< dur/2) {
                return Tween.Bounce.easeIn(0,alter,curTime*2,dur) *0.5+start;
            } else {
                return Tween.Bounce.easeOut(0,alter,curTime*2-dur,dur) *0.5 + alter*0.5 +start;
            }
        }
    }
};
View Code

动作插件2

js/time_move.js

function timeMove(obj, target, type, times, fn) {
    clearInterval(obj.timer);
    var iStartTime = new Date().getTime();
    var oCur = {};
    for(var sAttr in target) {
        if(sAttr == 'opacity') {
            oCur[sAttr] = Math.round(parseFloat(getStyle(obj, 'opacity'))*100);
        } else {
            oCur[sAttr] = parseInt(getStyle(obj, sAttr));
        }
    }
    obj.timer = setInterval(function () {
        var iChangeTime = new Date().getTime();
        var iScale = 1 - Math.max((iStartTime + times - iChangeTime)/times, 0);

        for(var sAttr in target) {
            var iCur = type(oCur[sAttr], target[sAttr] - oCur[sAttr], times * iScale, times);

            if(sAttr == 'opacity') {
                obj.style.opacity = iCur/100;
                obj.style.filter = 'alpha(opacity:' + iCur + ')';
            } else {
                obj.style[sAttr] = iCur + 'px';
            }
        }

        if(iScale == 1) {
            clearInterval(obj.timer);
            fn && fn();
        }
    }, 30);
}
// 获取属性样式
function getStyle(obj, sAttr) {
    if(obj.currentStyle) {
        return obj.currentStyle[sAttr];
    } else {
        return getComputedStyle(obj, false)[sAttr];
    }
}
View Code

php后台文件

/waterfall.php

<?php
    $data = array(
        array(
            'url' => 'img/1.jpg',
            'width' => 595,
            'height' => 914,
        ),
        array(
            'url' => 'img/2.jpg',
            'width' => 900,
            'height' => 1318,
        ),
        array(
            'url' => 'img/3.jpg',
            'width' => 600,
            'height' => 850,
        ),
        array(
            'url' => 'img/4.jpg',
            'width' => 512,
            'height' => 726,
        ),
        array(
            'url' => 'img/5.jpg',
            'width' => 567,
            'height' => 850,
        ),
        array(
            'url' => 'img/6.jpg',
            'width' => 361,
            'height' => 510,
        ),
        array(
            'url' => 'img/7.jpg',
            'width' => 510,
            'height' => 765,
        ),
        array(
            'url' => 'img/8.jpg',
            'width' => 400,
            'height' => 600,
        ),
        array(
            'url' => 'img/9.jpg',
            'width' => 460,
            'height' => 690,
        ),
        array(
            'url' => 'img/10.jpg',
            'width' => 683,
            'height' => 1024,
        ),
        array(
            'url' => 'img/11.jpg',
            'width' => 960,
            'height' => 1280,
        ),
        array(
            'url' => 'img/12.jpg',
            'width' => 427,
            'height' => 640,
        ),
        array(
            'url' => 'img/13.jpg',
            'width' => 607,
            'height' => 914,
        ),
        array(
            'url' => 'img/14.jpg',
            'width' => 402,
            'height' => 600,
        ),
        array(
            'url' => 'img/15.jpg',
            'width' => 720,
            'height' => 480,
        ),
        array(
            'url' => 'img/16.jpg',
            'width' => 658,
            'height' => 989,
        ),
        array(
            'url' => 'img/17.jpg',
            'width' => 641,
            'height' => 960,
        ),
        array(
            'url' => 'img/18.jpg',
            'width' => 658,
            'height' => 987,
        ),
        array(
            'url' => 'img/19.jpg',
            'width' => 600,
            'height' => 900,
        ),
        array(
            'url' => 'img/20.jpg',
            'width' => 683,
            'height' => 993,
        ),
    );
    echo json_encode($data);
View Code
原文地址:https://www.cnblogs.com/daysme/p/6279414.html