瀑布流,很常见了,淘宝,网易云音乐等等都有,实现原理,咱先放着一遍,先将涉及到的知识点拓展开来
一、Math的方法
Math求最小值、最大值,
对于一般的数字直接求,Math.min Math.max
但是求数组呢,一个方法,三种形式,js高程书中利用apply的回调函数,将this指向window,直接将所求的数组作为参数传入
封装函数的方法
封装一个getMin的函数直接调用获得
var numbers=[23,435,45,34] function getMin(arr){ //封装一个方法 return min=Math.min.apply(null,arr) //利用apply的回调函数,将作用域this指向window,将数组作为参数传入 } console.log(getMin(numbers))
原型对象的方法一
学过原型对象,直接在Array的原型上添加min方法,让Array拥有min的方法,不推荐,产品化的程序不推荐在基本包装类型添加多余的方法
Array.prototype.min=function(array){ //直接在原型上添加,传递参数 return Math.min.apply(null,array) } alert(numbers.min(numbers))
原型对象的方法二
利用Object.defineProperty方法,这个具体说说
Object.defineProperty(Array.prototype,'max',{ writable:false, enumerable:false, configurable:true, value:function(){ return Math.max.apply(null,numbers) } }) console.log(numbers.max())
拓展之Object.defineProperty方法
object.defineProperty()方法直接在对象上定义个新属性或者修改一个对象的现有属性,并返回这个对象
接受三个参数
obj:要在其上定义属性的对象,可以是引用类型Math,也可以是自定义的,或者原型对象
prop:要定义或修改属性的名称(方法名)
descriptor:将被定义或修改属性的描述符
默认情况下使用此方法添加的属性是不可改变的,但是可以设置一些特性使其可以改变,for in 遍历的到等等
对属性添加特性描述有数据描述和存取器描述两种
数据描述
writable:值是否可以重写
enumerable:目标属性是否可以被枚举
value:设置属性的值,可以为任意的数据类型或函数
configurable:目标属性是否可以被删除或修改
//在String原型对象上添加方法 var str='hello' Object.defineProperty(String.prototype,'newword',{ value:'world' }) alert(str.newword) //单独给某个对象添加方法 var obj={} Object.defineProperty(obj,'newword',{ value:'world' }) alert(obj.newword) //完整的特性例子 var obj={} Object.defineProperty(obj,'newword',{ value:'world', writable:false, //是否重写 enumerable:true, //for in 遍历 configurable:true //是否可以删除属性 是否可以再次修改特性 }) alert(obj.newword) //world obj.newword='hello' //writable为false 所以无效 alert(obj.newword) //word for(var i in obj){ console.log(i) //newword enumerable是true可以遍历 } delete obj.newword alert(obj.newword) //undefined 因为删除了
存取器描述
使用
getter方法 获得属性值
setter方法 设置属性值
当使用getter或setter就不允许使用writable和value这两个属性
var obj={} var initValue='hello' Object.defineProperty(obj,'newword',{ get:function(){ return initValue //得到属性值 }, set:function(value){ //设置属性值 initValue=value } }) console.log(obj.newword)
IE8只能在DOM对象上使用的
有趣的东西
Math.min 和 Math.max 方法
var max=Math.max() var min=Math.min() console.log(max>min) //false
这里min反而是大于max呢?
MDN里解释对于
Math.min()如果没有参数,则返回Infinity
Math.max()如果没有参数,则返回-Infinity
任意参数不能转换为数值,则返回NaN
二、获取指定class的元素
早期的浏览器中不兼容getElementsByClassName 为了获取指定的class元素集合,常常封装一个方法,返回数组
//获得指定class的元素 function getByClass(parent,name){ var lists=parent.getElementsByTagName('*') var arr=[] for(var i=0;i<lists.length;i++){ if(lists[i].className==name){ arr.push(lists[i]) } } return arr }
三、访问元素的样式
普通的访问简单,直接,DOM2级为style设置一些属性和方法,比如CSSText,可以直接访问到css元素属性,为元素应用多项变化最快捷的方式,一次性应用所有的
下面的代码,分别是设置CSSText 移除removeProperty length属性帮忙遍历
//访问元素的样式 //DOM2级中规定 CSSText访问style里的代码 var myDiv=document.getElementById('myDiv') myDiv.style.cssText='200px;height:200px;background:#fee;color:red;' //移除某个css属性 myDiv.style.removeProperty('color') //遍历css属性 length和item的结合 getPropertyValue方法返回的是css属性值的字符串 for(var i=0;i<myDiv.style.length;i++){ console.log(myDiv.style[i]) }
这里补充个非行间样式的获取方法,直接获取非行间样式是不可读的,返回“”
//获取非行间样式 function getStyle(obj,attr){ if(obj.currentStyle){ return obj.currentStyle[attr] //IE是属性 }else{ return getComputedStyle(obj,false)[attr] //其他为方法 } }
注意:如果是CSSText设置的,普通访问还是访问的到的,否则还是用封装函数的方法
四、json的遍历问题
json是一种轻量级的文本数据交换格式,是一种数据格式,支持多种编程语言,具有自我描述性,容易理解
JSON: JavaScript Object Notation(JavaScript 对象表示法)
JSON 是存储和交换文本信息的语法。类似 XML。
JSON 比 XML 更小、更快,更易解析。
下面是简单的json格式和遍历
var json={ 'name':'double', 'age':34, 'sex':'man' } // 对于json格式,一般用for in 遍历其中的元素 for(var i in json){ console.log(i) //得到name age sex 获得的是属性 } for(var j in json){ console.log(json[j]) //得到double 34 man 获得的是属性值 }
嵌套的json遍历,
//嵌套的json格式 var json={ 'name':'double', 'age':34, 'sex':{ 'man':'one', 'woman':'two' } } for(var i in json['sex']){ //遍历嵌套的json格式 console.log(i) //属性 console.log(json['sex'][i]) //属性值 }
五、关于offsetWidth clientHeight scrollTop相关的总结
明天再续写
六、瀑布流的思路
好吧,现在正式说一说瀑布流的问题,前面都是我在瀑布流中遇到的重要的知识点
下面总结一下思路
瀑布流,两步走
第一步,图片大大小小都对齐,不要溢出,不要塌陷
第二部,滚动鼠标,图片源源不断的来,永远滚不到底
解决第一步:
计算页面中的列数,利用列数求出container的宽度
计算最小图片的高度和索引,让次行的第一张图片到达最小图片的下面,且使得那一行的高度增加
解决第二步:
计算鼠标滚动的距离,相比较最后一张图片的scrollHeight
为新加载的图片创建节点,添加到页面上
附上源码,注释标的挺清楚的
window.onload=function(){ waterFall('container','wrap') //这里获取的是整个的wrap,box则不对,因为padding var dataInt={'data':[{'src':'50.jpg'},{'src':'51.jpg'},{'src':'52.jpg'}]} //数据库中的图片,以json的格式传入 window.onscroll=function(){ if(checkScrollSlide()){ var oParent=document.getElementById('container') for(var i=0;i<dataInt.data.length;i++){ //遍历数据库中的图片 var oWrap=document.createElement('div') //添加新节点到原来的HTML中 oWrap.className='wrap' oParent.appendChild(oWrap) var oBox=document.createElement('div') oBox.className='box' oWrap.appendChild(oBox) var oImg=document.createElement('img') oImg.src='images/'+dataInt.data[i].src oBox.appendChild(oImg) } waterFall('container','wrap') //再次的排序 } } } //排序,让图片大小一致的排序 function waterFall(parent,child){ var iParent=document.getElementById(parent) var aLists=getByClass(iParent,child) //获得class为wrap的图片块 //获得列数 var pageWidth=document.documentElement.clientWidth||document.body.clientWidth var boxWidth=aLists[0].offsetWidth cols=Math.floor(pageWidth/boxWidth) //整个页面/单个宽 //根据列数计算contianer宽度 iParent.style.cssText=''+cols*boxWidth+'px;margin:0 auto;' //存放每一行的高度 var colHeight=[] for(var i=0;i<aLists.length;i++){ if(i<cols){ colHeight.push(aLists[i].offsetHeight) //将第一行高度纳入 }else{ //其余行 var minH=Math.min.apply(null,colHeight) //利用Math.min查找数组高度最小 var index=colHeight.indexOf(minH) //获得最小的索引 aLists[i].style.position='absolute' //因为移动,所以设置position/top/left aLists[i].style.top=minH+'px' aLists[i].style.left=boxWidth*index+'px' colHeight[index]+=aLists[i].offsetHeight //最小的高度+接下来的高度,使第二小成为最小,然后依次 } } } //获取class为box的元素 传递两个参数parent className function getByClass(parent,name){ var list=parent.getElementsByTagName('*') var arr=[] for(var i=0;i<list.length;i++){ if(list[i].className==name){ arr.push(list[i]) } } return arr } //检测浏览器是否scroll function checkScrollSlide(){ var oParent=document.getElementById('container') var aWrap=getByClass(oParent,'wrap') var lastWrap=aWrap[aWrap.length-1].offsetTop+Math.floor(aWrap[aWrap.length-1].offsetHeight/2) //获得最后一张图片的距离的高度 var scrollTop=document.documentElement.scrollTop||document.body.scrollTop //scrollTop var clientHeight=document.documentElement.clientHeight||document.body.clientHeight //clientHeight if(lastWrap<scrollTop+clientHeight){ //判断 return true } }
但凡有错,直接指出,相互进步,就马上也过年了,祝大家新年大吉吧!