介绍
PullDownRefresh 提供下拉刷新的交互操作。
PullDownRefresh 可以在页面或滚动元素中使用, 当满足下拉刷新条件(滚动到顶部)且进行下拉操作时,会接替容器的滚动行为。
当用户下拉到指定阈值时会触发 refresh 事件,此时要设置 loading 属性为 true 以便向用户展示加载状态,并发送网络请求。
在获取到数据后设置 loading 属性为 false 来关闭加载状态。
代码演示
基于页面的刷新
vue
<template>
<doc-page title="基于页面的刷新">
<s-pull-down-refresh :loading="loading" @refresh="onRefresh">
<div
v-for="item in 5"
:key="item"
style="
display: flex;
justify-content: center;
align-items: center;
margin: 0 16px 5px;
height: 40px;
border: 1px solid var(--s-border-color);
border-radius: var(--s-border-radius);
"
>
{{ item }}
</div>
</s-pull-down-refresh>
</doc-page>
</template>
<script setup lang="ts">
import { toast } from 'sard'
import { ref } from 'vue'
const loading = ref(false)
const fetchApi = () => {
return new Promise<void>((resolve) => {
setTimeout(() => {
resolve()
}, 1000)
})
}
const onRefresh = () => {
loading.value = true
fetchApi()
.then(() => {
toast('刷新成功')
})
.catch(() => {
toast('刷新失败')
})
.finally(() => {
loading.value = false
})
}
</script>vue
<template>
<doc-page title="基于页面的刷新">
<s-pull-down-refresh :loading="loading" @refresh="onRefresh">
<div
v-for="item in 5"
:key="item"
style="
display: flex;
justify-content: center;
align-items: center;
margin: 0 16px 5px;
height: 40px;
border: 1px solid var(--s-border-color);
border-radius: var(--s-border-radius);
"
>
{{ item }}
</div>
</s-pull-down-refresh>
</doc-page>
</template>
<script setup lang="js">
import { toast } from 'sard'
import { ref } from 'vue'
const loading = ref(false)
const fetchApi = () => {
return new Promise((resolve) => {
setTimeout(() => {
resolve()
}, 1e3)
})
}
const onRefresh = () => {
loading.value = true
fetchApi()
.then(() => {
toast('刷新成功')
})
.catch(() => {
toast('刷新失败')
})
.finally(() => {
loading.value = false
})
}
</script>基于滚动元素的刷新
PullDownRefresh 会查找祖先中第一个滚动元素,在其滚动到顶部并下拉时触发事件。
vue
<template>
<doc-page title="基于 scroll-view 的刷新" padding="10px">
<s-button block @click="loading = !loading">toggle loading</s-button>
<div
class="overflow-y-auto"
style="height: 300px; margin: 10px 0; border: 1px solid var(--s-border-color)"
>
<s-pull-down-refresh :loading="loading" @refresh="onRefresh">
<div
v-for="item in 10"
:key="item"
style="
display: flex;
justify-content: center;
align-items: center;
margin: 5px 16px;
height: 40px;
border: 1px solid var(--s-border-color);
border-radius: var(--s-border-radius);
"
>
{{ item }}
</div>
</s-pull-down-refresh>
</div>
</doc-page>
</template>
<script setup lang="ts">
import { toast } from 'sard'
import { ref } from 'vue'
const loading = ref(false)
const fetchApi = () => {
return new Promise<void>((resolve) => {
setTimeout(() => {
resolve()
}, 1000)
})
}
const onRefresh = () => {
loading.value = true
fetchApi()
.then(() => {
toast('刷新成功')
})
.catch(() => {
toast('刷新失败')
})
.finally(() => {
loading.value = false
})
}
</script>vue
<template>
<doc-page title="基于 scroll-view 的刷新" padding="10px">
<s-button block @click="loading = !loading">toggle loading</s-button>
<div
class="overflow-y-auto"
style="height: 300px; margin: 10px 0; border: 1px solid var(--s-border-color)"
>
<s-pull-down-refresh :loading="loading" @refresh="onRefresh">
<div
v-for="item in 10"
:key="item"
style="
display: flex;
justify-content: center;
align-items: center;
margin: 5px 16px;
height: 40px;
border: 1px solid var(--s-border-color);
border-radius: var(--s-border-radius);
"
>
{{ item }}
</div>
</s-pull-down-refresh>
</div>
</doc-page>
</template>
<script setup lang="js">
import { toast } from 'sard'
import { ref } from 'vue'
const loading = ref(false)
const fetchApi = () => {
return new Promise((resolve) => {
setTimeout(() => {
resolve()
}, 1e3)
})
}
const onRefresh = () => {
loading.value = true
fetchApi()
.then(() => {
toast('刷新成功')
})
.catch(() => {
toast('刷新失败')
})
.finally(() => {
loading.value = false
})
}
</script>自定义插槽
通过使用插槽可以自定义不同状态的提示信息。
其中 unready 插槽接收一个 progress 属性用来实现下拉进度展示的效果。
vue
<template>
<doc-page title="自定义插槽" padding="10px">
<div
class="overflow-y-auto"
style="height: 300px; margin: 10px 0; border: 1px solid var(--s-border-color)"
>
<s-pull-down-refresh :loading="loading" :done-duration="500" @refresh="onRefresh">
<template #unready="{ progress }">
<s-loading size="24px" :animated="false" :progress="progress">
<template #circular>
<demo-icon name="arrow-clockwise" />
</template>
下拉刷新
</s-loading>
</template>
<template #ready>
<s-loading size="24px" :animated="false">
<template #circular>
<demo-icon name="arrow-clockwise" />
</template>
释放刷新
</s-loading>
</template>
<template #loading>
<s-loading size="24px">
<template #circular>
<demo-icon name="arrow-clockwise" />
</template>
加载中...
</s-loading>
</template>
<template #done>{{ doneText }}</template>
<div
v-for="item in 10"
:key="item"
style="
display: flex;
justify-content: center;
align-items: center;
margin: 5px 16px;
height: 40px;
border: 1px solid var(--s-border-color);
border-radius: var(--s-border-radius);
"
>
{{ item }}
</div>
</s-pull-down-refresh>
</div>
</doc-page>
</template>
<script setup lang="ts">
import { ref } from 'vue'
const loading = ref(false)
const fetchApi = () => {
return new Promise<void>((resolve) => {
setTimeout(() => {
resolve()
}, 1000)
})
}
const doneText = ref('')
const onRefresh = () => {
loading.value = true
fetchApi()
.then(() => {
doneText.value = '刷新成功'
})
.catch(() => {
doneText.value = '刷新失败'
})
.finally(() => {
loading.value = false
})
}
</script>vue
<template>
<doc-page title="自定义插槽" padding="10px">
<div
class="overflow-y-auto"
style="height: 300px; margin: 10px 0; border: 1px solid var(--s-border-color)"
>
<s-pull-down-refresh :loading="loading" :done-duration="500" @refresh="onRefresh">
<template #unready="{ progress }">
<s-loading size="24px" :animated="false" :progress="progress">
<template #circular>
<demo-icon name="arrow-clockwise" />
</template>
下拉刷新
</s-loading>
</template>
<template #ready>
<s-loading size="24px" :animated="false">
<template #circular>
<demo-icon name="arrow-clockwise" />
</template>
释放刷新
</s-loading>
</template>
<template #loading>
<s-loading size="24px">
<template #circular>
<demo-icon name="arrow-clockwise" />
</template>
加载中...
</s-loading>
</template>
<template #done>{{ doneText }}</template>
<div
v-for="item in 10"
:key="item"
style="
display: flex;
justify-content: center;
align-items: center;
margin: 5px 16px;
height: 40px;
border: 1px solid var(--s-border-color);
border-radius: var(--s-border-radius);
"
>
{{ item }}
</div>
</s-pull-down-refresh>
</div>
</doc-page>
</template>
<script setup lang="js">
import { ref } from 'vue'
const loading = ref(false)
const fetchApi = () => {
return new Promise((resolve) => {
setTimeout(() => {
resolve()
}, 1e3)
})
}
const doneText = ref('')
const onRefresh = () => {
loading.value = true
fetchApi()
.then(() => {
doneText.value = '刷新成功'
})
.catch(() => {
doneText.value = '刷新失败'
})
.finally(() => {
loading.value = false
})
}
</script>API
PullDownRefreshProps
| 属性 | 描述 | 类型 | 默认值 |
|---|---|---|---|
| threshold | 触发下拉刷新的阈值,单位 px | number | 50 |
| header-height | 顶部内容高度,单位 px | number | 50 |
| loading | 是否处于加载中状态 | boolean | false |
| transition-duration | 回弹动画时长,单位 ms | number | 300 |
| done-duration | 加载完成状态持续时长,单位 ms | number | 500 |
| disabled | 是否禁止用户进行下拉操作 | boolean | false |
PullDownRefreshSlots
| 插槽 | 描述 | 属性 |
|---|---|---|
| default | 自定义默认内容 | - |
| unready | 自定义未预备加载状态内容,progress 属性表示从下拉开始到达到 threshold 的进度值 | { progress: number } |
| ready | 自定义预备加载状态内容 | - |
| loading | 自定义加载中状态内容 | - |
| done | 自定义加载完成状态内容 | - |
PullDownRefreshEmits
| 事件 | 描述 | 类型 |
|---|---|---|
| refresh | 下拉到指定阈值并松开手指后触发 | () => void |
主题定制
样式变量
| CSS 变量 | 值 |
|---|---|
--s-pull-down-refresh-header-font-size | var(--s-font-size-sm) |
--s-pull-down-refresh-header-color | var(--s-text-color-tertiary) |
--s-pull-down-refresh-loading-font-size | 18px |