Motion review approved
4mThe pull request is ready to merge.
将向下拖动转换为有意触发的异步刷新,并显示进度。
选择安装方式,用法示例将同步更新导入路径。
此示例还需要:
pnpm add lucide-vue-next@^0.468.0首次使用时,将安装的 src/components/orvui/styles.css 导入项目样式入口。
Activity
Pull down to check for updates
Motion review approved
4mThe pull request is ready to merge.
New component feedback
18mThe spring feels much closer to native now.
Registry checks passed
31mAll component files resolved successfully.
Preview deployed
1hThe latest build is ready to inspect.
Docs comment resolved
2hThe usage example now covers async refreshes.
<script setup lang="ts">
import { computed, onBeforeUnmount, ref } from "vue";
import { Bell, CheckCircle2, GitPullRequest, MessageCircle } from "lucide-vue-next";
import { PullToRefresh } from "@/components/orvui/motion/pull-to-refresh";
const activity = [
{ id: 1, icon: GitPullRequest, title: "Motion review approved", detail: "The pull request is ready to merge.", time: "4m" },
{ id: 2, icon: MessageCircle, title: "New component feedback", detail: "The spring feels much closer to native now.", time: "18m" },
{ id: 3, icon: CheckCircle2, title: "Registry checks passed", detail: "All component files resolved successfully.", time: "31m" },
{ id: 4, icon: Bell, title: "Preview deployed", detail: "The latest build is ready to inspect.", time: "1h" },
{ id: 5, icon: MessageCircle, title: "Docs comment resolved", detail: "The usage example now covers async refreshes.", time: "2h" },
];
const refreshes = ref(0);
const latest = ref<number | null>(null);
const updates = computed(() => latest.value ? [{ id: latest.value, icon: Bell, title: "You’re all caught up", detail: "The activity feed was refreshed just now.", time: "now" }, ...activity] : activity);
let timer: ReturnType<typeof setTimeout> | undefined;
let release: (() => void) | undefined;
let disposed = false;
function refresh() { return new Promise<void>(resolve => { release = resolve; timer = setTimeout(() => { if (!disposed) { refreshes.value++; latest.value = Date.now(); } release = undefined; resolve(); }, 900); }); }
onBeforeUnmount(() => { disposed = true; clearTimeout(timer); release?.(); });
</script>
<template><div class="flex min-h-[34rem] w-full items-center justify-center p-4"><div class="w-full max-w-sm overflow-hidden rounded-[2rem] border border-border bg-background shadow-2xl"><PullToRefresh ariaLabel="Activity feed" class="h-[30rem]" :on-refresh="refresh"><header class="sticky top-0 z-10 flex items-center justify-between border-b border-border bg-background/90 px-5 py-4 backdrop-blur-md"><div><p class="font-semibold text-foreground">Activity</p><p class="text-xs text-muted-foreground">Pull down to check for updates</p></div><span class="rounded-full bg-muted px-2.5 py-1 font-mono text-[10px] text-muted-foreground">{{ refreshes ? `${refreshes} refreshed` : 'live' }}</span></header><div class="divide-y divide-border px-2 pb-3"><article v-for="update in updates" :key="update.id" class="flex gap-3 px-3 py-4"><div class="grid h-9 w-9 shrink-0 place-items-center rounded-xl border border-border bg-card text-muted-foreground shadow-sm"><component :is="update.icon" class="h-4 w-4" /></div><div class="min-w-0 flex-1"><div class="flex items-start justify-between gap-3"><p class="text-sm font-medium text-foreground">{{ update.title }}</p><span class="shrink-0 font-mono text-[10px] text-muted-foreground">{{ update.time }}</span></div><p class="mt-1 text-xs leading-relaxed text-muted-foreground">{{ update.detail }}</p></div></article></div></PullToRefresh></div></div></template>
此示例组合没有声明成对的受控属性与 update 事件。使用已列出的属性、原生事件和插槽组合内容;不要为它添加未公开的 v-model。
onRefresh?() => void | Promise<void>—refreshing?booleanfalsedisabled?booleanfalsethreshold?number76maxPull?number132holdDistance?number68pullingLabel?boolean | null | string | number | void | VNode<RendererNode, RendererElement, { [key: string]: any; }> | VNodeArrayChildren | ComponentOptions<any, any, any, ComputedOptions, MethodOptions, any, any, any, string, {}, {}, string, {}, {}, {}, string, ComponentProvideOptions> | FunctionalComponent<any, {}, any, {}> | ComponentPublicInstanceConstructor<any, any, any, any, ComputedOptions, MethodOptions>"Pull to refresh"releaseLabel?boolean | null | string | number | void | VNode<RendererNode, RendererElement, { [key: string]: any; }> | VNodeArrayChildren | ComponentOptions<any, any, any, ComputedOptions, MethodOptions, any, any, any, string, {}, {}, string, {}, {}, {}, string, ComponentProvideOptions> | FunctionalComponent<any, {}, any, {}> | ComponentPublicInstanceConstructor<any, any, any, any, ComputedOptions, MethodOptions>"Release to refresh"refreshingLabel?boolean | null | string | number | void | VNode<RendererNode, RendererElement, { [key: string]: any; }> | VNodeArrayChildren | ComponentOptions<any, any, any, ComputedOptions, MethodOptions, any, any, any, string, {}, {}, string, {}, {}, {}, string, ComponentProvideOptions> | FunctionalComponent<any, {}, any, {}> | ComponentPublicInstanceConstructor<any, any, any, any, ComputedOptions, MethodOptions>"Refreshing"ariaLabel?string"Refreshable content"contentClassName?string—indicatorClassName?string—error[error: unknown]@errordefault—作用域参数: status, progress
#default为交互控件提供明确的无障碍名称。保留文档中的键盘路径、可见焦点与减少动态效果状态;自定义插槽应继续保留所替代部件的语义。
更新于