迁移到 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 prop 中的 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 prop 中使用 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 prop 进行的所有覆盖都过时了。

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

重命名的组件

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

v2v3
DividerSeparator
DropdownDropdownMenu
FormGroupFormField
RangeSlider
ToggleSwitch
NotificationToast
VerticalNavigationNavigationMenu 带有 orientation="vertical"
HorizontalNavigationNavigationMenu 带有 orientation="horizontal"

以下是已重命名或移除的 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 prop 已重命名为 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 prop 一起用于控制可见性
<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 prop 已重命名为 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 组合式函数现在用于创建 overlay 实例
  • 打开的 overlay 可以等待其结果
  • Overlay 不能再通过 modal.close()slideover.close() 关闭,而是自动关闭:要么当从打开的组件显式触发 close 事件,要么当 overlay 自身关闭时(点击背景、按 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 现在通过 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>

更改的表单验证

  • 用于定位表单字段的 error 对象属性已从 path 重命名为 name
<script setup lang="ts">
const 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>

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