瀑布流
前几天做一个类似便利贴的项目,我想了很多页面的设计,但是最后还是敲定使用瀑布流来展示,可以充分利用空间,而且给人浏览的欲望,但是做起来可没那么简单,我们先试一试吧
由于项目中使用 jQuery,故演示也使用 jQuery
const waterfall=(container)=>{
const childs=container.children()
const arr=[]
// 存放每列高度的数组,依据此来确定每次放置节点的位置
const cols=parseInt(($('#root').outerWidth(true)) / ($(childs).outerWidth(true)))
// 确定列数,因为第一行的放置的其余行不相同,所以要分开处理,而且要向下取整
for(let i=0;i<childs.length;i++){
// 放置第一行图片
if(i<cols){
$(childs[i]).css({
top:0,
// 我们取元素的最大宽度,也就是包括了 margin,因为有可能用户设置了 margin,我们把它看成一个盒子的整体
left:`${i*$(childs).outerWidth(true)}px`
})
// 把第一列的高度 push 进去,以后循环需要使用
arr.push($(childs[i]).outerHeight(true))
}else{
let minHeight=arr[0]
let index=0
for(let j=0;j<arr.length;j++){
if(arr[j]<minHeight){
// 从第二行元素开始,每轮循环找到高度最小的上一行元素,记录其高度和列的下标,也就是 index(下面有用)
minHeight=arr[j]
index=j
}
}
// 设置 top 为我们找到的最小高度,index 为最小高度的的列数的下标
// 这个 childs[index] 不一定是那个最小高度的元素,但是列是一样的,我们只需要取他的 offsetLeft 即可
$(childs[i]).css({
top:`${minHeight}px`,
left:`${childs[index].offsetLeft}px`
})
// arr 是我们用来判定每次最小高度的数组,它的长度永远只有 cols 那么长
// 所以我们每次放置元素后,需要修改刚刚用过的最小高度,变成刚刚放置的元素的高度加上原来的高度
arr[index]=arr[index]+$(childs[i]).outerHeight(true)
}
}
}
我认为,瀑布流比较核心的一点就是最小高度数组的处理,在最后一步,我们嫁接了高度,这样每次的最小高度在使用完之后,也就是放置一个元素之后,它将不会是最小高度了,那么第二小高度便开始生效,转换成视图就是每次先在高度最小的列放置节点
注意最后一步嫁接不要写成
arr[index]=arr[index]+minHeight
是因为 minHeight 其实和对应的 arr[index] 相等,可以说,它是旧的每一列的最小高度,所以应该加上该放置元素的高度完成嫁接
可以拖曳的 div
那就要先熟悉三个鼠标事件,鼠标按下(mousedown),鼠标移动(mousemove),鼠标松开(mouseup)
思路基本是,我们要知道鼠标移动的距离,然后把这个改变利用事件同步到元素上
let drag
let position
xxx.addEventListener('mousedown',(e)=>{
drag=true
position=[e.clientX,e.clientY]
})
document.addEventListener('mousemove',(e)=>{
if(!drag)return
let moveX=e.clientX-position[0]
let moveY=e.clientY-position[1]
let x=moveX+parseInt(xxx.getBoundingClientRect().left||0)
let y=moveY+parseInt(xxx.getBoundingClientRect().top||0)
xxx.style.transform=`translate(${x}px,${y}px)`
position=[e.clientX,e.clientY]
})
document.addEventListener('mouseup',()=>{
drag=false
})
试玩地址:JS Bin - JS Bin
我们在鼠标按下时,确定鼠标的位置,我们把移动分割为帧,每一帧我们先算出当前鼠标的落点,然后减去上一次的鼠标落点,得出 moveX 和 moveY
不过我们只拿到了变化量,我们还需要通过 getBoundingClientRect 得到元素距离视口的位置,进行相加才得到最终位置
总结
使用瀑布流要注意最小高度数组的设置
拖曳 div 的核心就是拿到变化量,然后对鼠标落点进行重置,便于下一次移动
现在可以用瀑布流和拖曳 div 做出很好看的效果啦