迁移到 v3

迁移到 v4
一份将您的应用程序从 Nuxt UI v2 迁移到 Nuxt UI v3 的综合指南。

Nuxt UI v3 是一个从头开始重建的新主要版本,引入了现代架构,显著提升了性能并增强了开发者体验。此主要版本包含多项重大变更以及强大的新特性和功能。

  • Tailwind CSS v4:从 JavaScript 迁移到基于 CSS 的配置
  • Reka UI:取代 Headless UI 作为底层组件库
  • Tailwind Variants:新的组件变体样式 API

本指南提供将您的应用程序从 v2 迁移到 v3 的分步说明。

迁移您的项目

更新 Tailwind CSS

Tailwind CSS v4 对其配置方法进行了重大更改。官方的 Tailwind 升级工具将帮助自动化大部分迁移过程。

有关所有更改的详细说明,请参阅官方的 Tailwind CSS v4 升级指南
  1. 创建一个 main.css 文件并将其导入到您的 nuxt.config.ts 文件中。
@import "tailwindcss";
  1. 运行 Tailwind CSS 升级工具
npx @tailwindcss/upgrade

更新 Nuxt UI

  1. 安装最新版本的包
pnpm add @nuxt/ui
  1. 将其导入到您的 CSS 中
app/assets/css/main.css
@import "tailwindcss";
@import "@nuxt/ui";
  1. App 组件包裹您的应用程序
app.vue
<template>
  <UApp>
    <NuxtPage />
  </UApp>
</template>

v2 中的更改

现在您已经更新了项目,可以开始迁移代码了。以下是 Nuxt UI v3 中所有重大更改的综合列表。

更新的设计系统

在 Nuxt UI v2 中,我们混合使用了带有 primarygrayerror 别名以及所有 Tailwind CSS 颜色的设计系统。我们已将其替换为包含 7 个颜色别名的适当设计系统

颜色默认值描述
primarygreen主要品牌颜色,用作组件的默认颜色。
secondaryblue辅助颜色,用于补充主要颜色。
successgreen用于成功状态。
infoblue用于信息状态。
warningyellow用于警告状态。
errorred用于表单错误验证状态。
neutralslate用于背景、文本等的中性颜色。

此更改引入了一些您需要注意的重大变更:

  • gray 颜色已重命名为 neutral
<template>
- <p class="text-gray-500 dark:text-gray-400" />
+ <p class="text-neutral-500 dark:text-neutral-400" />
</template>
您还可以使用新的设计令牌来处理亮色和暗色模式。
<template>
- <p class="text-gray-500 dark:text-gray-400" />
+ <p class="text-muted" />

- <p class="text-gray-900 dark:text-white" />
+ <p class="text-highlighted" />
</template>
  • color 属性中的 grayblackwhite 已被移除,取而代之的是 neutral
- <UButton color="black" />
+ <UButton color="neutral" />

- <UButton color="gray" />
+ <UButton color="neutral" variant="subtle" />

- <UButton color="white" />
+ <UButton color="neutral" variant="outline" />
  • 您不能再在 color 属性中使用 Tailwind CSS 颜色,请改用新的别名。
- <UButton color="red" />
+ <UButton color="error" />
了解如何扩展设计系统以添加新的颜色别名。
  • app.config.ts 中的颜色配置已移至 colors 对象中。
export default defineAppConfig({
  ui: {
-   primary: 'green',
-   gray: 'cool'
+   colors: {
+     primary: 'green',
+     neutral: 'slate'
+   }
  }
})

更新的主题系统

Nuxt UI 组件现在使用 Tailwind Variants API 进行样式设置,这使得您通过 app.config.tsui 属性进行的所有覆盖都已过时。

export default defineAppConfig({
   ui: {
     button: {
-       font: 'font-bold',
-       default: {
-         size: 'md',
-         color: 'primary'
-       }
+       slots: {
+         base: 'font-medium'
+       },
+       defaultVariants: {
+         size: 'md',
+         color: 'primary'
+       }
     }
   }
})
  • 更新您的 ui 属性以使用新主题覆盖每个组件的插槽。
<template>
- <UButton :ui="{ font: 'font-bold' }" />
+ <UButton :ui="{ base: 'font-bold' }" />
</template>
我们无法在此处详细说明所有更改,但您可以在主题部分查看每个组件的主题。

重命名的组件

我们重命名了一些 Nuxt UI 组件以符合 Reka UI 的命名约定

v2v3
DividerSeparator
DropdownDropdownMenu
FormGroupFormField
范围Slider
ToggleSwitch
NotificationToast
VerticalNavigation带有 orientation="vertical"NavigationMenu
HorizontalNavigation带有 orientation="horizontal"NavigationMenu

以下是已重命名或移除的 Nuxt UI Pro 组件

