vue实现网络图片瀑布流 + 下拉刷新 + 上拉加载更多(步骤详解)


Posted in Javascript onJanuary 14, 2020

一、思路分析和效果图

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

根据加载数据的顺序,依次追加标签展示效果;

选择哪种方式实现瀑布流,这里选择绝对定位方式;

关键问题:由于每张图片的宽高不一样,而瀑布流中要求所有图片的宽度一致,高度随宽度等比缩放。而且由于图片的加载是异步延迟。在不知道图片高度的情况下,每个图片所在的item盒子不好绝对定位。因此在渲染页面前先获取所有图片的高度,是解决问题的关键点!这里选择用JS中的Image类,通过预加载图片的方式提前获取图片宽高,另外通过一个临时变量来计算是否所有图片的高度已经得到。当所有的图片高度获取后,开始渲染页面。
页面渲染后,获取所有图片所在的盒子,循环计算盒子的高度,开始设置每个盒子item的绝对定位。
页面渲染时,会出现闪烁的现象。如何解决这个问题呢?这里用了一个动画样式。不过在第一次加载的时候,还是会有一点闪烁的感觉。
然后就是下拉刷新和上拉加载更多的效果,这里用了有赞的vant组件PullRefresh和List这套组合组件来实现。

先看个效果动图:

vue实现网络图片瀑布流 + 下拉刷新 + 上拉加载更多(步骤详解)

静态截图:

vue实现网络图片瀑布流 + 下拉刷新 + 上拉加载更多(步骤详解)

二、具体实现步骤

2.1、页面结构设计,测试数据准备。

 

本地准备一个json文件数据,放在项目public文件夹下。注意,本地测试数据必须放在public文件夹下,网络请求时才能请求到数据,这是vue3.x。新增加一个axios依赖包,用来进行网络请求。部分截图,及关键代码:

vue实现网络图片瀑布流 + 下拉刷新 + 上拉加载更多(步骤详解)

//数据请求
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实现网络图片瀑布流 + 下拉刷新 + 上拉加载更多(步骤详解),希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对三水点靠木网站的支持!
如果你觉得本文对你有帮助,欢迎转载,烦请注明出处,谢谢!

Javascript 相关文章推荐
return false;和e.preventDefault();的区别
Jul 11 Javascript
jquery中:input和input的区别分析
Jul 13 Javascript
ejs v9 javascript模板系统
Mar 21 Javascript
在js中判断checkboxlist(.net控件客户端id)是否有选中
Apr 11 Javascript
点击页面其它地方隐藏该div的两种思路
Nov 18 Javascript
Grunt入门教程(自动任务运行器)
Aug 06 Javascript
鼠标悬停小图标显示大图标
Jan 22 Javascript
微信小程序 生命周期详解
Oct 12 Javascript
js实现京东轮播图效果
Jun 30 Javascript
angular ng-model 无法获取值的处理方法
Oct 02 Javascript
vue的keep-alive用法技巧
Aug 15 Javascript
JavaScript页面加载事件实例讲解
Sep 01 Javascript
vue页面加载时的进度条功能(实例代码)
Jan 13 #Javascript
微信小程序canvas截取任意形状的实现代码
Jan 13 #Javascript
js实现列表向上无限滚动
Jan 13 #Javascript
vue 组件销毁并重置的实现
Jan 13 #Javascript
VUE实现自身整体组件销毁的示例代码
Jan 13 #Javascript
微信小程序聊天功能的示例代码
Jan 13 #Javascript
js实现适配移动端的拖动效果
Jan 13 #Javascript
You might like
在PHP3中实现SESSION的功能(二)
2006/10/09 PHP
PHP批量生成缩略图的代码
2008/07/19 PHP
PHP的openssl加密扩展使用小结(推荐)
2016/07/18 PHP
PNG背景在不同浏览器下的应用
2009/06/22 Javascript
IE iframe的onload方法分析小结
2010/01/07 Javascript
jQuery 通过事件委派一次绑定多种事件,以减少事件冗余
2010/06/30 Javascript
微博@符号的用户名提示效果。(想@到谁?)
2010/11/05 Javascript
Node.js 条形码识别程序构建思路详解
2016/02/14 Javascript
解析Node.js异常处理中domain模块的使用方法
2016/02/16 Javascript
JavaScript资源预加载组件和滑屏组件的使用推荐
2016/03/10 Javascript
纯JS实现可拖拽表单的简单实例
2016/09/02 Javascript
基于jQuery实现滚动刷新效果
2017/01/09 Javascript
Nodejs之TCP服务端与客户端聊天程序详解
2017/07/07 NodeJs
JS模拟超市简易收银台小程序代码解析
2017/08/18 Javascript
原生JS实现网页手机音乐播放器 歌词同步播放的示例
2018/02/02 Javascript
IE9 elementUI文件上传的问题解决
2018/10/17 Javascript
基于AngularJS拖拽插件ngDraggable.js实现拖拽排序功能
2019/04/02 Javascript
微信小程序实现拖拽功能
2019/09/26 Javascript
vue 实现用户登录方式的切换功能
2020/04/14 Javascript
javascript实现扫雷简易版
2020/08/18 Javascript
手动实现vue2.0的双向数据绑定原理详解
2021/02/06 Vue.js
Python使用PyGreSQL操作PostgreSQL数据库教程
2014/07/30 Python
Numpy中stack(),hstack(),vstack()函数用法介绍及实例
2018/01/09 Python
Django在admin后台集成TinyMCE富文本编辑器的例子
2019/08/09 Python
python实现布隆过滤器及原理解析
2019/12/08 Python
Python编程快速上手——strip()函数的正则表达式实现方法分析
2020/02/29 Python
python实现企业微信定时发送文本消息的实例代码
2020/11/25 Python
HTML5 MiranaVideo播放器 (代码开源)
2010/06/11 HTML / CSS
HTML5实现签到 功能
2018/10/09 HTML / CSS
日本网路线上商品代购服务:转送JAPAN
2016/08/05 全球购物
SQL Server面试题
2013/04/04 面试题
大学生简短的自我评价分享
2014/02/20 职场文书
专项法律服务方案
2014/06/11 职场文书
培训学校2015年度工作总结
2015/07/20 职场文书
MySQL系列之十二 备份与恢复
2021/07/02 MySQL
MySQL 服务和数据库管理
2021/11/11 MySQL