下拉刷新和上拉加载是提升用户体验的重要功能,它们让用户在浏览内容时更加直观和便捷。本文将使用Refresh组件、List组件分别实现下拉刷新和上拉加载效果。
Refresh组件 下拉刷新
Refresh组件:可以进行页面下拉操作并显示刷新动效的容器组件
Refresh(value: RefreshOptions){
子组件() // 只支持单个子组件
}
.refreshOffset(value: number) // 设置触发刷新的下拉偏移量
.pullToRefresh(value: boolean) // 设置是否能触发刷新
// 当前刷新状态变更时,触发回调
.onStateChange(callback: (state: RefreshStatus) => void)
// 进入刷新状态时触发回调
.onRefreshing(callback: () => void)
// 下拉距离发生变化时触发回调
.onOffsetChange(callback: Callback<number>)
常用参数(RefreshOptions):
| 参数名 | 类型 | 说明 |
|---|---|---|
| refreshing(必填) | boolean | 组件当前是否处于刷新中状态。 默认值:false,支持$$双向绑定 |
| builder? | CustomBuilder | 自定义刷新区域显示内容 |
| promptText? | ResourceStr | 设置刷新区域底部显示的文本 |
| refreshingContent? | 自定义组件 | 自定义刷新区域显示内容 |
显示优先级:refreshingContent > builder > promptText
下拉刷新的几种状态(RefreshStatus):
Inactive:默认未下拉状态,初始状态Drag:下拉中,下拉距离小于刷新距离OverDrag:下拉中,下拉距离超过刷新距离Refresh:下拉结束,回弹至刷新距离,进入刷新中状态Done:刷新结束,返回初始状态(顶部)
@Component
export struct QuestionListComp {
@State isRefreshing: boolean = false
@State refreshText: string = '' // 刷新提示文本
aboutToAppear(): void {
this.getData()
}
/* 上拉刷新自定义内容 */
@Builder
getRefreshBuilder() {
Row({ space: 8 }) {
LoadingProgress()
.width(20)
.aspectRatio(1)
Text(this.refreshText)
.fontSize(14)
.fontColor('#818181')
}
}
/* 请求数据 */
async getData() {
const res = await getQuestionList({ questionBankType: '10', type: this.typeId.toString() })
this.questions = res.rows
this.isRefreshing = false
}
build() {
Column() {
Refresh({ refreshing: $$this.isRefreshing,builder: this.getRefreshBuilder() }) {
List() {
ForEach(this.questions, (item: Question) => {
ListItem() {
QuestionItemComp({ item })
.padding({ left: 10, right: 10 })
}
})
}
.width('100%')
.height('100%')
}
.onStateChange(async (status) => {
switch (status) {
case RefreshStatus.Inactive:
console.log('初始化状态')
break
case RefreshStatus.Drag:
console.log('继续往下拉')
this.refreshText = '继续往下拉'
break
case RefreshStatus.OverDrag:
console.log('够了,不用拉了')
this.refreshText = '松手加载'
break
case RefreshStatus.Refresh:
console.log('刷新中')
this.refreshText = '加载中'
// 重新调用getData方法获取最新数据
await this.getData()
this.refreshText = '加载完成'
break
case RefreshStatus.Done:
this.refreshText = '加载成功'
console.log('刷新结束,回到初始值')
}
})
}
}
}
List组件 上拉加载
实现方案:使用List组件结合onReachEnd方法实现触底加载更多
/* 上拉加载时,显示的加载文字和loading */
@Builder
getBottom(){
Row({ space: 8 }) {
if (this.isLoadMore) {
Text('加载中...')
.fontSize(14)
.fontColor('#818181')
LoadingProgress()
.width(20)
.aspectRatio(1)
}
if (!this.haveData && !this.isLoadMore) {
Text('没有更多数据啦')
.fontSize(14)
.fontColor('#818181')
}
}
.width('100%')
.justifyContent(FlexAlign.Center)
.margin(5)
}
}
List() {
ForEach(this.questions, (item: Question) => {
ListItem() {
...
}
})
ListItem() {
this.getBottom()
}
.width('100%')
.height('100%')
.onReachEnd(() => {
// 如果还有数据,就触底加载更多
if (this.haveData) {
this.isLoadMore = true
this.getData()
}
})
:::danger
注:onReachEnd方法在页面进入的时候会触发一次
:::
完整示例
import { getQuestionList } from '../../../api/question'
import { MyLoadingDialog } from '../../../common/components'
import { Logger } from '../../../common/utils/logger'
import { Question, QuestionParams } from '../../../models'
import { QuestionItemComp } from '../QuestionItemComp/index'
@Component
export struct QuestionListComp {
@Prop typeId: number
@State questions: Question[] = []
@State isRefreshing: boolean = false
@State isLoadMore: boolean = false // 是否下拉刷新
@State page: number = 0
@State haveData: boolean = true // 是否还有数据
@State refreshText: string = '' // 刷新提示文本
aboutToAppear(): void {
// 页面刚加载会触发List的onReachEnd事件
// this.getData()
}
/* 上拉刷新 */
@Builder
getRefreshBuilder() {
Row({ space: 8 }) {
LoadingProgress()
.width(20)
.aspectRatio(1)
Text(this.refreshText)
.fontSize(14)
.fontColor('#818181')
}
}
async getData() {
// 上拉加载,加载下一页10条数据,page++
if (this.isLoadMore) {
this.page++
}
// 下拉刷新,重置到第一条数据,page为1
if (this.isRefreshing) {
this.page = 1
}
const res = await getQuestionList({
page:this.page,
pageSize: 10
})
if (this.isLoadMore) {
// 下拉刷新追加数据
this.questions.push(...res.rows)
} else {
// 刷新重置数据替换
this.questions = res.rows
}
// 判断是否还有数据
this.haveData = !(res.total === this.questions.length)
// 关闭刷新状态
this.isRefreshing = false
// 关闭下刷新
this.isLoadMore = false
}
build() {
Column() {
Refresh({ refreshing: $$this.isRefreshing, builder: this.getRefreshBuilder() }) {
List() {
ForEach(this.questions, (item: Question) => {
ListItem() {
QuestionItemComp({ item })
.padding({ left: 10, right: 10 })
}
})
ListItem() {
Row({ space: 8 }) {
if (this.isLoadMore) {
Text('加载中...')
.fontSize(14)
.fontColor('#818181')
LoadingProgress()
.width(20)
.aspectRatio(1)
}
if (!this.haveData && !this.isLoadMore) {
Text('没有更多数据啦')
.fontSize(14)
.fontColor('#818181')
}
}
.width('100%')
.justifyContent(FlexAlign.Center)
.margin(5)
}
}
.width('100%')
.height('100%')
.onReachEnd(() => {
// 如果还有数据,就触底加载更多
if (this.haveData) {
this.isLoadMore = true
this.getData()
}
})
}
.onStateChange(async (status) => {
switch (status) {
case RefreshStatus.Inactive:
break
case RefreshStatus.Drag:
this.refreshText = '继续往下拉'
break
case RefreshStatus.OverDrag:
this.refreshText = '松手加载'
break
case RefreshStatus.Refresh:
this.refreshText = '加载中'
await this.getData()
break
case RefreshStatus.Done:
this.refreshText = '加载成功'
}
})
}
}
}