Loading...
Loading...
Compare original and translation side by side
@vuetify/v0 — Headless composables and components for Vue 3. Unstyled, logic-focused building blocks for design systems.
@vuetify/v0 — 适用于Vue 3的无头组合式函数与组件。无样式、专注逻辑的设计系统构建块。
pnpm install @vuetify/v0import { createSelection } from '@vuetify/v0/composables'
import { Tabs } from '@vuetify/v0/components'
import { mergeDeep } from '@vuetify/v0/utilities'
import { IN_BROWSER } from '@vuetify/v0/constants'
import { Vuetify0DateAdapter } from '@vuetify/v0/date'
import type { ID } from '@vuetify/v0/types'pnpm install @vuetify/v0import { createSelection } from '@vuetify/v0/composables'
import { Tabs } from '@vuetify/v0/components'
import { mergeDeep } from '@vuetify/v0/utilities'
import { IN_BROWSER } from '@vuetify/v0/constants'
import { Vuetify0DateAdapter } from '@vuetify/v0/date'
import type { ID } from '@vuetify/v0/types'claude mcp add --transport http vuetify-mcp https://mcp.vuetifyjs.com/mcpget_vuetify0_skillget_vuetify0_composable_listget_vuetify0_composable_guideget_vuetify0_component_listget_vuetify0_component_guideclaude mcp add --transport http vuetify-mcp https://mcp.vuetifyjs.com/mcpget_vuetify0_skillget_vuetify0_composable_listget_vuetify0_composable_guideget_vuetify0_component_listget_vuetify0_component_guide| Need | Use |
|---|---|
| Single item selection | |
| Multi-item selection | |
| Selection with "select all" | |
| Step wizard / carousel | |
| Tree / nested items | |
| Form validation | |
| Shared state (provide/inject) | |
| Collection tracking | |
| Overflow detection | |
| Stacking / z-index layers | |
| Filtering arrays | |
| Pagination | |
| Virtual scrolling | |
| Undo / redo | |
| Notification queue | |
| Design tokens | |
| Proxy model (v-model) | |
| Keyboard shortcuts | |
| Click outside | |
| Element resizing | |
| Element visibility | |
| Responsive breakpoints | |
| Theme switching | |
| Persistent storage | |
| SSR check | |
| Type guards | |
| 需求 | 使用工具 |
|---|---|
| 单项选择 | |
| 多项选择 | |
| 带“全选”的选择 | |
| 分步向导/轮播 | |
| 树形/嵌套项 | |
| 表单验证 | |
| 共享状态(provide/inject) | |
| 集合跟踪 | |
| 溢出检测 | |
| 堆叠/z-index层级 | |
| 数组过滤 | |
| 分页 | |
| 虚拟滚动 | |
| 撤销/重做 | |
| 通知队列 | |
| 设计令牌 | |
| 代理模型(v-model) | |
| 键盘快捷键 | |
| 外部点击检测 | |
| 元素尺寸变化 | |
| 元素可见性 | |
| 响应式断点 | |
| 主题切换 | |
| 持久化存储 | |
| SSR检测 | |
| 类型守卫 | |
<script lang="ts" setup>
import { Tabs } from '@vuetify/v0/components'
</script>
<template>
<Tabs.Root v-model="active">
<Tabs.List>
<Tabs.Item value="overview">Overview</Tabs.Item>
<Tabs.Item value="features">Features</Tabs.Item>
</Tabs.List>
<Tabs.Panel value="overview">...</Tabs.Panel>
<Tabs.Panel value="features">...</Tabs.Panel>
</Tabs.Root>
</template><script lang="ts" setup>
import { Tabs } from '@vuetify/v0/components'
</script>
<template>
<Tabs.Root v-model="active">
<Tabs.List>
<Tabs.Item value="overview">Overview</Tabs.Item>
<Tabs.Item value="features">Features</Tabs.Item>
</Tabs.List>
<Tabs.Panel value="overview">...</Tabs.Panel>
<Tabs.Panel value="features">...</Tabs.Panel>
</Tabs.Root>
</template><script lang="ts" setup>
import { Dialog } from '@vuetify/v0/components'
</script>
<template>
<Dialog.Root v-model="open">
<Dialog.Activator>Open</Dialog.Activator>
<Dialog.Content>
<Dialog.Title>Confirm</Dialog.Title>
<Dialog.Description>Are you sure?</Dialog.Description>
<Dialog.Close>Cancel</Dialog.Close>
</Dialog.Content>
</Dialog.Root>
</template><script lang="ts" setup>
import { Dialog } from '@vuetify/v0/components'
</script>
<template>
<Dialog.Root v-model="open">
<Dialog.Activator>Open</Dialog.Activator>
<Dialog.Content>
<Dialog.Title>Confirm</Dialog.Title>
<Dialog.Description>Are you sure?</Dialog.Description>
<Dialog.Close>Cancel</Dialog.Close>
</Dialog.Content>
</Dialog.Root>
</template>| Component | Purpose |
|---|---|
| Polymorphic element — render as any HTML tag |
| Image with fallback system |
| Checkbox with tri-state and group support |
| Modal with focus trap |
| Accordion (single or multi-expand) |
| Multi-selection container |
| Page navigation with First/Last/Next/Prev/Ellipsis |
| Toggle overlay (CSS anchor positioning) |
| Radio buttons with roving tabindex |
| Overlay backdrop |
| Generic selection container |
| Single-selection container |
| Stepper / wizard |
| Tab navigation with keyboard support |
// Single selection (e.g., theme picker, active tab)
const single = createSingle({ mandatory: 'force' })
single.register({ id: 'light', value: 'light' })
single.register({ id: 'dark', value: 'dark' })
single.select('dark')
single.selectedValue // Ref<string | undefined>
// Multi-selection (e.g., tag picker, multi-select list)
const selection = createSelection({ multiple: true })
selection.toggle('a')
selection.isSelected('a') // boolean
// Group with "select all" (e.g., data table checkboxes)
const group = createGroup()
group.selectAll()
group.toggleAll()
group.isMixed // true when partially selected
// Sequential navigation (e.g., stepper, carousel)
const stepper = createStep({ circular: true })
stepper.next()
stepper.prev()
stepper.first()
stepper.last()// 单项选择(如主题选择器、激活标签页)
const single = createSingle({ mandatory: 'force' })
single.register({ id: 'light', value: 'light' })
single.register({ id: 'dark', value: 'dark' })
single.select('dark')
single.selectedValue // Ref<string | undefined>
// 多项选择(如标签选择器、多选列表)
const selection = createSelection({ multiple: true })
selection.toggle('a')
selection.isSelected('a') // boolean
// 带“全选”的分组选择(如数据表格复选框)
const group = createGroup()
group.selectAll()
group.toggleAll()
group.isMixed // 部分选中时为true
// 顺序导航(如分步向导、轮播)
const stepper = createStep({ circular: true })
stepper.next()
stepper.prev()
stepper.first()
stepper.last()const form = createForm()
form.register({
id: 'email',
value: '',
rules: [
v => !!v || 'Required',
v => /.+@.+/.test(v) || 'Invalid email',
async v => await checkAvailable(v) || 'Email taken'
]
})
form.submit() // Validates all fields, returns { valid, errors }const form = createForm()
form.register({
id: 'email',
value: '',
rules: [
v => !!v || '必填项',
v => /.+@.+/.test(v) || '邮箱格式无效',
async v => await checkAvailable(v) || '该邮箱已被占用'
]
})
form.submit() // 验证所有字段,返回 { valid, errors }// createContext — type-safe provide/inject
const [useTheme, provideTheme] = createContext<ThemeContext>('Theme')
// Provider component
provideTheme({ mode, toggle })
// Consumer component (throws helpful error if not provided)
const { mode, toggle } = useTheme()
// createTrinity — context with built-in defaults
const [useConfig, provideConfig, defaultConfig] = createTrinity<Config>('Config', {
theme: 'light',
locale: 'en'
})// createContext — 类型安全的provide/inject
const [useTheme, provideTheme] = createContext<ThemeContext>('Theme')
// 提供者组件
provideTheme({ mode, toggle })
// 消费者组件(若未提供提供者,会抛出清晰的错误提示)
const { mode, toggle } = useTheme()
// createTrinity — 带默认值的上下文
const [useConfig, provideConfig, defaultConfig] = createTrinity<Config>('Config', {
theme: 'light',
locale: 'en'
})// Filtering
const { apply } = createFilter({ keys: ['name', 'email'] })
const filtered = apply(query, users)
// Pagination
const pagination = createPagination({ page: 1, itemsPerPage: 10, length: 100 })
pagination.next()
// Virtual scrolling
const { virtualItems, totalHeight, scrollTo } = createVirtual({
items: largeList,
itemHeight: 48
})
// Undo/redo
const timeline = createTimeline({ maxSize: 50 })
timeline.push(state)
timeline.undo()
// Notification queue with auto-dismiss
const notifications = createQueue({ timeout: 5000 })
notifications.push({ message: 'Saved!' })// 过滤
const { apply } = createFilter({ keys: ['name', 'email'] })
const filtered = apply(query, users)
// 分页
const pagination = createPagination({ page: 1, itemsPerPage: 10, length: 100 })
pagination.next()
// 虚拟滚动
const { virtualItems, totalHeight, scrollTo } = createVirtual({
items: largeList,
itemHeight: 48
})
// 撤销/重做
const timeline = createTimeline({ maxSize: 50 })
timeline.push(state)
timeline.undo()
// 带自动关闭的通知队列
const notifications = createQueue({ timeout: 5000 })
notifications.push({ message: '保存成功!' })// SSR-safe environment checks
import { IN_BROWSER, SUPPORTS_TOUCH, SUPPORTS_OBSERVER } from '@vuetify/v0/constants'
// DOM observation (auto-cleanup on unmount)
const { width, height } = useResizeObserver(el)
const { isIntersecting } = useIntersectionObserver(el, { threshold: 0.1 })
// Events
useEventListener(window, 'resize', onResize)
useHotkey('ctrl+k', openSearch)
useClickOutside(menuRef, close)
// Responsive
const { md, lgAndUp } = useBreakpoints()
const { matches } = useMediaQuery('(prefers-color-scheme: dark)')// SSR安全的环境检测
import { IN_BROWSER, SUPPORTS_TOUCH, SUPPORTS_OBSERVER } from '@vuetify/v0/constants'
// DOM监听(组件卸载时自动清理)
const { width, height } = useResizeObserver(el)
const { isIntersecting } = useIntersectionObserver(el, { threshold: 0.1 })
// 事件监听
useEventListener(window, 'resize', onResize)
useHotkey('ctrl+k', openSearch)
useClickOutside(menuRef, close)
// 响应式
const { md, lgAndUp } = useBreakpoints()
const { matches } = useMediaQuery('(prefers-color-scheme: dark)')main.tsimport { createThemePlugin, createBreakpointsPlugin } from '@vuetify/v0'
app.use(
createThemePlugin({
themes: {
light: { colors: { primary: '#3b82f6' } },
dark: { colors: { primary: '#60a5fa' } },
}
})
)
app.use(createBreakpointsPlugin())
// Then in any component:
const { current, toggle } = useTheme()
const { md, lgAndUp } = useBreakpoints()createThemePlugincreateBreakpointsPlugincreateFeaturesPlugincreateLoggerPlugincreateLocalePlugincreateDatePlugincreateStoragePluginmain.tsimport { createThemePlugin, createBreakpointsPlugin } from '@vuetify/v0'
app.use(
createThemePlugin({
themes: {
light: { colors: { primary: '#3b82f6' } },
dark: { colors: { primary: '#60a5fa' } },
}
})
)
app.use(createBreakpointsPlugin())
// 之后在任意组件中使用:
const { current, toggle } = useTheme()
const { md, lgAndUp } = useBreakpoints()createThemePlugincreateBreakpointsPlugincreateFeaturesPlugincreateLoggerPlugincreateLocalePlugincreateDatePlugincreateStoragePlugin// Bad — v0 handles reactivity, mandatory constraints, and events for you
const selected = ref<string[]>([])
function toggle (id: string) {
const index = selected.value.indexOf(id)
if (index >= 0) selected.value.splice(index, 1)
else selected.value.push(id)
}
// Good
const selection = createSelection({ multiple: true })
selection.toggle(id)// 不推荐 — v0已为你处理响应式、强制约束和事件
const selected = ref<string[]>([])
function toggle (id: string) {
const index = selected.value.indexOf(id)
if (index >= 0) selected.value.splice(index, 1)
else selected.value.push(id)
}
// 推荐
const selection = createSelection({ multiple: true })
selection.toggle(id)// Bad — no type safety, no error on missing provider
provide('theme', theme)
const theme = inject('theme') // Could be undefined!
// Good — type-safe, throws descriptive error if provider is missing
const [useTheme, provideTheme] = createContext<ThemeContext>('theme')// 不推荐 — 无类型安全,提供者缺失时无错误提示
provide('theme', theme)
const theme = inject('theme') // 可能为undefined!
// 推荐 — 类型安全,提供者缺失时抛出明确错误
const [useTheme, provideTheme] = createContext<ThemeContext>('theme')// Bad
if (typeof window !== 'undefined')
// Good
import { IN_BROWSER } from '@vuetify/v0/constants'
if (IN_BROWSER)// 不推荐
if (typeof window !== 'undefined')
// 推荐
import { IN_BROWSER } from '@vuetify/v0/constants'
if (IN_BROWSER)Foundation (no dependencies)
├── createContext → Basic DI
├── createPlugin → Vue plugin factory
└── createTrinity → [use, provide, default] pattern
Registry (uses Foundation)
├── createRegistry → Collection management
├── useProxyRegistry → External registry proxy
└── useStack → Layered z-index management
Selection (uses Registry)
├── createSelection → Multi-select (base)
├── createSingle → Single-select
├── createGroup → Multi + tri-state
├── createStep → Sequential navigation
└── createNested → Hierarchical
Data (uses Registry)
├── createForm → Validation
├── createFilter → Array filtering
├── createPagination → Page navigation
├── createVirtual → Virtual scrolling
├── createTokens → Design tokens
├── createQueue → FIFO with timeout
└── createTimeline → Undo/redo
System (standalone)
├── useResizeObserver → Element dimensions
├── useIntersectionObserver → Visibility detection
├── useMutationObserver → DOM mutations
├── useEventListener → Auto-cleanup events
├── useHotkey → Keyboard shortcuts
├── useClickOutside → Outside click detection
├── useToggleScope → Conditional effect scopes
└── createOverflow → Container overflow detection
Plugins (app-wide, uses createPlugin)
├── useTheme → Theme switching
├── useBreakpoints → Responsive detection
├── useLocale → i18n
├── useDate → Date utilities
├── useStorage → localStorage/sessionStorage
├── useFeatures → Feature flags
├── usePermissions → Permission management
├── useLogger → Logging
├── useHydration → SSR hydration
└── useLazy → Deferred computation
Transformers
├── toArray → Normalize to array
└── toReactive → MaybeRef to reactive基础层(无依赖)
├── createContext → 基础依赖注入
├── createPlugin → Vue插件工厂
└── createTrinity → [use, provide, default] 模式
注册管理层(基于基础层)
├── createRegistry → 集合管理
├── useProxyRegistry → 外部注册管理代理
└── useStack → 分层z-index管理
选择层(基于注册管理层)
├── createSelection → 多选(基础)
├── createSingle → 单选
├── createGroup → 多选+三态
├── createStep → 顺序导航
└── createNested → 层级选择
数据层(基于注册管理层)
├── createForm → 验证
├── createFilter → 数组过滤
├── createPagination → 分页导航
├── createVirtual → 虚拟滚动
├── createTokens → 设计令牌
├── createQueue → 带超时的FIFO队列
└── createTimeline → 撤销/重做
系统层(独立)
├── useResizeObserver → 元素尺寸监听
├── useIntersectionObserver → 可见性检测
├── useMutationObserver → DOM变化监听
├── useEventListener → 自动清理的事件监听
├── useHotkey → 键盘快捷键
├── useClickOutside → 外部点击检测
├── useToggleScope → 条件生效的作用域
└── createOverflow → 容器溢出检测
插件层(全局应用,基于createPlugin)
├── useTheme → 主题切换
├── useBreakpoints → 响应式断点检测
├── useLocale → 国际化
├── useDate → 日期工具
├── useStorage → localStorage/sessionStorage管理
├── useFeatures → 功能开关
├── usePermissions → 权限管理
├── useLogger → 日志管理
├── useHydration → SSR水合
└── useLazy → 延迟计算
转换工具
├── toArray → 标准化为数组
└── toReactive → MaybeRef转响应式import { mergeDeep, clamp, range, debounce, useId } from '@vuetify/v0/utilities'
mergeDeep({}, defaults, overrides) // Deep merge (prototype-pollution safe)
clamp(value, 0, 100) // Clamp to range
range(5) // [0, 1, 2, 3, 4]
range(5, 1) // [1, 2, 3, 4, 5]
const search = debounce(fn, 300) // With .clear() and .immediate()
const id = useId() // SSR-safe unique IDimport { mergeDeep, clamp, range, debounce, useId } from '@vuetify/v0/utilities'
mergeDeep({}, defaults, overrides) // 深度合并(防原型污染)
clamp(value, 0, 100) // 数值范围限制
range(5) // [0, 1, 2, 3, 4]
range(5, 1) // [1, 2, 3, 4, 5]
const search = debounce(fn, 300) // 支持.clear()和.immediate()
const id = useId() // SSR安全的唯一IDimport { isString, isNumber, isObject, isArray, isFunction, isBoolean, isNull, isUndefined, isNullOrUndefined, isPrimitive, isSymbol, isNaN } from '@vuetify/v0/utilities'import { isString, isNumber, isObject, isArray, isFunction, isBoolean, isNull, isUndefined, isNullOrUndefined, isPrimitive, isSymbol, isNaN } from '@vuetify/v0/utilities'