v1v3
BlogList博客文章列表
ColorModeToggle颜色模式开关
DashboardCard已移除(请改用 PageCard
DashboardLayout仪表盘组
DashboardModal已移除(请改用 Modal
DashboardNavbarToggle仪表盘侧边栏切换
DashboardPage已移除
DashboardPanelContent已移除(请改用 #body 插槽)
DashboardPanelHandle仪表盘调整大小手柄
DashboardSection已移除(请改用 PageCard
DashboardSidebarLinks已移除(请改用 NavigationMenu
DashboardSlideover已移除(请改用 Slideover
FooterLinks已移除(请改用 NavigationMenu
HeaderLinks已移除(请改用 NavigationMenu
LandingCard已移除(请改用 PageCard
LandingCTA页面 CTA
LandingFAQ已移除(请改用 Accordion
LandingGrid已移除(请改用 PageGrid
LandingHero已移除(请改用 PageHero
LandingLogos页面标志
LandingSection页面节
LandingTestimonial已移除(请改用 PageCard
NavigationAccordion内容导航
NavigationLinks内容导航
NavigationTree内容导航
PageError错误
PricingCard定价方案
PricingGrid定价方案列表
PricingSwitch已移除(请改用 SwitchTabs

更改的组件

除了重命名的组件,组件 API 还有很多更改。让我们详细说明最重要的几点:

  • 为保持一致性,linksoptions 属性已重命名为 items
<template>
- <USelect :options="countries" />
+ <USelect :items="countries" />

- <UHorizontalNavigation :links="links" />
+ <UNavigationMenu :items="links" />
</template>
此更改影响以下组件:BreadcrumbHorizontalNavigationInputMenuRadioGroupSelectSelectMenuVerticalNavigation
  • 不同组件中的 click 字段已移除,取而代之的是原生的 Vue onClick 事件。
<script setup lang="ts">
const items = [{
  label: 'Edit',
-  click: () => {
+  onClick: () => {
    console.log('Edit')
  }
}]
</script>
此更改影响 Toast 组件以及所有具有 items 链接的组件,例如 NavigationMenuDropdownMenuCommandPalette 等。
  • 全局 ModalsSlideoversNotifications 组件已移除,取而代之的是 App 组件。
app.vue
<template>
+  <UApp>
+    <NuxtPage />
+  </UApp>
-  <UModals />
-  <USlideovers />
-  <UNotifications />
</template>
  • v-model:open 指令和 default-open 属性现在用于控制可见性。
<template>
- <UModal v-model="open" />
+ <UModal v-model:open="open" />
</template>
此更改影响以下组件:ContextMenuModalSlideover,并可用于控制 InputMenuSelectSelectMenuTooltip 的可见性。
  • 默认插槽现在用于触发器,内容位于 #content 插槽内(您无需使用 v-model:open 指令)。
<script setup lang="ts">
- const open = ref(false)
</script>

<template>
- <UButton label="Open" @click="open = true" />

- <UModal v-model="open">
+ <UModal>
+   <UButton label="Open" />

+   <template #content>
      <div class="p-4">
        <Placeholder class="h-48" />
      </div>
+   </template>
  </UModal>
</template>
此更改影响以下组件:ModalPopoverSlideoverTooltip
  • #content 插槽内添加了 #header#body#footer 插槽,就像 Card 组件一样。
<template>
- <UModal>
+ <UModal title="Title" description="Description">
-   <div class="p-4">
+   <template #body>
      <Placeholder class="h-48" />
+   </template>
-   </div>
  </UModal>
</template>
此更改影响以下组件:ModalSlideover

更改的组合式函数

  • useToast() 组合式函数的 timeout 属性已重命名为 duration
<script setup lang="ts">
const toast = useToast()

- toast.add({ title: 'Invitation sent', timeout: 0 })
+ toast.add({ title: 'Invitation sent', duration: 0 })
</script>
  • useModaluseSlideover 组合式函数已移除,取而代之的是更通用的 useOverlay 组合式函数。

一些重要的区别

  • useOverlay 组合式函数现在用于创建覆盖层实例。
  • 可以等待已打开的覆盖层返回其结果。
  • 覆盖层不能再通过 modal.close()slideover.close() 关闭,而是会自动关闭:当从打开的组件显式触发 close 事件时,或者当覆盖层自行关闭时(点击背景、按 ESC 键等)。
  • 要在父组件中捕获返回值,您必须显式地使用所需的值发出 close 事件。
<script setup lang="ts">
import { ModalExampleComponent } from '#components'

- const modal = useModal()
+ const overlay = useOverlay()

- modal.open(ModalExampleComponent)
+ const modal = overlay.create(ModalExampleComponent)
</script>

属性现在通过 props 属性传递。

<script setup lang="ts">
import { ModalExampleComponent } from '#components'

- const modal = useModal()
+ const overlay = useOverlay()

const count = ref(0)

- modal.open(ModalExampleComponent, {
-   count: count.value
- })
+ const modal = overlay.create(ModalExampleComponent, {
+   props: {
+     count: count.value
+   }
+ })
</script>

关闭模态框现在通过 close 事件完成。modal.open 方法现在返回一个实例,可用于等待模态框关闭时的结果。

<script setup lang="ts">
import { ModalExampleComponent } from '#components'

- const modal = useModal()
+ const overlay = useOverlay()

+ const modal = overlay.create(ModalExampleComponent)

- function openModal() {
-   modal.open(ModalExampleComponent, {
-     onSuccess() {
-       toast.add({ title: 'Success!' })
-     }
-   })
- }
+ async function openModal() {
+   const instance = modal.open(ModalExampleComponent, {
+     count: count.value
+   })
+
+   const result = await instance.result
+
+   if (result) {
+     toast.add({ title: 'Success!' })
+   }
+ }
</script>

更改的表单验证

  • 用于定位表单字段的错误对象属性已从 path 重命名为 name
<script setup lang="ts">
function validate(state: any): FormError[] {
  const errors = []
  if (!state.email) {
    errors.push({
-     path: 'email',
+     name: 'email',
      message: 'Required'
    })
  }
  if (!state.password) {
    errors.push({
-     path: 'password',
+     name: 'password',
      message: 'Required'
    })
  }
  return errors
}
</script>

此页面正在开发中,我们将定期改进它。