vue实现网络图片瀑布流 + 下拉刷新 + 上拉加载更多
一、思路分析和效果图
用vue来实现一个瀑布流效果,加载网络图片,同时有下拉刷新和上拉加载更多功能效果。然后针对这几个效果的实现,捋下思路:
- 根据加载数据的顺序,依次追加标签展示效果;
- 选择哪种方式实现瀑布流,这里选择绝对定位方式;
- 关键问题:由于每张图片的宽高不一样,而瀑布流中要求所有图片的宽度一致,高度随宽度等比缩放。而且由于图片的加载是异步延迟。在不知道图片高度的情况下,每个图片所在的item盒子不好绝对定位。因此在渲染页面前先获取所有图片的高度,是解决问题的关键点!这里选择用JS中的Image类,通过预加载图片的方式提前获取图片宽高,另外通过一个临时变量来计算是否所有图片的高度已经得到。当所有的图片高度获取后,开始渲染页面。
- 页面渲染后,获取所有图片所在的盒子,循环计算盒子的高度,开始设置每个盒子item的绝对定位。
- 页面渲染时,会出现闪烁的现象。如何解决这个问题呢?这里用了一个动画样式。不过在第一次加载的时候,还是会有一点闪烁的感觉。
- 然后就是下拉刷新和上拉加载更多的效果,这里用了有赞的vant组件PullRefresh和List这套组合组件来实现。
先看个效果动图:
静态截图:
二、具体实现步骤
2.1、页面结构设计,测试数据准备。
本地准备一个json文件数据,放在项目public文件夹下。注意,本地测试数据必须放在public文件夹下,网络请求时才能请求到数据,这是vue3.x。新增加一个axios依赖包,用来进行网络请求。部分截图,及关键代码:
//数据请求
getDataList(){
this.$axios.get("/json/dataList.json").then((res)=>{ let list = res.data.data ? res.data.data: [];
if (list.length > 0){
//从list中取pageSize条数据出来
var tempList = [];
for (let i = 0; i < this.pageSize; i++){
if (list.length > 0){
let tempIndex = parseInt(Math.random() * 1000) % list.length;
tempList.push(list[tempIndex]);
list.splice(tempIndex, 1);
}
}
this.loadImagesHeight(tempList); //模拟预加载图片,获取图片高度
}
else {
this.loadImagesHeight(list);
}
}).catch((res)=>{
console.log("..fail: ", res);
this.$toast.clear();
this.isLoading = false; //下拉刷新请求完成
this.loading = false; //上拉加载更多请求完成
})
},
2.2、预加载图片,存储图片高度
获取数据后,遍历数据数组,预加载图片,计算图片缩放后的高度,存储起来。同时由于图片加载是异步加载,所以用变量计数,当最后一个图片加载完成后,开始渲染页面。
loadImagesHeight(list){
var count = 0; //用来计数,表示是否所有图片高度已经获取
list.forEach((item, index)=>{
//创建图片对象,加载图片,计算图片高度
var img = new Image();
img.src = item.cover;
img.onload = img.onerror = (e)=>{
count++;
if (e.type == 'load'){ //图片加载成功
//计算图片缩放后的高度:图片原高度/原宽度 = 缩放后高度/缩放后宽度
list[index].imgHeight = Math.round(img.height * this.boxWidth / img.width);
// console.log('index: ', index, ', load suc, imgHeiht: ', list[index].imgHeight);
}
else{ //图片加载失败,给一个默认高度50
list[index].imgHeight = 50;
console.log("index: ", index, ", 加载报错:", e);
} //加载完成最后一个图片高度,开始下一步数据处理
if (count == list.length){
this.resolveDataList(list);
}
}
})
},
2.3、渲染页面,设置绝对定位
所有图片通过预加载获取图片高度后,开始渲染页面。然后遍历所有图片所在盒子标签,获取盒子高度,设置每个盒子的绝对定位。
resolveDataList(list){ //处理数据
//下拉刷新,清空原数据
if (this.pageIndex <= 1){
this.itemCount = 0;
this.dataList = [];
this.lastRowHeights = [0, 0]; //存储每列的最后一行高度清0
} if (list.length >= this.pageSize){
this.pageIndex++; //还有下一页
}
else{
this.finished = true; //当前tab类型下所有数据已经加载完成
} //合并新老两个数组数据
this.dataList = [...this.dataList, ...list];
//判断页面是否有数据
this.haveData = this.dataList.length > 0 ? 2 : 1;
this.isLoading = false; //下拉刷新请求完成
this.loading = false; //上拉加载更多请求完成 console.log("...datalist: ", this.dataList);
console.log("...this.isLoading: ", this.isLoading) this.$nextTick(()=>{
setTimeout(()=>{
//渲染完成,计算每个item宽高,设置标签坐标定位
this.setItemElementPosition();
this.isLoading = false; //下拉刷新请求完成
this.loading = false; //上拉加载更多请求完成
}, 1000)
});
},
//获取每个item标签高度,设置item的定位
setItemElementPosition(){
let parentEle = document.getElementById('data-list-box');
let boxEles = parentEle.getElementsByClassName("data-item"); for (let i = this.itemCount; i < boxEles.length; i++){
let tempEle = boxEles[i];
//上一个标签最小高度的列索引
let curColIndex = this.getMinHeightIndex(this.lastRowHeights);
let boxTop = this.lastRowHeights[curColIndex] + this.boxMargin;
let boxLeft = curColIndex * (this.boxWidth + this.boxMargin) + this.boxMargin;
tempEle.style.left = boxLeft + 'px';
tempEle.style.top = boxTop + 'px';
this.lastRowHeights[curColIndex] = boxTop + tempEle.offsetHeight; // console.log('i = ', i, ', boxTop: ', boxTop, ', eleHeight: ', tempEle.offsetHeight);
} this.itemCount = boxEles.length; //修改父级标签的高度
let maxHeight = Math.max.apply(null, this.lastRowHeights);
parentEle.style.height = maxHeight + 'px'; this.$toast.clear();
console.log("...boxEles: ", boxEles.length, ", maxH: ", maxHeight);
},
2.4、其他说明
其他页面中如下拉刷新,和上拉加载更多等功能,使用了有赞的组件库中的PullRefresh 和 List这一套组合组件。感觉效果挺棒的,使用步骤也简单。另外就是在页面渲染时,会出现页面闪烁的现象,后面使用了一个css动画处理了这个现象,效果好了很多。但是在第一次加载的时候,还是有轻微的闪烁现象。等后面找到更好的方法,再更新。
完整效果DEMO地址:https://github.com/xiaotanit/tan_vue/blob/master/src/views/PageWaterFall.vue
vue实现网络图片瀑布流 + 下拉刷新 + 上拉加载更多的更多相关文章
- SwipeRefreshLayout实现下拉刷新上滑加载
1. 效果图 2.RefreshLayout.java package myapplication.com.myapplication; import android.content.Context; ...
- Android 下拉刷新上啦加载SmartRefreshLayout + RecyclerView
在弄android刷新的时候,可算是耗费了一番功夫,最后发觉有现成的控件,并且非常好用,这里记录一下. 原文是 https://blog.csdn.net/huangxin112/article/de ...
- juery下拉刷新,div加载更多元素并添加点击事件(二)
buffer.append("<div class='col-xs-3 "+companyId+"' style='padding-left: 10px; padd ...
- 移动端下拉刷新上拉加载-mescroll.js插件
最近无意间看到有这么一个上拉刷新下拉加载的插件 -- mescroll.js,个人感觉挺好用的,官网地址是:http://www.mescroll.com 然后我就看了一下文档,简单的写了一个小dem ...
- Android如何定制一个下拉刷新,上滑加载更多的容器
前言 下拉刷新和上滑加载更多,是一种比较常用的列表数据交互方式. android提供了原生的下拉刷新容器 SwipeRefreshLayout,可惜样式不能定制. 于是打算自己实现一个专用的.但是下拉 ...
- Android 自定义 ListView 上下拉动“刷新最新”和“加载更多”歌曲列表
本文内容 环境 测试数据 项目结构 演示 参考资料 本文演示,上拉刷新最新的歌曲列表,和下拉加载更多的歌曲列表.所谓"刷新最新"和"加载更多"是指日期.演示代码 ...
- vue mint-ui 框架下拉刷新上拉加载组件的使用
安装 npm i mint-ui -S 然后在main.js中引入 import MintUI from 'mint-ui' import 'mint-ui/lib/style.css' Vue.us ...
- Android 下拉刷新上拉载入 多种应用场景 超级大放送(上)
转载请标明原文地址:http://blog.csdn.net/yalinfendou/article/details/47707017 关于Android下拉刷新上拉载入,网上的Demo太多太多了,这 ...
- mui下拉刷新上拉加载
新外卖商家端主页订单大厅页面 使用mui双webview,实现下拉刷新上拉加载 主页面: order_index.html <!doctype html> <html> < ...
随机推荐
- java三大循环结构
用于处理需要重复执行的操作: 根据判断条件的成立与否,决定程序段落的执行次数,而这个程序段落我们称为循环体: while:事先不需要知道循环执行多少次: do while:同上,只是至少要执行一次( ...
- 教你怎么让vi和vim显示行数
首先我们来看看没有行号是多么难看. 2 再来看看有行号后的效果. 3 设置行号很简单. 我们要到命令模式下,输入set number :set number 按下回车 来看看效果 4 那么怎么关闭行号 ...
- [转]Spring历史版本变迁和如今的生态帝国
前两篇: 为什么要有Spring? 为什么要有Spring AOP? 前两篇从Web开发史的角度介绍了我们在开发的时候遇到的一个个坑,然后一步步衍生出Spring Ioc和Spring AOP的概念雏 ...
- Python--day47--mysql索引类型介绍
组合索引(联合索引)详讲:组合索引相对索引合并的缺点是 覆盖索引和索引合并不是真实的索引,只是名词: 命中索引,要避免使用哪些:id.nid是主键 email,num()是索引 1,避免使用like ...
- 整理了一下react16.7.0的webpack模板
基本上react需要方法和依赖的库都引配好了.github地址:https://github.com/qianxiaoning/demo-react16.7.0 欢迎大家star或者fork呀~ te ...
- 【React】react项目引入echarts插件 K线图
参考npm文档:https://www.npmjs.com/package/echarts-for-react 由于npm上已经有针对react项目出的echarts插件,所以在这里直接安装 第一步: ...
- Java 9版本之后Base64Encoder和Base64Decoder无法继续使用解决办法
在项目开发过程中,因为重装系统,安装了Java10版本,发现sun.misc.Base64Encoder和sun.misc.Base64Decoder无法使用. 原因: 查看官网发现,JDK中的/li ...
- tensorflow在文本处理中的使用——词袋
代码来源于:tensorflow机器学习实战指南(曾益强 译,2017年9月)——第七章:自然语言处理 代码地址:https://github.com/nfmcclure/tensorflow-coo ...
- visual studio 2010问题修复
我在重新安装 Visual Studio 2010 和 SQL sever 2012 的时候,安装好的两个软件打开时都遇到了这个问题:“在此计算机中仅有部分 Microsoft Visual Stud ...
- 网摘-获取屏幕dc并且将其画面显示在窗体中
获取屏幕dc并且将其画面显示在窗体中 HWND hWnd = ::GetDesktopWindow();//获得屏幕的HWND. HDC hScreenDC = ::GetDC(hWnd); // ...