vant van-pull-refresh + van-list实现list列表支持搜索和下拉刷新
1 介绍
在使用 van-pull-refresh + van-list实现list列表下拉刷新时遇到几个问题在这里进行一个总结。
2 出现的问题
问题一:当van-pull-refresh + van-list组合使用时,下拉刷新会调用两个加载图标。
解答:去除van-pull-refresh加载图标,防止下拉刷新时出现两个加载图标
<!-- 去除加载图标,防止下拉刷新时出现两个加载图标 -->
<template #loading>
<div></div>
</template>
问题二: 通过筛选条件查询数据时,van-list会请求多次接口
解答:因为当this.finished = false时, 会触发 onLoad 事件,onLoad方法会调用一次fetchData方法,onRefresh方法也会调用fetchData方法这就使得你会调用两次接口。所以我们只好把查询单独写一个方法onSearch,然后在onLoad中判断是不是刷新操作,如果说是刷新就设置为false,只调用onload方法。
onSearch() {
this.medicalList = []
this.pageIndex = 1
this.finished = false
this.loading = true
this.refreshing = false
this.fetchData()
},
onLoad() {
if (this.refreshing) {
this.medicalList = []
this.refreshing = false
}
// 触底加载下一页数据
// 网页刚打开也会触发一次
this.fetchData()
},
// 下拉刷新
onRefresh() {
this.medicalList = []
this.pageIndex = 1
// finished 设置为 false 则会触发 onLoad 事件
this.finished = false
this.loading = true
this.fetchData()
},
3 结果展示
这个页面叫做TreatmentStation分为两部分:顶部的搜索和中间的内容。中间的内容是一个单独的组件(MedicalList),是TreatmentStation的子组件,父组件通过传值的方式将查询条件传给子组件,子组件调用接口获取数据,渲染至页面。
4 代码实现
TreatmentStation 组件
<template>
<div id="treatment">
<!-- 筛选条件 -->
<div class="filter-criteria">
<van-search
v-model="model.keyword"
placeholder="请输入患者姓名/就诊号"
show-action
@search="onSearch"
>
<template #action>
<div style="display: flex; align-items: center;justify-content: center">
<van-button size="small" type="info" @click="onSearch">搜索</van-button>
</div>
</template>
</van-search>
<van-dropdown-menu active-color="#1989fa">
<van-dropdown-item ref="dateItem" v-model="model.appointTime" :title="model.appointTime.toString()">
<van-datetime-picker
v-model="currentDate"
title="选择日期"
type="date"
@cancel="onCancelDate"
@confirm="onConfirmDate"
/>
</van-dropdown-item>
<van-dropdown-item v-model="model.departmentName" :options="model.deptOption" @change="changeDropdown"/>
<van-dropdown-item v-model="model.my" :options="model.myOption" @change="changeDropdown"/>
</van-dropdown-menu>
</div>
<back-top/>
<!-- list-->
<medical-list ref="medicalList" :model="model"/>
</div>
</template>
<script>
import moment from 'moment'
import MedicalList from './components/medical-list.vue'
import api from '../../api'
import BackTop from '../../components/back-top.vue'
export default {
name: 'TreatmentStation',
components: {BackTop, MedicalList},
data() {
return {
model: {
keyword: '',
my: true,
myOption: [
{text: '我的', value: true},
{text: '全部医师', value: false}
],
departmentName: '',
deptOption: [{text: '全部科室', value: ''}],
appointTime: ''
},
medicalList: [],
pageIndex: 1,
currentDate: new Date()
}
},
mounted() {
//
this.model.appointTime = moment().format('YYYY-MM-DD')
const sessionModel = JSON.parse(sessionStorage.getItem('sessionModel'))
if (sessionModel !== null) {
this.model = sessionModel
}
this.getDepartList()
},
methods: {
// 搜索确定
onSearch(val) {
this.$refs.medicalList.onSearch()
},
// 搜索框取消按钮
onCancel() {
// Toast('取消')
this.$refs.medicalList.onSearch()
},
onConfirmDate(value) {
this.model.appointTime = moment(value).format('YYYY-MM-DD')
this.$refs.dateItem.toggle()
this.$refs.medicalList.onSearch()
},
onCancelDate() {
// 收起
this.$refs.dateItem.toggle()
},
changeDropdown(value) {
this.$refs.medicalList.onSearch()
},
// 获取所有科室
getDepartList() {
api.getDepartment().then(res => {
this.model.deptOption = res.data.map(item => ({
text: item.name,
value: item.name
}))
this.model.deptOption.unshift({text: '全部科室', value: ''})
}).catch(error => {
console.log(error)
})
}
},
beforeRouteLeave(to, from, next) {
// 当路由跳转到治疗页面时存储sessionModel
if (to.name === 'treatmentContent') {
sessionStorage.setItem('sessionModel', JSON.stringify(this.model))
} else {
sessionStorage.removeItem('sessionModel')
}
next()
}
}
</script>
<style scoped>
#treatment {
height: 100%;
}
</style>
MedicalList组件
<template>
<div id="medical-list">
<van-pull-refresh
v-model="refreshing"
:class="{'content': activeClass}"
:offset="100"
success-text="刷新成功"
@refresh="onRefresh"
>
<!-- 去除加载图标,防止下拉刷新时出现两个加载图标 -->
<template #loading>
<div></div>
</template>
<van-list
v-model="loading"
:finished="finished"
finished-text="没有更多了"
@load="onLoad"
>
<van-cell v-for="item in medicalList" :key="item.id"
:to="{
name:'treatmentContent',
params:{
medicalInfo_Id: item.id,
appointTime: model.appointTime,
patientName: item.patientName,
patient_Id: item.patient_Id
}
}"
is-link
style="text-align: left; align-items: center"
>
<template #title>
<span style="margin-left: 10px">{{ item.patientName }}</span>
</template>
<template #label>
<span style="margin-left: 10px">{{ '就诊号: ' + item.medicalNo }}</span>
</template>
<template #default>
<span>{{ item.bedNumber ? '床号: ' + item.bedNumber : '' }}</span>
</template>
<template #icon>
<van-icon name="contact-o" size="25px"/>
</template>
</van-cell>
</van-list>
</van-pull-refresh>
</div>
</template>
<script>
import api from '../../../api'
export default {
name: 'MedicalList',
props: ['model'],
data() {
return {
medicalList: [],
loading: false,
finished: false,
refreshing: false,
pageIndex: 1,
pageSize: 50,
pullRefreshDisabled: false
}
},
methods: {
// list列表方法
onLoad() {
if (this.refreshing) {
this.medicalList = []
this.refreshing = false
}
// 触底加载下一页数据
// 网页刚打开也会触发一次
this.fetchData()
},
// 下拉刷新
onRefresh() {
this.medicalList = []
this.pageIndex = 1
// finished 设置为 false 则会触发 onLoad 事件
this.finished = false
this.loading = true
this.fetchData()
},
onSearch() {
this.medicalList = []
this.pageIndex = 1
this.finished = false
this.loading = true
this.refreshing = false
this.fetchData()
},
// 获取就诊信息数据
fetchData() {
api.query({
'page.index': this.pageIndex,
'page.size': this.pageSize,
My: this.model.my,
keyword: this.model.keyword,
appointTime: this.model.appointTime,
departmentName: this.model.departmentName
}).then(res => {
if (!res.data) return
this.medicalList = this.medicalList.concat(res.data.rows)
// 所有数据加载完成
if (this.medicalList.length >= res.data.total) {
this.finished = true
} else {
this.pageIndex++
}
}).catch(error => {
console.log(error)
this.finished = true
}).finally(() => {
this.refreshing = false
this.loading = false
})
},
bedNumber(value) {
return value ? '床号:' + value : ''
}
},
computed: {
activeClass() {
return this.medicalList.length <= 5
}
}
}
</script>
<style scoped>
#medical-list {
}
#medical-list .content {
height: 80vh;
}
</style>
back-top组件
悬浮回到顶部按钮
<template>
<!-- 回到顶部悬浮按钮-->
<div id="back-top">
<van-sticky>
<van-icon v-if="showBackTop" class="back-to-top" name="back-top" size="20px" @click="scrollToTop"/>
</van-sticky>
</div>
</template>
<script>
export default {
name: 'BackTop',
data() {
return {
showBackTop: false
}
},
beforeDestroy() {
window.removeEventListener('scroll', this.handleScroll)
},
mounted() {
window.addEventListener('scroll', this.handleScroll)
},
methods: {
handleScroll() {
this.showBackTop = window.pageYOffset >= 300
},
scrollToTop() {
window.scrollTo({top: 0, behavior: 'smooth'})
}
}
}
</script>
<style scoped>
#back-top .back-to-top {
position: fixed;
bottom: 50px;
right: 30px;
padding: 15px 15px;
background-color: whitesmoke;
color: black;
border-radius: 25px;
cursor: pointer;
z-index: 1000;
}
</style>