components

components/ 目录是您放置所有 Vue 组件的位置。

Nuxt会自动导入此目录中的任何组件(以及您可能使用的任何模块注册的组件)。

目录结构
-| components/
---| AppHeader.vue
---| AppFooter.vue
app.vue
<template>
  <div>
    <AppHeader />
    <NuxtPage />
    <AppFooter />
  </div>
</template>

组件名称

如果组件位于嵌套目录中,例如:

目录结构
-| components/
---| base/
-----| foo/
-------| Button.vue

……那么组件的名称将基于其自己的路径目录和文件名,移除重复的片段。因此,组件的名称将是:

<BaseFooButton />
为了清晰起见,我们建议组件的文件名与其名称相匹配。因此,在上面的例子中,您可以将 Button.vue 重命名为 BaseFooButton.vue

如果您希望仅基于其名称而不是路径自动导入组件,那么您需要设置 pathPrefix 选项为 false 使用扩展形式的配置对象:

nuxt.config.ts
export default 
defineNuxtConfig
({
components
: [
{
path
: '~/components',
pathPrefix
: false,
}, ], });

这将使用与Nuxt 2中使用相同的技术注册组件。例如,~/components/Some/MyComponent.vue 可以作为 <MyComponent> 使用,而不是 <SomeMyComponent>

动态组件

如果您想要使用 Vue <component :is="someComputedComponent"> 语法,则需要使用 resolveComponent 由 Vue 提供或直接从 #components 导入组件并将其传递给 is 属性。

例如:

pages/index.vue
<script setup lang="ts">
import { SomeComponent } from '#components'

const MyButton = resolveComponent('MyButton')
</script>

<template>
  <component :is="clickable ? MyButton : 'div'" />
  <component :is="SomeComponent" />
</template>
如果您正在使用 resolveComponent 来处理动态组件,请确保不插入任何东西,只是组件的名称,它必须是字符串而不是变量。
观看 Daniel Roe 关于 resolveComponent 的短片。

或者,虽然不推荐,您可以将所有组件全局注册,这将为您应用程序的所有组件创建异步块。

  export default defineNuxtConfig({
    components: {
+     global: true,
+     dirs: ['~/components']
    },
  })

您还可以选择性地将一些组件全局注册,方法是将它们放在 ~/components/global 目录中,或者使用 .global.vue 后缀在文件名中。如上所述,每个全局组件都是在单独的块中渲染的,因此请小心不要过度使用此功能。

global 选项也可以针对组件目录进行设置。

动态导入

要动态导入组件(也称为懒加载组件),您只需在组件名称前添加 Lazy 前缀。这对于只有在需要时才希望使用组件的情况特别有用。

通过使用 Lazy 前缀,您可以延迟加载组件代码直到正确的时刻,这对于优化您的JavaScript包大小非常有帮助。

pages/index.vue
<script setup lang="ts">
const show = ref(false)
</script>

<template>
  <div>
    <h1>山脉</h1>
    <LazyMountainsList v-if="show" />
    <button v-if="!show" @click="show = true">显示列表</button>
  </div>
</template>

直接导入

您也可以显式地从 #components 导入组件,如果您需要或需要绕过 Nuxt 的自动导入功能。

pages/index.vue
<script setup lang="ts">
import { NuxtLink, LazyMountainsList } from '#components'

const show = ref(false)
</script>

<template>
  <div>
    <h1>山脉</h1>
    <LazyMountainsList v-if="show" />
    <button v-if="!show" @click="show = true">显示列表</button>
    <NuxtLink to="/">首页</NuxtLink>
  </div>
</template>

自定义目录

默认情况下,仅扫描 ~/components 目录。如果您想添加其他目录,或者更改此目录子文件夹内组件的扫描方式,您可以在配置中添加其他目录:

