@Wangww0925
2019-08-07T05:47:05.000000Z
字数 4936
阅读 189
vue-cli
瀑布流结合了 onresize事件、onscroll事件。onresize事件主要是为了监听窗口尺寸变化;onscroll事件主要是为了滚动到底部加载更多数据
$ul
是li的外部ul,可修改spacingW
间距,可修改columnNum
列数,可修改,默认2vue文件
<template>
<div>
<ul class="article_list w" ref="article_list">
<li class="item" v-for="(item,i) in imgsArr">
<router-link :to="{path:'Detail', query: {id: item.id} }">
<img class="w" :src="item.path" alt="">
<p class="ti24" v-text="item.summary"></p>
</router-link>
</li>
</ul>
<div v-if="!isMore">
<p class="tc" v-text="isMoreText"></p>
</div>
<div class="loading tc" v-if="isFirstLoad" style="font-size: 30px;">正在加载中...</div>
</div>
</template>
<script>
import store from '@/store/store';
export default {
store,
data () {
return {
ajaxData:{ // 列表请求数据
page: 0, // 当前加载的加载图片的次数
},
imgsArr: [], // 列表数据
isFirstLoad:true, // loading
isMore:true, // true-还有更多
isMoreText:'没有更多的内容了',
isPreloading:true, // 滚动到底部,并且能获取数据
}
},
methods: {
DateRenew(){ // 列表初始化
this.imgsArr = []; // 列表数据
this.ajaxData.page = 0; // 页码
this.removeScroll();
this.scroll();
this.getData();
},
getData() { // 请求列表
console.log(this.ajaxData)
this.isFirstLoad = true; // loading显示
this.$http.get("http://118.24.194.224:20001/api/blog/article-list")
.then((res)=>{
this.ajaxData.page++
let result = res.data.body.data
console.log(res)
this.ajaxData.page == 0 ? this.imgsArr = [] : ""; // 避免多次请求出现数据重复
this.imgsArr = this.imgsArr.concat(result)
this.getPosition()
this.isFirstLoad = false; // loading隐藏
},(res)=>{
console.log(res)
})
},
getPosition() { // 不固定列宽的瀑布流
let that = this;
let $ul = that.$refs.article_list;
let spacingW = 15; // 间距
var columnNum = 2; // 一列个数
// 延迟是为了解决ul下的li获取不到问题
setTimeout(function (){
let ulW = $ul.offsetWidth;
let listArr = []; // 存放每个li的top + height值
let $list = $ul.children;
ulW > 900 ? columnNum = 3 : ""; // 大于宽度900的列数为 3
// 如果宽度相等,不执行定位
if(ulW < 700){
$ul.style.height = "auto"
for(var j = 0; j < $list.length; j++){
$list[j].style.position = "";
$list[j].style.width = "100%";
$list[j].style.marginBottom = "15px";
$list[j].setAttribute("class","item fadeOut");
}
}
// 瀑布流布局逻辑
if(ulW >= 700){
for(var i = 0; i < $list.length; i++){
$list[i].style.position = "absolute";
$list[i].style.marginBottom = "0px";
// 设置列宽
let liW = (ulW - spacingW * (columnNum - 1)) / columnNum; // 每个宽度 = (总宽 - 间距)/ 一列个数
$list[i].style.width = `${ liW }px`;
// 当前列高
let liH = $list[i].offsetHeight;
// 设置 top 值;小于一行的个数top都为0
if(i < columnNum){
$list[i].style.top = 0;
$list[i].style.left = `${ (liW + spacingW) * i }px`;
listArr[i] = liH;
}else{
let minTopHeight = Math.min.apply(null, listArr); // 获取数组中的最小值
let minIndex = listArr.indexOf(minTopHeight); // 获取数组中最小值的索引
let liTopHeight = minTopHeight + spacingW; // 当前 top = 上一行对应列的top + 上一行对应列的height + 间距
$list[i].style.top = `${ liTopHeight }px`;
$list[i].style.left = `${ $list[minIndex].offsetLeft }px`; // left = 最低高的left
listArr[minIndex] = $list.length * 500; // 确保下一次获取最小值时不会再次获取到;$list.length * 500 让其一定比数组中所有的值大
listArr[i] = liTopHeight + liH; // 将当前top + 当前height 放到数组中
}
$list[i].setAttribute("class","item fadeOut");
}
let lastEle = $list[$list.length - 1]; // 获取最后一个li
$ul.style.height = `${lastEle.offsetTop + lastEle.offsetHeight + 50 }px`; // 设置ul高度 = 最后一个li的top + 最后一个li的height + 50
}
// 判断无更多数据
// 由于setTimeout是异步,所以isMore不能在返回数据时就判断,会照成没有更多内容提早显示,给用户造成体验不好的感觉
if (that.ajaxData.page === 3) { // 模拟已经无新数据
that.removeScroll()
that.isMore = false;
that.isPreloading = false;
}else{
that.isMore = true;
that.isPreloading = true; // 滚动到底部还原,让其可以继续加载数据
}
},500)
},
scroll(){ // 绑定滚动事件
window.addEventListener('scroll', this.scrollFun,true)
},
scrollFun(){ // 处理滚动事件
let $ul = this.$refs.article_list;
let innerHeight = $ul.clientHeight; // 可滚动容器的高度
let outerHeight = document.documentElement.clientHeight; // 屏幕尺寸高度let
let scrollTop = document.documentElement.scrollTop; // 可滚动容器超出当前窗口显示范围的高度
// 判断滚动到底部
if (innerHeight < (outerHeight + scrollTop)) {
if (this.isPreloading && !this.isMore){ // 可以加载数据,并且数据没有全部加载完毕
this.isPreloading = false // 滚动到底部不能加载数据,等待数据处理完毕时才可以加载数据
this.getData() // 加载数据
}
}
},
removeScroll(){ // 解除滚动事件
window.removeEventListener('scroll', this.scrollFun)
}
},
created : function (){
// console.log("2 - created 实例对象创建完成")
this.DateRenew()
},
watch:{ // 监听
'$store.state.windowResizeW':function(){ // 监听屏幕宽度变化
this.getPosition()
},
'$store.state.windowResizeH':function(){ // 监听屏幕高度变化
this.getPosition()
}
}
}
</script>
<style scoped lang="stylus">
.w
width:100%;
.ti34
text-indent:24px;
.tc
text-align: center;
.boxShadow
box-shadow:0 2px 2px 0 rgba(0,0,0,0.12), 0 3px 1px -2px rgba(0,0,0,0.06), 0 1px 5px 0 rgba(0,0,0,0.12), 0 -1px 0.5px 0 rgba(0,0,0,0.09);
vendor(prop, n)
-webkit-{prop}:n;
-moz-{prop}:n;
-ms-{prop}:n;
-o-{prop}:n;
{prop}:n;
.item
width:100%;
background-color:#fff;
padding:10px;
opacity:0;
vendor('transition',opacity 2s)
&:hover
vendor('transform', translateY(-1px));
box-shadow: 0 1px 3px rgba(0,0,0,.02), 0 9px 15px -4px rgba(0,0,0,.17);
.fadeOut
opacity:1;
.loading
height:50px;
line-height:50px;
text-align:center;
@media screen and (min-width: 992px)
.article_list
position:relative;
.item
@extend .boxShadow;
</style>
作者 wendy
2019 年 1月 4日