使用 vant 实现移动端上拉加载和下拉刷新功能

上拉加载

文档指明List组件是瀑布流滚动加载,用于展示长列表。当列表即将滚动到底部时,会触发事件并加载更多列表项

实际使用时,List组件能做的就是触发加载事件,加载更多列表项对应的代码还需要开发者编写。

html 复制代码
<van-list 
    v-model="loading" 
    :finished="finished" 
    finished-text="没有更多了" 
    :error.sync="error"
    error-text="请求失败,点击重新加载"
    @load="onLoad" > 
        <van-cell v-for="item in list" :key="item" :title="item" /> 
</van-list>

基础用法(引用自文档):

List 组件通过 loadingfinished 两个变量控制加载状态,当组件滚动到底部时,会触发 load 事件并将 loading 设置成 true。此时可以发起异步操作并更新数据,数据更新完毕后,将 loading 设置成 false 即可。若数据已全部加载完毕,则直接将 finished 设置成 true 即可。

我的理解:

List 组件通过 loading 和 finished 两个变量控制加载状态。

loading变量代表刷新状态,值为true时表示加载中,值为false时表示加载结束。

finished变量代表另一个状态:数据是否加载完毕。数据库中的数据总有穷尽,finished值为true时表示已经加载到最后一条,没有更多;值为false表示依旧能够加载新的数据。

代码示例

js 复制代码
import { getList } from "@/api/demo"
export default {
    data() {
        list: [],
        loading: false,
        error: false,
        finished: false,
        pageNum: 0, // 初始请求第一页
        pageSize: 5
    }
    methods: {
        // 当组件滚动到底部时,会触发 `load` 事件
        // 并将 `loading` 设置成 `true`。此时可以发起异步操作并更新数据
        async onLoad() {
            // 加1,表示加载下一页
            this.pageNum++; // 初始请求第一页
            
            try {
                // 发送 ajax 请求获取后端数据
                const { rows, total } = await getList({
                    pageNum: this.pageNum,
                    pageSize: this.pageSize
                });
            } catch() {
                this.error: true,
                this.pageNum--; 
            }
            
            // 返回的数据格式为:该格式来源于`mybatis`的轻量级分页插件pageHelper
            // {
            //    rows: [], // 所请求的数据列表
            //    total: 10, // 数据总条数
            // }
            
            // 将新数据添加在已展示数据的后面
            this.list = [...this.list, ...rows]
            
            // 加载状态结束 
            this.loading = false; 
            
            // 判断是否达到终点
            if(this.list.length == total) {
                this.finished = true;
            }
        }
    }
}

下面是文档给出的示例代码,经过对比可以发现,主要需要编写的就是加载更多列表项对应的代码:

js 复制代码
export default { 
    data() { 
        return { 
            list: [], 
            loading: false, 
            finished: false, 
        }; 
    }, 
    methods: { 
        onLoad() { 
            // 异步更新数据
            // setTimeout 仅做示例,真实场景中一般为 ajax 请求 
            setTimeout(() => { 
              for (let i = 0; i < 10; i++) { 
                this.list.push(this.list.length + 1); 
              } 
              
              // 加载状态结束 
              this.loading = false; 
                
              // 数据全部加载完成 
              if (this.list.length >= 40) { 
                  this.finished = true; 
              } 
            }, 1000); 
        }, 
     }, 
};

关于List组件的更多信息,可参考文档:Vant 2 - List组件

下拉刷新

PullRefresh组件用于提供下拉刷新的交互操作。

基础用法(引用自文档):

下拉刷新时会触发 refresh 事件,在事件的回调函数中可以进行同步或异步操作,操作完成后将 v-model 设置为 false,表示加载完成。

我的理解

通过下拉这个操作,告知系统需要重新加载数据,此时会触发refresh 事件,在此事件中需要将相关变量重置为初始状态然后发出Ajax请求。

List 组件可以与 PullRefresh 组件结合使用,实现下拉刷新的效果。

代码示例

html 复制代码
<van-pull-refresh v-model="refreshing" @refresh="onRefresh"> 
    <van-list 
        v-model="loading" 
        :finished="finished" 
        finished-text="没有更多了" 
        :error.sync="error"
        error-text="请求失败,点击重新加载"
        @load="onLoad" > 
            <van-cell v-for="item in list" :key="item" :title="item" /> 
    </van-list>
</van-pull-refresh>
js 复制代码
import { getList } from "@/api/demo"
export default {
    data() {
        list: [],
        loading: false,
        error: false,
        finished: false,
        pageNum: 0, // 初始请求第一页
        pageSize: 5,
        refreshing: false,
    }
    methods: {
        onRefresh() { 
            // 清空列表数据
            this.finished = false; 
            
            // 重新加载数据
            // 将 loading 设置为 true,表示处于加载状态 
            this.loading = true; 
            this.onLoad(); // 手动执行onLoad()
        },
        // 当组件滚动到底部时,会触发 `load` 事件
        // 并将 `loading` 设置成 `true`。此时可以发起异步操作并更新数据
        async onLoad() {
            if (this.refreshing) { 
                this.pageNum = 0;
                this.list = []; 
                this.refreshing = false; 
            }
            
            // 加1,表示加载下一页
            this.pageNum++; // 初始请求第一页
            
            try {
                // 发送 ajax 请求获取后端数据
                const { rows, total } = await getList({
                    pageNum: this.pageNum,
                    pageSize: this.pageSize
                });
            } catch() {
                this.error: true,
                this.pageNum--; 
            }
            
            // 返回的数据格式为:该格式来源于`mybatis`的轻量级分页插件pageHelper
            // {
            //    rows: [], // 所请求的数据列表
            //    total: 10, // 数据总条数
            // }
            
            // 将新数据添加在已展示数据的后面
            this.list = [...this.list, ...rows]
            
            // 加载状态结束 
            this.loading = false; 
            
            // 判断是否达到终点
            if(this.list.length == total) {
                this.finished = true;
            }
        }
    }
}