nuxt.config.ts
export default 
defineNuxtConfig
({
components
: [
// ~/calendar-module/components/event/Update.vue => <EventUpdate /> {
path
: '~/calendar-module/components' },
// ~/user-module/components/account/UserDeleteDialog.vue => <UserDeleteDialog /> {
path
: '~/user-module/components',
pathPrefix
: false },
// ~/components/special-components/Btn.vue => <SpecialBtn /> {
path
: '~/components/special-components',
prefix
: 'Special' },
// 如果您的配置中有任何覆盖您希望应用于 `~/components` 子目录的覆盖,则非常重要, // 它需要在最后添加。 // // ~/components/Btn.vue => <Btn /> // ~/components/base/Btn.vue => <BaseBtn /> '~/components' ] })
任何嵌套目录都需要首先添加,因为它们是按顺序扫描的。

npm 包

如果您想根据 npm 包自动导入组件,您可以在 本地模块 中使用 addComponent 提供的 addComponent 钩子来注册它们。

import { 
addComponent
,
defineNuxtModule
} from '@nuxt/kit'
export default
defineNuxtModule
({
setup
() {
// import { MyComponent as MyAutoImportedComponent } from 'my-npm-package'
addComponent
({
name
: 'MyAutoImportedComponent',
export
: 'MyComponent',
filePath
: 'my-npm-package',
}) }, })

组件扩展

默认情况下,任何在 nuxt.config.tsextensions 键中指定的扩展文件都被视为组件。 如果您需要限制应注册为组件的文件扩展名,您可以使用组件目录的扩展形式及其 extensions 键:

nuxt.config.ts
export default 
defineNuxtConfig
({
components
: [
{
path
: '~/components',
extensions
: ['.vue'],
} ] })

客户端组件

如果组件是仅在客户端渲染的,则可以在组件上添加 .client 后缀。

目录结构
| components/
--| Comments.client.vue
pages/example.vue
<template>
  <div>
    <!-- 此组件仅在客户端渲染时才被渲染 -->
    <Comments />
  </div>
</template>
此功能仅在 Nuxt 的自动导入和 #components 导入时有效。如果显式从它们的真实路径导入这些组件,它们不会转换为仅客户端组件。
使用 .client 组件的渲染仅在挂载后发生。在 onMounted() 回调中使用 await nextTick() 以确保可以访问渲染的模板。
您也可以使用 <ClientOnly> 组件实现类似的结果。

服务器组件

服务器组件允许在您的客户端应用程序中渲染单个组件。即使您生成了一个静态网站,也可以在 Nuxt 中使用服务器组件。这意味着您可以构建混合动态组件、服务器端渲染的 HTML 甚至静态标记块的复杂站点。

服务器组件可以单独使用,也可以与 客户端组件 配对。

观看 Learn Vue 视频了解 Nuxt 服务器组件。
阅读 Daniel Roe 的指南了解 Nuxt 服务器组件。

独立的服务器组件

独立的服务器组件将始终在服务器上渲染,也称为岛屿组件。

当它们的属性更新时,这将导致一个网络请求,该请求将更新渲染的 HTML。

服务器组件目前是实验性的,为了使用它们,您需要在 nuxt.config 中启用 '组件岛屿' 特性:

nuxt.config.ts
export default 
defineNuxtConfig
({
experimental
: {
componentIslands
: true
} })

现在您可以在 Nuxt 模块中注册仅服务器组件,使用 .server 后缀和在应用程序的任何地方使用它们。

目录结构
-| components/
---| HighlightedMarkdown.server.vue
pages/example.vue
<template>
  <div>
    <!--
      此组件将自动在服务器上渲染,这意味着您的 Markdown 解析加高亮显示
      库不会包含在您的客户端包中。
     -->
    <HighlightedMarkdown markdown="# Headline" />
  </div>
</template>

服务器组件在内部使用 <NuxtIsland>,这意味着 lazy 属性和 #fallback 槽都传递给它。

服务器组件(和岛屿)必须有一个单一的根元素。(HTML 注释也被视为元素。)
在将岛屿嵌套在其他岛屿中时要小心,因为每个岛屿都会增加一些额外开销。
服务器组件(和岛屿)的特性,如插槽和客户端组件,仅在单个文件组件中可用。

客户组件在服务器组件内部

