vant list refresh 二次封装
组件:
<template> <div> <van-pull-refresh v-model="refreshing" @refresh="onRefresh" :disabled="disabled" :style="fullScreen? 'min-height: 100vh;': ''"> <van-list v-model="loading" :finished="finished" :finished-text="finishedText" error-text="请求失败,点击重新加载" @load="onLoad" :immediate-check="immeCheck" > <slot></slot> <div v-if="noData" class="no-data-cont" :class="noDataClass"> <!-- 暂无数据图片展示 --> <img :src="noDateIcon" alt=""> <p>{{searchInput ? '没有查询到任何内容':'- 暂无数据 -'}}</p> </div> <div slot="finished" class="finished-data"> <p v-if="!noData">{{ finishedText }}</p> </div> </van-list> </van-pull-refresh> </div> </template> <script> export default { props: { immeCheck: { type: Boolean, default: false }, searchInput: { type: String, default: '' }, fullScreen: { // 是否需要让下拉区域始终为全屏 type:Boolean, default: false }, disabled: { type: Boolean, default: false }, noDataClass: { type: String, default: '' }, finishedText: { type: String, default: '没有更多了' } }, data () { return { refreshing: false, loading: false, finished: false, noData: false, noDateIcon: require('@/assets/common/page-empty.png'), len: 0, total: 0 } }, methods: { // 刷新加载完成 onRefreshSuc () { this.refreshing = false this.finished = false }, onRefresh () { setTimeout(() => { this.$emit('onRefreshList') }, 500) }, // true false 是否全部加载完成 // onLoadSuc (isOver) { // this.loading = false // this.finished = isOver // }, // len 已加载数据 total 总数据 onLoadSuc(len, total) { this.loading = false this.len = len this.total = Number(total) if (Number(total) > 0) { this.noData = false if (len < Number(total)) { this.finished = false } else { this.finished = true } } else { this.finished = true this.noData = true } }, onLoad () { setTimeout(() => { if (this.len < this.total) { this.$emit('onLoadMore') } else { this.finished = true } }, 500) } } } </script> <style lang="scss" scoped> /deep/ .van-pull-refresh { // overflow: visible!important; } .data-none { font-size: .2rem; color: #888888; line-height: .4rem; } .finished-data { p:nth-child(2) { text-align: center; color: #969799; font-size: .28rem; } } .no-data-cont { // height: 4rem; min-height: 4rem; width: 100%; padding-top: 0.3rem; text-align: center; img { // display: block; // margin: 0 auto; display: inline-block; height: 3rem; width: 3rem; } p { text-align: center; color: #969799; font-size: .28rem; } } .no-h-data-cont { height: auto; img { display: block; margin: 0 auto; height: auto; width: auto; } } </style>
使用:
<template> <div> <div class="panel-title"> <div class="left-avatar"> <img :src="userInfo.avatar || defaultAvatar" alt="" /> <span v-if="userInfo.gender == 1" class="gender-icon"> <svg-icon icon-class="nan"></svg-icon> </span> <span v-if="userInfo.gender == 2" class="gender-icon"> <svg-icon icon-class="ru"></svg-icon> </span> </div> <div class="left-info"> <div class="nickname"> <span>{{ userInfo.title || '-' }}</span> </div> <div class="info"> <span>{{ userInfo.age || '-' }}岁</span> <span></span> <span>{{ userInfo.phone || '-' }}</span> </div> </div> </div> <LoadMore class="loadMore" key="ehbList" @onRefreshList="onRefreshList" @onLoadMore="onLoadMore" ref="loadMoreCont" > <div class="userItem" v-for="(item, index) in list" :key="index"> <div class="item-top"> <van-image class="item-top-left-avatar" round :src="item.customerHeadImg || defaultAvatar" /> <p class="item-top-left-name">{{ item.customerName }}</p> </div> <div class="item-bottom"> <div class="item-bottom-content"> <span class="label">添加时间</span> <span class="value">2023-10-19 17:37:45</span> </div> <div class="item-bottom-content"> <span class="label">所属部门</span> <span class="value">产品部、技术部、测试部共3个部门</span> </div> </div> </div> </LoadMore> </div> </template> <script> import LoadMore from '@/components/loadMore/index' export default { name: 'friends', components: { LoadMore }, data() { return { userInfo: {}, defaultAvatar: require('@/assets/qwGuide/headportrait.png'), pageNum: 1, pageSize: 10, list: [ { customerName: '张三' }, { customerName: '张三' }, { customerName: '张三' }, { customerName: '张三' }, { customerName: '张三' }, { customerName: '张三' } ] } }, created() { // this.getList() }, methods: { getList() { const params = { pageNum: this.pageNum, pageSize: this.pageSize } this.$toast.loading({ message: '加载中...', forbidClick: true, duration: 0 }) // receiveRecordPageList(params).then(res => { // this.$toast.clear() // if (this.$refs.loadMoreCont) this.$refs.loadMoreCont.onRefreshSuc() // if (this.pageNum == 1) { // this.list = res.data.list || [] // } else { // this.list = this.list.concat(res.data.list || []) // } // if (this.$refs.loadMoreCont) this.$refs.loadMoreCont.onLoadSuc(this.list.length, res.data.total) // }).catch(() => { // this.$toast.clear() // }) }, onRefreshList() { this.pageNum = 1 this.getList() }, onLoadMore() { this.pageNum++ this.getList() } } } </script> <style lang="scss" scoped> .panel-title { background: #ffffff; border-radius: 0px 0px 0.08rem 0.08rem; padding: 0.48rem 0.32rem 0.32rem; display: flex; align-items: center; .left-avatar { position: relative; width: 0.88rem; height: 0.88rem; margin-right: 0.16rem; img { width: 100%; height: 100%; border-radius: 50%; } .gender-icon { position: absolute; display: block; width: 0.28rem; height: 0.28rem; line-height: 0.28rem; bottom: 0; right: 0; border-radius: 50%; // background: #165DFF; } .boy-class { background: #165dff; border-radius: 50%; } .girl-class { background: #f77234; } } .left-info { height: 0.88rem; .nickname { display: flex; align-items: center; span { max-width: 2.56rem; font-size: 0.32rem; font-weight: 700; white-space: nowrap; text-overflow: ellipsis; overflow: hidden; } /deep/ .van-rate__item:not(:last-child) { padding-right: 0.04rem; } } .info { display: flex; align-items: center; font-size: 0.24rem; margin-top: 0.08rem; color: #c9cdd4; span:nth-child(2) { width: 1px; height: 0.24rem; background-color: #86909c; margin: 0 0.16rem; } } } } .loadMore { height: calc(100vh - 1.68rem); overflow: hidden; /deep/ { .van-pull-refresh { height: calc(100vh - 1.68rem)!important; overflow: auto; } } } .userItem { padding: 0.32rem; margin: 0.24rem; display: flex; flex-direction: column; background: #ffffff; border-radius: 0.08rem; position: relative; .item-top { display: flex; align-items: center; gap: 0.16rem; margin-bottom: 0.24rem; .item-top-left-avatar { width: 0.64rem; height: 0.64rem; flex-shrink: 0; } .item-top-left-name { font-size: 0.32rem; line-height: 0.44rem; color: #1d2129; font-weight: 500; } } .item-bottom { display: flex; flex-direction: column; gap: 0.16rem; line-height: 0.32rem; font-size: 0.28rem; .item-bottom-content { display: flex; word-break: break-all; gap: 0.16rem; } .label { color: #86909c; width: 1.68rem; flex-shrink: 0; } .value { color: #4e5969; } } } </style>