使用 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;
            }
        }
    }
}

留言

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

相关推荐
博客zhu虎康几秒前
ElementUI 的 form 表单校验
前端·javascript·elementui
敲啊敲952729 分钟前
5.npm包
前端·npm·node.js
brrdg_sefg43 分钟前
Rust 在前端基建中的使用
前端·rust·状态模式
m0_748230941 小时前
Rust赋能前端: 纯血前端将 Table 导出 Excel
前端·rust·excel
qq_589568101 小时前
Echarts的高级使用,动画,交互api
前端·javascript·echarts
黑客老陈2 小时前
新手小白如何挖掘cnvd通用漏洞之存储xss漏洞(利用xss钓鱼)
运维·服务器·前端·网络·安全·web3·xss
正小安2 小时前
Vite系列课程 | 11. Vite 配置文件中 CSS 配置(Modules 模块化篇)
前端·vite
暴富的Tdy3 小时前
【CryptoJS库AES加密】
前端·javascript·vue.js
neeef_se3 小时前
Vue中使用a标签下载静态资源文件(比如excel、pdf等),纯前端操作
前端·vue.js·excel