此功能需要 experimental.componentIslands.selectiveClient 在您的配置中为真。

您可以通过在组件上设置 nuxt-client 属性来部分地水合组件,您希望它在客户端加载和水分化。

components/ServerWithClient.vue
<template>
  <div>
    <HighlightedMarkdown markdown="# Headline" />
    <!-- Counter 将只在浏览器中加载和水分化 -->
    <Counter nuxt-client :count="5" />
  </div>
</template>
这仅在服务器组件内部有效。由于它们在服务器上渲染,因此它们不是交互式的,除非 experimental.componentIsland.selectiveClient 设置为 'deep',并且它们在客户端渲染时不是交互式的。

服务器组件上下文

当渲染一个服务器或岛屿组件时,<NuxtIsland> 会发起一个 fetch 请求,该请求以 NuxtIslandResponse 返回。(如果您在服务器上渲染,这是内部请求,或者如果您是客户端导航,您可以在网络标签中看到它。)

这意味着:

  • 一个新的 Vue 应用将在服务器上创建,以创建 NuxtIslandResponse
  • 一个新的 '岛屿上下文' 将在渲染组件时创建。
  • 您不能访问岛屿上下文,也不能访问岛屿上下文。换句话说,服务器组件或岛屿是 隔离 的。
  • 您的插件将再次运行,当渲染岛屿时,除非他们有 env: { islands: false } 设置为真(您可以在对象语法插件中这样做)。

在岛屿组件内部,您可以通过 nuxtApp.ssrContext.islandContext 访问它的岛屿上下文。请注意,由于岛屿组件仍然是实验性的,这个上下文的格式可能会改变。

插槽可以交互式,并且被包裹在 <div> 带有 display: contents;

与一个客户端组件配对

在这种情况下,.server + .client 组件是组件的两个“半”,并且可以用于高级用例,在服务器和客户端实现组件的分离实现。

目录结构
-| components/
---| Comments.client.vue
---| Comments.server.vue
pages/example.vue
<template>
  <div>
    <!-- 此组件将在服务器上渲染 Comments.server,然后一旦浏览器中挂载,Comments.client -->
    <Comments />
  </div>
</template>

内置 Nuxt 组件

Nuxt 提供了一些组件,包括 <ClientOnly><DevOnly>。您可以在 API 文档中阅读更多关于它们的信息。

Read more in Docs > API.

库作者

创建一个具有自动树剪枝和组件注册的 Vue 组件库非常容易。✨

您可以使用 components:dirs 钩子扩展目录列表,而无需在 Nuxt 模块中要求用户配置。

想象一个目录结构如下:

目录结构
-| node_modules/
---| awesome-ui/
-----| components/
-------| Alert.vue
-------| Button.vue
-----| nuxt.js
-| pages/
---| index.vue
-| nuxt.config.js

然后,在 awesome-ui/nuxt.js 中,您可以使用 components:dirs 钩子:

import { 
defineNuxtModule
,
createResolver
} from '@nuxt/kit'
export default
defineNuxtModule
({
hooks
: {
'components:dirs': (
dirs
) => {
const {
resolve
} =
createResolver
(import.meta.
url
)
// 添加 ./components 目录到列表
dirs
.
push
({
path
:
resolve
('./components'),
prefix
: 'awesome'
}) } } })

就是这样!现在在你的项目中,你可以把你的 UI 库作为 Nuxt 模块在你的 nuxt.config 文件中导入:

nuxt.config.ts
export default 
defineNuxtConfig
({
modules
: ['awesome-ui/nuxt']
})

...并且直接在你的 pages/index.vue 中使用模块组件(带有 awesome- 前缀):

<template>
  <div>
    我的 <AwesomeButton>UI 按钮</AwesomeButton>    <awesome-alert>这是一个警告!</awesome-alert>
  </div>
</template>

它将自动导入组件,只有在使用时才会导入,并且在更新您的组件时也支持 HMR node_modules/awesome-ui/components/

Read and edit a live example in Docs > Examples > Features > Auto Imports.