页面布局和UI全部使用的elementUI,很多代码都是抄人家的案例。
使用到的组件有:无限滚动,图片懒加载,图片占位,卡片,图片详情Dialog
import CommonHeader from '../components/CommonHeader.vue';
import PicDetail from './pic/PicDetail.vue';
const imgurl = 'http://103.45.251.27:8888/img/';
export default {
name: 'v-waterfall',
components: {
CommonHeader,
PicDetail
},
data() {
return {
//存放计算好的数据
waterfallList: [],
//每一列的宽度
imageWidth: 200,
//多少列
waterfallImgCol: 5,
//右边距
waterfallImgRight: 20,
//下边距
waterfallImgBottom: 10,
//存放瀑布流各个列的高度
waterfallColHeight: [],
imgList: [],
//整体左偏移量,左右相同
colLeft: 0,
currentPage: 1,
//是否还有数据
noMore: false,
//搜索内容
searchKey: '',
//图片详情弹窗可见
dialogVisible: false,
//点击的图片ID
picId:'',
//随机占位色卡的颜色
suijicolour: ['#b4ffe3','#66CDAA','#acc2e6','#d7b0d8','#95abe6','#ffc47b','#b6d288','#f49586','#bcaf7a'],
};
},
created() {
//初始就加载数据
this.getMoreData();
},
mounted() {
//计算可视区域能够容纳的最大列数,向下取整
let fullWidth = this.$refs.abc.clientWidth;
if (fullWidth > 1500) {
this.imageWidth = 240;
} else if (fullWidth < 800) {
this.imageWidth = 170;
}
let maxColNum = Math.floor(fullWidth / (this.imageWidth + this.waterfallImgRight));
console.log('可视宽度:' + fullWidth + ',列数:' + maxColNum);
if (maxColNum == 0) {
maxColNum = 1;
}
let contentWhith = (this.imageWidth + this.waterfallImgRight) * maxColNum;
if ((fullWidth - contentWhith) < (this.imageWidth * 0.8)) {
maxColNum--;
contentWhith = (this.imageWidth + this.waterfallImgRight) * maxColNum;
}
console.log('计算列数:' + maxColNum);
this.waterfallImgCol = maxColNum;
//获取左边距
this.colLeft = (fullWidth - contentWhith) / 2;
console.log('总宽度:' + fullWidth + ',内容宽度:' + contentWhith + '左偏移:' + this.colLeft);
//初始化偏移高度数组
this.waterfallColHeight = new Array(this.waterfallImgCol);
for (let i = 0; i < this.waterfallColHeight.length; i++) {
this.waterfallColHeight[i] = 0;
}
},
methods: {
//搜索,从其他组件传值放到$store中的
search() {
//点击查询重置页数和瀑布流每列高度
this.currentPage = 1;
for (let i = 0; i < this.waterfallColHeight.length; i++) {
this.waterfallColHeight[i] = 0;
}
this.waterfallList = [];
this.getMoreData();
},
// 获取数据
getMoreData() {
//表单数据
let param = {
pageNo: this.currentPage++,
pageSize: 10,
orderBy: 'updateTime desc'
};
let search = this.$store.state.searchText;
console.log('查询参数:' + search);
if (search.trim().length > 0) {
param.title = search.trim();
}
console.log('查询参数:' + JSON.stringify(param));
// if(param.pageNo>10){this.noMore=true;return;}
this.$axios.get('/api/pic/query', {
params: param
}).then(response => {
// console.log('获取数据', response.data);
if (response.data.success) {
if (response.data.data.rows.length == 0) {
this.noMore = true;
} else {
this.imgPreloading(response.data.data.rows);
this.noMore = false;
}
} else {
this.$message.error(response.data.msg);
this.noMore = true;
}
}, response => {
this.$message.error('错误');
this.noMore = true;
});
},
//图片预加载
imgPreloading(moreList) {
let listLen = this.waterfallList.length;
for (let i = 0; i < moreList.length; i++) {
if(moreList[i].imgUrl.indexOf('http') > 0){
continue;
}
let aImg = new Image();
//图片渲染列表,先把高宽和占位颜色赋值直接push到waterfallList,图片的实际url等图片加载上了在赋值
let imgData = {};
imgData.height = this.imageWidth / moreList[i].width * moreList[i].height;
// console.log('第' + i + '张图片的高度是:'+imgData.height );
imgData.id = moreList[i].id;
//获取随机占位背景色
imgData.colour=this.suijicolour[i%9];
this.waterfallList.push(imgData);
aImg.onload = (e) => {
aImg.src = imgurl + moreList[i].imgUrl;
};
this.rankImg(imgData);
imgData.src = imgurl + moreList[i].imgUrl;
}
},
//瀑布流布局核心,计算高度和左偏移
rankImg(imgData) {
let {
imageWidth,
waterfallImgRight,
waterfallImgBottom,
waterfallColHeight,
waterfallImgCol,
colLeft
} = this;
//找出当前最短列的索引
let minIndex = waterfallColHeight.indexOf(Math.min.apply(null, waterfallColHeight));
//获取最短列底部高度,既下一张图片的顶部高度
imgData.top = waterfallColHeight[minIndex];
//计算左侧偏移,最短列索引*(右边距+列宽度)
imgData.left = minIndex * (waterfallImgRight + imageWidth) + colLeft;
//改变当前列高度
waterfallColHeight[minIndex] += imgData.height + waterfallImgBottom;
// console.log(imgData.key + ":" + JSON.stringify(imgData));
// console.log(waterfallColHeight);
},
//打开图片详情
openDialog(picId){
this.picId = picId;
this.dialogVisible = true;
// this.$refs.detailWin.getInfo();
},
opmethod(){
//打开详情页的回调,延迟加载详情页的数据,避免子组件的方法没找到
setTimeout(() => {
this.$refs.detailWin.getInfo();
}, 10);
},
closedialog(){
//关闭弹窗
this.dialogVisible = false;
}
},
computed: {
disabled() {
return this.noMore;
}
}
};
公共搜索头部和图片详情弹窗可以都删掉
执行顺序 :
created 加载数据,
mounted 根据浏览器宽度计算好瀑布流的列数,左右间距
imgPreloading()拿到后端返回的数据,根据图片宽和高设置好占位色卡提前加载,等待图片onload完成赋值真实src