一、思路分析和效果图

  用vue来实现一个瀑布流效果,加载网络图片,同时有下拉刷新和上拉加载更多功能效果。然后针对这几个效果的实现,捋下思路:

  1. 根据加载数据的顺序,依次追加标签展示效果;
  2. 选择哪种方式实现瀑布流,这里选择绝对定位方式;
  3. 关键问题:由于每张图片的宽高不一样,而瀑布流中要求所有图片的宽度一致,高度随宽度等比缩放。而且由于图片的加载是异步延迟。在不知道图片高度的情况下,每个图片所在的item盒子不好绝对定位。因此在渲染页面前先获取所有图片的高度,是解决问题的关键点!这里选择用JS中的Image类,通过预加载图片的方式提前获取图片宽高,另外通过一个临时变量来计算是否所有图片的高度已经得到。当所有的图片高度获取后,开始渲染页面。
  4. 页面渲染后,获取所有图片所在的盒子,循环计算盒子的高度,开始设置每个盒子item的绝对定位。
  5. 页面渲染时,会出现闪烁的现象。如何解决这个问题呢?这里用了一个动画样式。不过在第一次加载的时候,还是会有一点闪烁的感觉。
  6. 然后就是下拉刷新和上拉加载更多的效果,这里用了有赞的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实现网络图片瀑布流 + 下拉刷新 + 上拉加载更多的更多相关文章

  1. SwipeRefreshLayout实现下拉刷新上滑加载

    1. 效果图 2.RefreshLayout.java package myapplication.com.myapplication; import android.content.Context; ...

  2. Android 下拉刷新上啦加载SmartRefreshLayout + RecyclerView

    在弄android刷新的时候,可算是耗费了一番功夫,最后发觉有现成的控件,并且非常好用,这里记录一下. 原文是 https://blog.csdn.net/huangxin112/article/de ...

  3. juery下拉刷新,div加载更多元素并添加点击事件(二)

    buffer.append("<div class='col-xs-3 "+companyId+"' style='padding-left: 10px; padd ...

  4. 移动端下拉刷新上拉加载-mescroll.js插件

    最近无意间看到有这么一个上拉刷新下拉加载的插件 -- mescroll.js,个人感觉挺好用的,官网地址是:http://www.mescroll.com 然后我就看了一下文档,简单的写了一个小dem ...

  5. Android如何定制一个下拉刷新,上滑加载更多的容器

    前言 下拉刷新和上滑加载更多,是一种比较常用的列表数据交互方式. android提供了原生的下拉刷新容器 SwipeRefreshLayout,可惜样式不能定制. 于是打算自己实现一个专用的.但是下拉 ...

  6. Android 自定义 ListView 上下拉动“刷新最新”和“加载更多”歌曲列表

    本文内容 环境 测试数据 项目结构 演示 参考资料 本文演示,上拉刷新最新的歌曲列表,和下拉加载更多的歌曲列表.所谓"刷新最新"和"加载更多"是指日期.演示代码 ...

  7. vue mint-ui 框架下拉刷新上拉加载组件的使用

    安装 npm i mint-ui -S 然后在main.js中引入 import MintUI from 'mint-ui' import 'mint-ui/lib/style.css' Vue.us ...

  8. Android 下拉刷新上拉载入 多种应用场景 超级大放送(上)

    转载请标明原文地址:http://blog.csdn.net/yalinfendou/article/details/47707017 关于Android下拉刷新上拉载入,网上的Demo太多太多了,这 ...

  9. mui下拉刷新上拉加载

    新外卖商家端主页订单大厅页面 使用mui双webview,实现下拉刷新上拉加载 主页面: order_index.html <!doctype html> <html> < ...

随机推荐

  1. rsa加密(非对称加密)

    rsa加密 是非对称加密 需要公钥 与 私钥 这个公钥私钥的具体值需要与后端协商定下 rsa js代码如下 代码太多不插入了 html代码如下 <!DOCTYPE html> <ht ...

  2. H3C Basic NAT配置示例

  3. H3C 在接口上应用ACL

  4. php检测函数

    验证字符串是否为电子邮箱  var_dump(filter_var('bob@example.com', FILTER_VALIDATE_EMAIL));       //bob@example.co ...

  5. win10 uwp 使用 Azure DevOps 自动构建

    通过 Azure DevOps 可以做到自动构建程序,覆盖计划.创建.编程.测试.部署.发布.托管.共享等各个环节,适用于大多数的语言.平台. 本文继续使用图床为例告诉大家如何使用 Azure Dev ...

  6. Hamcrest匹配器框架

    其实在之前的文章中已经使用过 Hamcrest 匹配器框架,本篇文章将系统的介绍它的使用. 为什么要用Hamcrest匹配器框架 Hamcrest是一款软件测试框架, 可以通过现有的匹配器类检查代码中 ...

  7. Linux 内核 NuBus 总线

    另一个有趣的, 但是几乎被忘记的, 接口总线是 NuBus. 它被发现于老的 Mac 计算机(那 些有 M68K CPU 家族的). 所有的这个总线是内存映射的(象 M68K 的所有东西), 并且设备 ...

  8. 使用eclipse运行maven web项目 插件/非插件

    一.使用插件 tomcat 8.5 tomcat-users.xml中添加这一行就ok <user username="admin" password="admin ...

  9. 19.yield和send的区别

    转载:https://www.jianshu.com/p/ccb5e7da3fd8 https://www.cnblogs.com/xhcdream/p/8304953.html https://ww ...

  10. 聊聊多线程哪一些事儿(task)之 二 延续操作

    hello,又见面啦,昨天我们简单的介绍了如何去创建和运行一个task.如何实现task的同步执行.如何阻塞等待task集合的执行完毕等待,昨天讲的是task的最基本的知识点,如果你没有看昨天的博客, ...