Helpers & Composables
除了组件,@tripo3d/design 还导出若干工具函数与 composable。Nuxt 项目均自动导入,Vue 3 项目按需 import 即可。
cn
合并 class,内部使用 clsx + 扩展版 tailwind-merge,正确处理 UnoCSS / Tailwind 工具类的冲突(如 px-4 px-6 保留后者)。
| 签名 | 类型 | 说明 |
|---|---|---|
cn | (...classes: ClassValue[]) => string | 合并任意数量的 class 片段,自动去重/后胜 |
<script setup lang="ts">
import { cn } from '@tripo3d/design';
const props = defineProps<{ class?: string; active?: boolean }>();
const cls = cn('px-4 py-2', props.active && 'bg-yellow-400', props.class);
</script>dialog(命令式)
用于在非模板上下文(事件处理、工具函数)打开弹窗。依赖 <DialogOpener> 已挂载在应用根部(Nuxt 自动;Vue 3 需手动)。
| 方法 | 签名 | 说明 |
|---|---|---|
dialog.show | (Component, params?, key?) => key | 打开任意组件作为弹窗,返回唯一 key;传固定 key 则同一逻辑弹窗多次 show 复用实例(upsert 不卸载) |
dialog.update | (key, params?) => void | 更新已打开弹窗的 props |
dialog.close | (key) => void | 关闭弹窗(带 150ms 退场动画) |
<script setup lang="ts">
import { dialog } from '@tripo3d/design';
import MySettingsPanel from './MySettingsPanel.vue';
const key = dialog.show(MySettingsPanel, { initialTab: 'profile' });
// 3 秒后自动关闭
setTimeout(() => dialog.close(key), 3000);
</script>详见 Dialog。
float(命令式)
命令式打开通用浮窗(无遮罩、不阻塞背景交互),与 dialog 同款签名但走独立的 <FloatOpener> 栈。依赖 <FloatOpener> 已挂载在应用根部(Nuxt 自动;Vue 3 需手动)。
| 方法 | 签名 | 说明 |
|---|---|---|
float.show | (Component, params?, key?) => key | 打开任意组件作为浮窗,返回唯一 key;传固定 key 则同一逻辑浮窗多次 show 复用实例(upsert 不卸载) |
float.update | (key, params?) => void | 更新已打开浮窗的 props |
float.close | (key) => void | 关闭浮窗(带 150ms 退场动画) |
详见 Float。
imgViewer(命令式)
命令式打开图片放大预览浮窗,基于 float 单例(再次 show 自动关闭上一个)。自管 File→ObjectURL,无需手动挂组件。
| 方法 / 字段 | 签名 | 说明 |
|---|---|---|
imgViewer.show | (src, options?) => () => void | 打开预览,src 支持单图或数组;返回 close 闭包 |
imgViewer.close | () => void | 关闭当前预览 |
imgViewer.isOpen / currentIndex / currentImage | Readonly<Ref<...>> | 当前浮窗状态(模板中使用前须先在 setup 顶层解包) |
详见 ImgViewer · 浮窗预览。
loading(命令式)
全屏 Loading 遮罩,委托给 dialog 原语,默认渲染 Loading 组件。
| 方法 | 签名 | 说明 |
|---|---|---|
loading.show | (dialog?, params?) => key | 显示 Loading,可自定义渲染组件 |
loading.update | (key, params?) => void | 更新 Loading 内容 |
loading.close | (key) => void | 关闭 Loading |
<script setup lang="ts">
import { loading, toast } from '@tripo3d/design';
async function handleUpload() {
const key = loading.show();
try {
await uploadFiles(files);
toast.success('上传成功');
} finally {
loading.close(key);
}
}
</script>useDialog
在命令式打开的弹窗子组件中获取 close 方法,无需通过 emit 层层传递。
| 字段 | 类型 | 说明 |
|---|---|---|
close | () => void | 关闭当前弹窗 |
<script setup lang="ts">
import { useDialog } from '@tripo3d/design';
const { close } = useDialog();
</script>
<template>
<button @click="close">关闭自己</button>
</template>useFloat
在命令式打开的浮窗子组件中获取 close 方法(与 useDialog 对称,只是作用于 float 栈)。
| 字段 | 类型 | 说明 |
|---|---|---|
close | () => void | 关闭当前浮窗 |
详见 Float。
useCarousel
在 <Carousel> 默认 slot 作用域或子组件中控制轮播状态。
| 字段 | 类型 | 说明 |
|---|---|---|
orientation | 'horizontal' | 'vertical' | 当前方向 |
scrollNext | () => void | 滚动到下一项 |
scrollPrev | () => void | 滚动到上一项 |
canScrollNext | Ref<boolean> | 是否可向后滚动 |
canScrollPrev | Ref<boolean> | 是否可向前滚动 |
carouselApi | Ref<EmblaCarouselType> | Embla 原始 API,用于高级控制 |
<script setup lang="ts">
import { useCarousel } from '@tripo3d/design';
const { scrollNext, scrollPrev, canScrollNext } = useCarousel();
</script>详见 Carousel。
CarouselPlugin
<Carousel> 的内置插件集合,当前提供 Autoplay(来自 embla-carousel-autoplay),传给 Carousel 的 plugins。
<script setup lang="ts">
import { Carousel, CarouselPlugin } from '@tripo3d/design';
</script>
<template>
<Carousel :plugins="[CarouselPlugin.Autoplay()]">
<!-- ... -->
</Carousel>
</template>详见 Carousel。
toast
基于 vue-sonner 的 toast API。详见 Toaster。
常见模式
Opener 模式(命令式弹窗)
<script setup lang="ts">
import { dialog, useDialog } from '@tripo3d/design';
// 1. 打开任意组件作为弹窗
const key = dialog.show(MyComponent, { propA: 'value' });
// 2. 动态更新 props
dialog.update(key, { propA: 'new' });
// 3. 主动关闭
dialog.close(key);
// 4. 或在 MyComponent 内部关闭自己:
// const { close } = useDialog();
</script>链式 class 合并
<script setup lang="ts">
import { cn } from '@tripo3d/design';
const props = defineProps<{
size?: 'sm' | 'md' | 'lg';
variant?: 'solid' | 'outline';
class?: string;
}>();
const cls = cn(
'rounded-6 transition',
{
'px-3 h-8': props.size === 'sm',
'px-4 h-10': props.size === 'md',
'px-6 h-12': props.size === 'lg',
},
props.variant === 'outline' && 'border border-purple-1',
props.class, // 允许外部覆写最终落位
);
</script>