vue.js移动端app之上拉加载以及下拉刷新实战
作者:Runlin 发布时间:2024-05-09 10:40:22
上拉加载以及下拉刷新都是移动端很常见的功能,在搜索或者一些分类列表页面常常会用到。
跟横向滚动一样,我们还是采用better-scroll这个库来实现。由于better已经更新了新的版本,之前是0.几的版本,更新了一下发现,现在已经是1.2.6这个版本了,新版本多了些 比较好用的api,所以我也重写了之前的代码,用新的api来实现上拉加载以及下拉刷新。
首先把基本的样式写好,这里就略过了,然后引入better-scroll库
import BScroll from 'better-scroll'
其次,在mounted生命周期实例化scroll,可以获取完数据后再new,也可以先new后,获取完数据调用refresh。
实例时需要传入一个配置参数,由于参数比较多,具体的请参考文档,这里只讲2个重点的:
//是否开启下拉刷新,可传入true或者false,如果需要更多配置可以传入一个对象
pullDownRefresh:{
threshold:80,
stop:40
}
//是否开启上拉加载,同上,上拉无stop参数,这里需要注意是负数
pullUpLoad:{
threshold:-80,
}
/**
*
* @param threshold 触发事件的阀值,即滑动多少距离触发
* @param stop 下拉刷新后回滚距离顶部的距离(为了给loading留出一点空间)
*/
以上的数字个人感觉比较合适,但是这里有一个问题,由于我采用的是淘宝flexible.js来适配,这就导致:在安卓下80这个距离是合适的,但是到了iphone6s下,由于被缩放了3陪,所以现在80在iphone6s下就是27左右了。
所以,对于不同缩放程度的屏幕,还需要乘以对应的缩放比。
淘宝flexible.js里面其实已经有这个获取屏幕缩放比方法,这里直接从里面拿:
//在util.js里面加一个方法
export function getDeviceRatio(){
var isAndroid = window.navigator.appVersion.match(/android/gi);
var isIPhone = window.navigator.appVersion.match(/iphone/gi);
var devicePixelRatio = window.devicePixelRatio;
var dpr;
if (isIPhone) {
// iOS下,对于2和3的屏,用2倍的方案,其余的用1倍方案
if (devicePixelRatio >= 3) {
dpr = 3;
} else if (devicePixelRatio >= 2){
dpr = 2;
} else {
dpr = 1;
}
} else {
// 其他设备下,仍旧使用1倍的方案
dpr = 1;
}
return dpr
}
import{ DEVICE_RATIO} from '../base/js/api.js'
/*获取当前缩放比*/
const DEVICE_RATIO=getDeviceRatio();
/*下拉配置*/
const DOWN_CONFIG={
threshold:80*DEVICE_RATIO,
stop:40*DEVICE_RATIO
}
/*上拉配置*/
const UP_CONFIG={
threshold:-80*DEVICE_RATIO,
}
this.scroller = new BScroll(scrollWrap,{
click:true,
probeType:3,
pullDownRefresh:DOWN_CONFIG,
pullUpLoad:UP_CONFIG
});
实例化后,接下来就是监听上拉和下拉事件了。betterScroll新增了一些事件,主要的有:
/*下拉事件*/
this.scroller.on('pullingDown',()=> {});
/*上拉事件*/
this.scroller.on('pullingUp',()=>{});
触发上拉或者下拉事件后,需要我们调用 this.scroller.finishPullDown() 或者 this.scroller.finishPullUp() 来通知better-scroll事件完成。
大致的流程是这样的:
this.scroller.on('pullingDown',()=> {
<!-- 1. 发送请求获取数据 -->
<!-- 2. 获取成功后,通知事件完成 -->
<!-- 3. 修改data数据,在nextTick调用refresh -->
});
通常操作完成后都需要我们手动触发refresh方法来重新计算可滚动的距离,因此可以写一个watch监听数据的变化,这样我们只需要改变数据,不用每次操作数据后都调用refresh方法。
watch:{
dataList(){
this.$nextTick(()=>{
this.scroller.refresh();
})
}
},
如果你使用的版本还是旧的,那可以在on( scroll )事件的时候进行判断来实现功能
this.scroller.on("scroll",(pos)=>{
//获取整个滚动列表的高度
var height=getStyle(scroller,"height");
//获取滚动外层wrap的高度
var pageHeight=getStyle(scrollWrap,"height");
//触发事件需要的阀值
var distance=80*DEVICE_RATIO;
//参数pos为当前位置
if(pos.y>distance){
//console.log("下拉");
//do something
}else if(pos.y-pageHeight<-height-distance){
//console.log("上拉");
//do something
}
为了防止多次触发,需要加2个开关类的东西;
var onPullUp=true;
var onPullDown=true;
每次触发事件时,將对应的开关设置为false, 等操作完成后,再重新设置为true,否则多次下拉或者上拉就会触发多次事件。通过设置开关可以保证每次只有一个事件在进行。
最后,来封装成一个组件
<template>
<div ref="wrapper" class="list-wrapper">
<div class="scroll-content">
<slot></slot>
</div>
</div>
</template>
由于每个页面需要滚动的具体内容都是不一样的,所以用了一个插槽来分发。
组件需要的参数由父级传入,通过prop来接收并设置默认值
export default {
props: {
dataList:{
type: Array,
default: []
},
probeType: {
type: Number,
default: 3
},
click: {
type: Boolean,
default: true
},
pullDownRefresh: {
type: null,
default: false
},
pullUpLoad: {
type: null,
default: false
},
}
组件挂载后,在事件触发时并不直接处理事件,而是向父级发送一个事件,父级通过在模板v-on接收事件并处理后续的逻辑
mounted() {
this.scroll = new BScroll(this.$refs.wrapper, {
probeType: this.probeType,
click: this.click,
pullDownRefresh: this.pullDownRefresh,
pullUpLoad: this.pullUpLoad,
})
this.scroll.on('pullingUp',()=> {
if(this.continuePullUp){
this.beforePullUp();
this.$emit("onPullUp","当前状态:上拉加载");
}
});
this.scroll.on('pullingDown',()=> {
this.beforePullDown();
this.$emit("onPullDown","当前状态:下拉加载更多");
});
}
父组件在使用时,需要传入配置参数Props以及处理子组件发射的事件,并且用具体的内容并替换掉 slot 标签
<Scroller
id="scroll"
ref="scroll"
:dataList="filmList"
:pullDownRefresh="DOWN_CONFIG"
:pullUpLoad="UP_CONFIG"
@onPullUp="pullUpHandle"
@onPullDown="pullDownHandle"
>
<ul>
<router-link class="film-list" v-for="(v,i) in filmList" :key="v.id" tag="li" :to='{path:"/film-detail/"+v.id}'>
<div class="film-list__img">
<img v-lazy="v.images.small" alt="" />
</div>
<div class="film-list__detail">
<p class="film-list__detail__title">{{v.title}}</p>
<p class="film-list__detail__director">导演:{{filterDirectors(v.directors)}}</p>
<p class="film-list__detail__year">年份:{{v.year}}<span>{{v.stock}}</span></p>
<p class="film-list__detail__type">类别:{{v.genres.join(" / ")}}<span></span></p>
<p class="film-list__detail__rank">评分:<span>{{v.rating.average}}分</span></p>
</div>
</router-link>
</ul>
</Scroller>
父组件可以通过this.$refs.xxx来获取到子组件,可以调用子组件里面的方法;
computed:{
scrollElement(){
return this.$refs.scroll
}
}
完整的scroller组件内容如下
<template>
<div ref="wrapper" class="list-wrapper">
<div class="scroll-content">
<slot></slot>
<div>
<PullingWord v-show="!inPullUp&&dataList.length>0" :loadingWord="beforePullUpWord"></PullingWord>
<Loading v-show="inPullUp" :loadingWord='PullingUpWord'></Loading>
</div>
</div>
<transition name="pullDown">
<Loading class="pullDown" v-show="inPullDown" :loadingWord='PullingDownWord'></Loading>
</transition>
</div>
</template>
<script >
import BScroll from 'better-scroll'
import Loading from './loading.vue'
import PullingWord from './pulling-word'
const PullingUpWord="正在拼命加载中...";
const beforePullUpWord="上拉加载更多";
const finishPullUpWord="加载完成";
const PullingDownWord="加载中...";
export default {
props: {
dataList:{
type: Array,
default: []
},
probeType: {
type: Number,
default: 3
},
click: {
type: Boolean,
default: true
},
pullDownRefresh: {
type: null,
default: false
},
pullUpLoad: {
type: null,
default: false
},
},
data() {
return {
scroll:null,
inPullUp:false,
inPullDown:false,
beforePullUpWord,
PullingUpWord,
PullingDownWord,
continuePullUp:true
}
},
mounted() {
setTimeout(()=>{
this.initScroll();
this.scroll.on('pullingUp',()=> {
if(this.continuePullUp){
this.beforePullUp();
this.$emit("onPullUp","当前状态:上拉加载");
}
});
this.scroll.on('pullingDown',()=> {
this.beforePullDown();
this.$emit("onPullDown","当前状态:下拉加载更多");
});
},20)
},
methods: {
initScroll() {
if (!this.$refs.wrapper) {
return
}
this.scroll = new BScroll(this.$refs.wrapper, {
probeType: this.probeType,
click: this.click,
pullDownRefresh: this.pullDownRefresh,
pullUpLoad: this.pullUpLoad,
})
},
beforePullUp(){
this.PullingUpWord=PullingUpWord;
this.inPullUp=true;
},
beforePullDown(){
this.disable();
this.inPullDown=true;
},
finish(type){
this["finish"+type]();
this.enable();
this["in"+type]=false;
},
disable() {
this.scroll && this.scroll.disable()
},
enable() {
this.scroll && this.scroll.enable()
},
refresh() {
this.scroll && this.scroll.refresh()
},
finishPullDown(){
this.scroll&&this.scroll.finishPullDown()
},
finishPullUp(){
this.scroll&&this.scroll.finishPullUp()
},
},
watch: {
dataList() {
this.$nextTick(()=>{
this.refresh();
})
}
},
components: {
Loading,
PullingWord
}
}
</script>
具体内容可以查看github , 项目地址如下:https://github.com/linrunzheng/vueApp
来源:http://www.cnblogs.com/zhengrunlin/p/7503605.html?utm_source=tuicool&utm_medium=referral


猜你喜欢
- 为什么要用jsonpath就跟为什么要用xpath一样,jsonpath的设计灵感来源于xpath。一个强大的json数据提取工具。让用户不
- 在Python中,代码越少越好、越简单越好。基于这一思想,需要掌握Python中非常有用的高级特性,1行代码能实现的功能,决不写5行代码。代
- 简介mysql应该是我们在日常工作中使用到的一个非常普遍的数据库,虽然mysql现在是oracle公司的,但是它是开源的,市场占有率还是非常
- 一、图像缩略图的编辑图像的缩略图是指把图像按原比例缩小,可作为原图的预览,这在网络速度比较慢时可快速地显示图片的概图。当你的网页上有大型图片
- 原始两张图片:代码运行结果如下。5种算法值哈希算法、差值哈希算法和感知哈希算法都是值越小,相似度越高,取值为0-64,即汉明距离中,64位的
- 环境描述: 某公司装了一台SQL Server数据库,为了保证数据库能够在出现故障时及时的修复,管理员做了备份操作,比如说完整备份+差异备份
- selenium最初是一个自动化测试工具,而爬虫中使用它主要是为了解决requests无法直接执行JavaScript代码的问题,selen
- 1、环境搭建需安装:python3.6Pycharm专业版django 2.2.6mysqlclientpip install django
- CTE(Common Table Expressions)是从SQL Server 2005以后版本才有的。指定的临时命名结果集,这些结果集
- 前言最近写论文需要观察中间特征层的特征图,使用的是yolov5的代码仓库,但是苦于找不到很好的轮子,于是参考了很多,只找了这个,但是我觉得作
- python 使用get_argument获取url query参数ornado的每个请求处理程序,我们叫做handler,handler里
- JavaScript 中的并没有提供像 VBScript 里的 DateAdd 方法用于日
- 用6N±1法求素数 任何一个自然数,总可以表示成为如下的形式之一: 6N,6N+1,6N+2,6N+3,6N+4,6N+5 (N=0,1,2
- 1、安装依赖包yum -y install gcc-c++ ncurses-devel cmake make perl gcc autoco
- 问题:不同版本提交的城市文件夹数量固定,怎样确定本版本成果中缺少了哪些城市?背景:已有参照文件作为标准,利用取差集的方法#-*- codin
- 今天开始学习数据库,由于我对微软不怎么感冒,所以就不用他家的产品了本来想装ORACLE的,不过太大了,看着害怕对于我这种喜欢一切从简的人来说
- 用Python编写关于计算图形面积的代码实现,供大家参考,具体内容如下#寒假打卡28天第7天import mathclass Round()
- CAST、CONVERT都可以执行数据类型转换。在大部分情况下,两者执行同样的功能,不同的是CONVERT还提供一些特别的日期格式转换,而C
- 有这么一段代码,可以先看一下有没有什么问题,作用是输入一段json字符串,反序列化成map,然后将另一个inputMap的内容,merge进
- numpy多维数组的创建多维数组(矩阵ndarray)ndarray的基本属性shape维度的大小ndim维度的个数dtype数据类型1.1