多tab场景

比如任务列表,分为已完成、未完成,此时点击tab需要进行列表的切换。

官方示例:

html 复制代码
<van-tabs v-model="active"> 
    <van-tab title="标签 1">内容 1</van-tab>
    <van-tab title="标签 2">内容 2</van-tab> 
    <van-tab title="标签 3">内容 3</van-tab> 
    <van-tab title="标签 4">内容 4</van-tab> 
</van-tabs>

为了只维护一组以list数组核心的相关变量,列表不能放在 van-tab 标签内部。

代码示例

html 复制代码
<van-tabs v-model="active" @change="onChange"> 
    <van-tab title="未完成" :name="1"></van-tab>
    <van-tab title="已完成" :name="2"></van-tab> 
</van-tabs>


<van-pull-refresh v-model="refreshing" @refresh="onRefresh"> 
    <van-list 
        v-model="loading" 
        :finished="finished" 
        finished-text="没有更多了" 
        :error.sync="error"
        error-text="请求失败,点击重新加载"
        @load="onLoad" > 
            <!-- 如果已完成、未完成的列表项有不同的UI(一般都不一样) , -->
            <!-- 可依据 this.active 使用 v-if 进行条件渲染  -->
            
            <!-- 未完成列表 -->
            <div v-if="active == 1 ">
                <van-cell  v-for="item in list" :key="item" :title="item" /> 
            </div>
            
            <!-- 已完成列表 -->
            <div v-if="active == 2 ">
                <van-cell  v-for="item in list" :key="item" :title="item" /> 
            </div>
    </van-list>
</van-pull-refresh>
js 复制代码
import { getYwcList, getWwcList } from "@/api/demo"
export default {
    data() {
        active: 1,
        list: [],
        loading: false,
        error: false,
        finished: false,
        pageNum: 0, // 初始请求第一页
        pageSize: 5,
        refreshing: false,
    }
    methods: {
        onChange() {
            // 标签切换时,需要清空列表数据后重新加载数据
            this.finished = false; 
            this.pageNum = 0;
            this.list = [];
            // 将 loading 设置为 true,表示处于加载状态 
            this.loading = true; 
            // 手动执行onLoad()
            this.onLoad(); 
        },
        onRefresh() { 
            // 清空列表数据后
            this.finished = false; 

            // 重新加载数据
            // 将 loading 设置为 true,表示处于加载状态 
            this.loading = true; 
            this.onLoad(); // 手动执行onLoad()
        },
        // 当组件滚动到底部时,会触发 `load` 事件
        // 并将 `loading` 设置成 `true`。此时可以发起异步操作并更新数据
        async onLoad() {
            if (this.refreshing) { 
                this.pageNum = 0;
                this.list = []; 
                this.refreshing = false; 
            }
        
            // 加1,表示加载下一页
            this.pageNum++; // 初始请求第一页
            
            try {
                switch (this.active) {
                    case: 1:
                        // 发送 ajax 请求获取后端数据
                        const { rows, total } = await getWwcList({
                            pageNum: this.pageNum,
                            pageSize: this.pageSize
                        });
                        break;
                   case: 2:
                        // 发送 ajax 请求获取后端数据
                        const { rows, total } = await getYwcList({
                            pageNum: this.pageNum,
                            pageSize: this.pageSize
                        });
                        break;                
                }
          
            } catch() {
                this.error: true,
                this.pageNum--; 
            }
            
            // 返回的数据格式为:该格式来源于`mybatis`的轻量级分页插件pageHelper
            // {
            //    rows: [], // 所请求的数据列表
            //    total: 10, // 数据总条数
            // }
            
            // 将新数据添加在已展示数据的后面
            this.list = [...this.list, ...rows]
            
            // 加载状态结束 
            this.loading = false;
            
            // 判断是否达到终点
            if(this.list.length == total) {
                this.finished = true;
            }
        }
    }
}

留言

若有错误之处,请评论区批评指正,感谢。

相关推荐
酷酷的阿云6 分钟前
不用ECharts!从0到1徒手撸一个Vue3柱状图
前端·javascript·vue.js
微信:137971205878 分钟前
web端手机录音
前端
齐 飞14 分钟前
MongoDB笔记01-概念与安装
前端·数据库·笔记·后端·mongodb
神仙别闹31 分钟前
基于tensorflow和flask的本地图片库web图片搜索引擎
前端·flask·tensorflow
GIS程序媛—椰子1 小时前
【Vue 全家桶】7、Vue UI组件库(更新中)
前端·vue.js
DogEgg_0011 小时前
前端八股文(一)HTML 持续更新中。。。
前端·html
ZL不懂前端2 小时前
Content Security Policy (CSP)
前端·javascript·面试
木舟10092 小时前
ffmpeg重复回听音频流,时长叠加问题
前端
王大锤43912 小时前
golang通用后台管理系统07(后台与若依前端对接)
开发语言·前端·golang
我血条子呢2 小时前
[Vue]防止路由重复跳转
前端·javascript·vue.js