Button
使用具有按压反馈的操作表面,并可选磁吸、状态和金属质感变体。
适用场景
- 用于表单提交、确认等明确操作;跳转到其他页面时使用链接。
安装
选择安装方式,用法示例将同步更新导入路径。
$ bunx --bun shadcn-vue@2.8.2 add https://orvui.efu.me/r/button.json https://orvui.efu.me/r/button-metallic.json https://orvui.efu.me/r/button-base.json https://orvui.efu.me/r/button-stateful.json https://orvui.efu.me/r/button-magnetic.json
首次使用时,将安装的 src/components/orvui/styles.css 导入项目样式入口。
示例
金属质感
metallic.vue在中性操作表面的金属边缘移动一道直线反光。
packages/vue/src/motion/button/examples/metallic.vue
<script setup lang="ts">
import { ArrowUpRight, Sparkles } from "lucide-vue-next";
import { MetallicButton } from "@/components/orvui/motion/button";
</script>
<template><div class="flex flex-wrap items-center justify-center gap-3 px-6 py-10">
<MetallicButton>Continue<ArrowUpRight class="size-4" /></MetallicButton>
<MetallicButton size="sm"><Sparkles class="size-3.5" />Generate</MetallicButton>
<MetallicButton size="icon" aria-label="Magic tools"><Sparkles class="size-4" /></MetallicButton>
</div></template>
packages/vue/src/motion/button/src/MetallicButton.vue
基础
base.vue比较不同尺寸与外观,并查看悬停抬升和按压收缩反馈。
packages/vue/src/motion/button/examples/base.vue
<script setup lang="ts">
import { ArrowRight, Download, Trash2 } from "lucide-vue-next";
import { Button } from "@/components/orvui/motion/button";
const variants = ["outline", "ghost"] as const;
</script>
<template>
<div class="flex flex-col items-center gap-6">
<div class="flex flex-wrap items-center justify-center gap-3"><Button>Continue<ArrowRight class="h-4 w-4" /></Button><Button variant="secondary"><Download class="h-4 w-4" />Download</Button><Button v-for="variant in variants" :key="variant" :variant="variant">{{ variant === 'outline' ? 'Outline' : 'Ghost' }}</Button></div>
<div class="flex flex-wrap items-center justify-center gap-3"><Button size="sm">Small</Button><Button>Medium</Button><Button size="lg">Large</Button><Button variant="secondary" size="icon" aria-label="Delete"><Trash2 class="h-4 w-4" /></Button></div>
<div class="flex flex-wrap items-center justify-center gap-3"><Button ripple>Ripple</Button><Button variant="outline" ripple>Tap me</Button></div>
</div>
</template>
packages/vue/src/motion/button/src/Button.vue
状态按钮
stateful.vue在空闲、加载、成功与失败之间切换,宽度跟随当前内容调整。
packages/vue/src/motion/button/examples/stateful.vue
<script setup lang="ts">
import { onBeforeUnmount, reactive } from "vue";
import { ArrowRight } from "lucide-vue-next";
import { StatefulButton, type ButtonState } from "@/components/orvui/motion/button";
const states = reactive<{ ok: ButtonState; err: ButtonState }>({ ok: "idle", err: "idle" });
const scheduled = new Set<ReturnType<typeof setTimeout>>();
function after(delay: number, callback: () => void) {
const timer = setTimeout(() => { scheduled.delete(timer); callback(); }, delay);
scheduled.add(timer);
}
function run(key: "ok" | "err") {
if (states[key] === "loading") return;
states[key] = "loading";
after(1400, () => { states[key] = key === "ok" ? "success" : "error"; after(1800, () => { states[key] = "idle"; }); });
}
onBeforeUnmount(() => { scheduled.forEach(timer => clearTimeout(timer)); scheduled.clear(); });
</script>
<template><div class="flex flex-col items-center justify-center gap-3">
<StatefulButton :state="states.ok" loading-text="Saving" success-text="Saved" :icon="ArrowRight" @click="run('ok')">Save changes</StatefulButton>
<StatefulButton :state="states.err" variant="secondary" loading-text="Submitting" error-text="Failed" @click="run('err')">Submit</StatefulButton>
</div></template>
packages/vue/src/motion/button/src/StatefulButton.vue
磁吸
magnetic.vue用 Magnetic 包装操作控件,让其表面跟随附近的指针移动。
packages/vue/src/motion/button/examples/magnetic.vue
<script setup lang="ts">
import { ArrowRight } from "lucide-vue-next";
import { MagneticButton } from "@/components/orvui/motion/button";
const alternatives = [{ variant: "secondary", strength: 0.25, label: "Subtle pull" }, { variant: "outline", strength: 0.5, label: "Strong pull" }] as const;
</script>
<template><div class="flex flex-wrap items-center justify-center gap-4">
<MagneticButton :strength="0.35">Hover me<ArrowRight class="h-4 w-4" /></MagneticButton>
<MagneticButton v-for="sample in alternatives" :key="sample.variant" :variant="sample.variant" :strength="sample.strength">{{ sample.label }}</MagneticButton>
</div></template>
packages/vue/src/motion/button/src/MagneticButton.vue
状态与事件
此示例组合没有声明成对的受控属性与 update 事件。使用已列出的属性、原生事件和插槽组合内容;不要为它添加未公开的 v-model。
API 参考
金属质感
MetallicButton
size?"sm" | "md" | "lg" | "icon""md"paused?booleanfalsedisabled?booleanfalse插槽
default() => VNodeChild#defaultButton
variant?"primary" | "secondary" | "ghost" | "outline""primary"size?"sm" | "md" | "lg" | "icon""md"pressScale?number0.93ripple?booleanfalsedisabled?booleanfalsetype?"button" | "submit" | "reset""button"插槽
default() => VNodeChild#default基础
variant?"primary" | "secondary" | "ghost" | "outline""primary"size?"sm" | "md" | "lg" | "icon""md"pressScale?number0.93ripple?booleanfalsedisabled?booleanfalsetype?"button" | "submit" | "reset""button"插槽
default() => VNodeChild#default状态按钮
StatefulButton
state?"success" | "idle" | "loading" | "error""idle"loadingText?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>"Loading"successText?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>"Done"errorText?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>"Try again"icon?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>—variant?"primary" | "secondary" | "ghost" | "outline"—size?"sm" | "md" | "lg" | "icon"—pressScale?number—ripple?booleanfalsedisabled?booleanfalsetype?"button" | "submit" | "reset"—插槽
icon() => VNodeChild#iconButton
variant?"primary" | "secondary" | "ghost" | "outline""primary"size?"sm" | "md" | "lg" | "icon""md"pressScale?number0.93ripple?booleanfalsedisabled?booleanfalsetype?"button" | "submit" | "reset""button"插槽
default() => VNodeChild#default磁吸
MagneticButton
strength?number0.25disabled?booleanfalsemagneticClassName?string—插槽
default() => VNodeChild#defaultButton
variant?"primary" | "secondary" | "ghost" | "outline""primary"size?"sm" | "md" | "lg" | "icon""md"pressScale?number0.93ripple?booleanfalsedisabled?booleanfalsetype?"button" | "submit" | "reset""button"插槽
default() => VNodeChild#default无障碍
为交互控件提供明确的无障碍名称。保留文档中的键盘路径、可见焦点与减少动态效果状态;自定义插槽应继续保留所替代部件的语义。
常见问题
- 如何配置 Button?
- 通过 variant、size、pressScale、ripple、disabled、type 配置 Button;API 表列出其类型与默认值。
- 如何连接到应用状态?
- 通过default 插槽提供内容,应用副作用由调用方管理。
- 可以在服务端渲染吗?
- 可以在 Vue SSR 应用中正常渲染。服务端与客户端的初始 props 应保持一致;浏览器测量与交互资源在挂载后启动。
更新于
来源与许可 ↗MIT · 0.1.1