思路
页面 pege 分成左浮动的数列 lineBox ,每列中图片 sinImg 依次向下摆放 每加载一张图片时,判断页面中哪列的高度最小,将当前图片放到最小的那列尾部 监听当前图片 onload 事件,当前图片加载完成后,再加载下一张图片 等待上一张图片加载完的事件,可以用递归完成
实现
初步搭建瀑布流
< div class = " page" >
< div class = " floatBox clearfix" ref = " floatBox" >
< div
class = " lineBox"
v-for = " (item, index) in imgList"
:key = " index"
ref = " lineBox"
>
< div
class = " sinImg"
v-for = " (itemImg, indexImg) in item"
:key = " indexImg"
ref = " sinImg"
>
< img :src = " itemImg.url" alt = " " />
< div class = " desc" > {{ itemImg.desc }}</ div>
</ div>
</ div>
</ div>
</ div>
< style lang = " scss" scoped >
.page {
height : 100%;
.floatBox {
background : #f5f5f5;
padding : 20px;
height : 100%;
box-sizing : border-box;
overflow-y : auto;
.lineBox {
float : left;
margin-right : 10px;
&:last-child {
margin-right : 0;
}
.sinImg {
width : 200px;
margin-bottom : 10px;
background : #fff;
border-radius : 8px;
overflow : hidden;
img {
width : 100%;
height : auto;
}
.desc {
width : 100%;
line-height : 30px;
padding : 10px;
box-sizing : border-box;
}
}
}
}
}
.clearfix:after {
content : "" ;
display : block;
clear : both;
visibility : hidden;
}
</ style>
data ( ) {
return {
randomImg : [
require ( "@I/float1.png" ) ,
require ( "@I/float2.png" ) ,
require ( "@I/float3.png" ) ,
require ( "@I/float4.png" ) ,
require ( "@I/float5.png" ) ,
require ( "@I/float6.png" ) ,
] ,
randomDesc : [
"描述信息,描述信息描述信息,描述信息。" ,
"描述信息描述信息,描述信息,描述信息描述信息描述信息描述信息描述信息。" ,
"描述信息描述信息描述信息。" ,
"描述信息,描述信息描述信息,描述信息描述信息描述信息,描述信息描述信息描述信息描述信息描述信息描述信息。" ,
"描述信息描述信息描述信息,描述信息描述信息描述信息描述信息描述信息。" ,
"描述信息描述信息,描述信息描述信息描述信息描述信息描述信息。" ,
] ,
imgList : [ ] ,
split : 3 ,
} ;
} ,
mounted ( ) {
this . initImg ( ) ;
} ,
methods : {
initImg ( ) {
this . getImgList ( this . split) . then ( ( res ) => {
for ( var i = 0 ; i < this . split; i++ ) {
this . imgList[ i] = [ res[ i] ] ;
}
this . $forceUpdate ( ) ;
} ) ;
} ,
getImgList ( pageSize ) {
return new Promise ( ( resolve, reject ) => {
let imgList = [ ] ;
for ( var i = 0 ; i < pageSize; i++ ) {
let random1 = Math. floor ( Math. random ( ) * ( 0 - 6 ) + 6 ) ;
let random2 = Math. floor ( Math. random ( ) * ( 0 - 6 ) + 6 ) ;
imgList. push ( {
url : this . randomImg[ random1] ,
desc : this . randomDesc[ random2] ,
} ) ;
}
setTimeout ( ( ) => {
resolve ( imgList) ;
} , 500 ) ;
} ) ;
} ,
} ,
判断列高添加图片
遍历数据返回结果数组 判断当前页面中,所有列盒子 lineBox 的高度,选取最低的那一列,将当前遍历的数据结果添加到此列 遍历时,使用定时器 setTimeout ,相当于将执行函数按顺序放到队列中,后续会按照此顺序依次执行
initImg ( ) {
this . getImgList ( this . split) . then ( ( res ) => {
for ( var i = 0 ; i < this . split; i++ ) {
this . imgList[ i] = [ res[ i] ] ;
}
this . $forceUpdate ( ) ;
this . loadMoreImg ( ) ;
} ) ;
} ,
loadMoreImg ( ) {
this . getImgList ( 20 ) . then ( ( res ) => {
res. forEach ( ( item, index ) => {
setTimeout ( ( ) => {
this . pushImg ( item) ;
} , 0 ) ;
} ) ;
} ) ;
} ,
pushImg ( item ) {
let lineBoxArr = this . $refs. lineBox;
let minBoxIndex = 0 ;
let minBox = 0 ;
lineBoxArr. forEach ( ( item, index ) => {
if ( ! minBox) {
minBox = item. offsetHeight;
minBoxIndex = index;
} else if ( item. offsetHeight < minBox) {
minBox = item. offsetHeight;
minBoxIndex = index;
}
} ) ;
this . imgList[ minBoxIndex] . push ( item) ;
this . $forceUpdate ( ) ;
} ,
等待每张图片的 onload 事件
上述方法,队列在依次执行的时候,如果图片较大或者网络环境较差,可能会发生错列的情况。即在上一张图片未完全加载完成时,下一张图片加载前判断列高度最小值不准确的情况。
加入递归思路,请求到结果后,将结果数组赋值给一个递归数组 circleImgList 递归方法中,每次将 circleImgList 的第一项加入到最小列中,并且等待当前 item 的图片加载完后,移除递归数组 circleImgList 的第一项,再调用下次方法,直到递归数组被移除成空数组
circleFunc ( ) {
if ( this . circleImgList && this . circleImgList. length > 0 ) {
let lineBoxArr = this . $refs. lineBox;
let minBoxIndex = 0 ;
let minBox = 0 ;
lineBoxArr. forEach ( ( item, index ) => {
if ( ! minBox) {
minBox = item. offsetHeight;
minBoxIndex = index;
} else if ( item. offsetHeight < minBox) {
minBox = item. offsetHeight;
minBoxIndex = index;
}
} ) ;
this . imgList[ minBoxIndex] . push ( this . circleImgList[ 0 ] ) ;
this . $forceUpdate ( ) ;
this . $nextTick ( ( ) => {
let imgNode = lineBoxArr[ minBoxIndex] . lastChild. children[ 0 ] ;
imgNode. onload = ( ) => {
this . consoleTimeStr ( "当前图片加载完了,进行下一次" , "blue" ) ;
this . circleImgList. shift ( ) ;
this . circleFunc ( ) ;
} ;
} ) ;
}
} ,
consoleTimeStr ( flag, color ) {
let time = new Date ( ) ;
let minute = time. getMinutes ( ) ;
let second = time. getSeconds ( ) ;
let millSecond = time. getMilliseconds ( ) ;
if ( minute < 10 ) {
minute = "0" + minute;
}
if ( second < 10 ) {
second = "0" + second;
}
let str = minute + ":" + second + ":" + millSecond;
console. log ( "%c" + flag + ",当前时间:" + str, "color: " + color + ";" ) ;
} ,
完善
监听瀑布流盒子 floatBox 的滚动事件,当滚动到底部时,加载下一次数据 添加一个 loading 开关,等待当前数据加载完毕,再执行滚动加载事件
< template>
< div class = " page" >
< div class = " floatBox clearfix" ref = " floatBox" >
< div
class = " lineBox"
v-for = " (item, index) in imgList"
:key = " index"
ref = " lineBox"
>
< div
class = " sinImg"
v-for = " (itemImg, indexImg) in item"
:key = " indexImg"
ref = " sinImg"
>
< img :src = " itemImg.url" alt = " " />
< div class = " desc" > {{ itemImg.desc }}</ div>
</ div>
</ div>
</ div>
</ div>
</ template>
< script>
export default {
data ( ) {
return {
randomImg : [
require ( "@I/float1.png" ) ,
require ( "@I/float2.png" ) ,
require ( "@I/float3.png" ) ,
require ( "@I/float4.png" ) ,
require ( "@I/float5.png" ) ,
require ( "@I/float6.png" ) ,
] ,
randomDesc : [
"描述信息,描述信息描述信息,描述信息。" ,
"描述信息描述信息,描述信息,描述信息描述信息描述信息描述信息描述信息。" ,
"描述信息描述信息描述信息。" ,
"描述信息,描述信息描述信息,描述信息描述信息描述信息,描述信息描述信息描述信息描述信息描述信息描述信息。" ,
"描述信息描述信息描述信息,描述信息描述信息描述信息描述信息描述信息。" ,
"描述信息描述信息,描述信息描述信息描述信息描述信息描述信息。" ,
] ,
imgList : [ ] ,
split : 3 ,
circleImgList : [ ] ,
timmer : null ,
loading : false ,
} ;
} ,
mounted ( ) {
this . initImg ( ) ;
} ,
methods : {
initImg ( ) {
this . getImgList ( this . split) . then ( ( res ) => {
for ( var i = 0 ; i < this . split; i++ ) {
this . imgList[ i] = [ res[ i] ] ;
}
this . $forceUpdate ( ) ;
let floatBox = this . $refs. floatBox;
floatBox. addEventListener ( "scroll" , ( e ) => {
this . scrollFunc ( ) ;
} ) ;
this . loadMoreImg ( ) ;
} ) ;
} ,
loadMoreImg ( ) {
this . loading = true ;
this . getImgList ( 20 ) . then ( ( res ) => {
this . circleImgList = JSON . parse ( JSON . stringify ( res) ) ;
this . circleFunc ( ) ;
} ) ;
} ,
getImgList ( pageSize ) {
return new Promise ( ( resolve, reject ) => {
let imgList = [ ] ;
for ( var i = 0 ; i < pageSize; i++ ) {
let random1 = Math. floor ( Math. random ( ) * ( 0 - 6 ) + 6 ) ;
let random2 = Math. floor ( Math. random ( ) * ( 0 - 6 ) + 6 ) ;
imgList. push ( {
url : this . randomImg[ random1] ,
desc : this . randomDesc[ random2] ,
} ) ;
}
setTimeout ( ( ) => {
resolve ( imgList) ;
} , 500 ) ;
} ) ;
} ,
scrollFunc ( ) {
this . throttle ( ( ) => {
let floatBox = this . $refs. floatBox;
let scrollTop = floatBox. scrollTop;
let clientHeight = floatBox. clientHeight;
let scrollHeight = floatBox. scrollHeight;
if ( scrollTop * 1 + clientHeight * 1 >= scrollHeight) {
this . consoleTimeStr ( "滚动到底部了" , "red" ) ;
if ( ! this . loading) {
this . loadMoreImg ( ) ;
}
}
this . timmer = null ;
} , 200 ) ;
} ,
throttle ( func, delay ) {
return ( ( ) => {
if ( this . timmer) {
return ;
} else {
this . timmer = setTimeout ( func, delay) ;
}
} ) ( ) ;
} ,
pushImg ( item ) {
let lineBoxArr = this . $refs. lineBox;
let minBoxIndex = 0 ;
let minBox = 0 ;
lineBoxArr. forEach ( ( item, index ) => {
if ( ! minBox) {
minBox = item. offsetHeight;
minBoxIndex = index;
} else if ( item. offsetHeight < minBox) {
minBox = item. offsetHeight;
minBoxIndex = index;
}
} ) ;
this . imgList[ minBoxIndex] . push ( item) ;
this . $forceUpdate ( ) ;
} ,
circleFunc ( ) {
if ( this . circleImgList && this . circleImgList. length > 0 ) {
let lineBoxArr = this . $refs. lineBox;
let minBoxIndex = 0 ;
let minBox = 0 ;
lineBoxArr. forEach ( ( item, index ) => {
if ( ! minBox) {
minBox = item. offsetHeight;
minBoxIndex = index;
} else if ( item. offsetHeight < minBox) {
minBox = item. offsetHeight;
minBoxIndex = index;
}
} ) ;
this . imgList[ minBoxIndex] . push ( this . circleImgList[ 0 ] ) ;
this . $forceUpdate ( ) ;
this . $nextTick ( ( ) => {
let imgNode = lineBoxArr[ minBoxIndex] . lastChild. children[ 0 ] ;
imgNode. onload = ( ) => {
this . consoleTimeStr ( "当前图片加载完了,进行下一次" , "blue" ) ;
this . circleImgList. shift ( ) ;
this . circleFunc ( ) ;
} ;
} ) ;
} else {
this . loading = false ;
}
} ,
consoleTimeStr ( flag, color ) {
let time = new Date ( ) ;
let minute = time. getMinutes ( ) ;
let second = time. getSeconds ( ) ;
let millSecond = time. getMilliseconds ( ) ;
if ( minute < 10 ) {
minute = "0" + minute;
}
if ( second < 10 ) {
second = "0" + second;
}
let str = minute + ":" + second + ":" + millSecond;
console. log ( "%c" + flag + ",当前时间:" + str, "color: " + color + ";" ) ;
} ,
} ,
} ;
</ script>
< style lang = " scss" scoped >
.page {
height : 100%;
.floatBox {
background : #f5f5f5;
padding : 20px;
height : 100%;
box-sizing : border-box;
overflow-y : auto;
.lineBox {
float : left;
margin-right : 10px;
&:last-child {
margin-right : 0;
}
.sinImg {
width : 200px;
margin-bottom : 10px;
background : #fff;
border-radius : 8px;
overflow : hidden;
img {
width : 100%;
height : auto;
}
.desc {
width : 100%;
line-height : 30px;
padding : 10px;
box-sizing : border-box;
}
}
}
}
}
.clearfix:after {
content : "" ;
display : block;
clear : both;
visibility : hidden;
}
</ style>