components
Nuxt 会自动导入该目录中的所有组件(以及您可能使用的任何模块注册的组件)。
| components/
--| AppHeader.vue
--| AppFooter.vue
<template>
<div>
<AppHeader />
<NuxtPage />
<AppFooter />
</div>
</template>
组件名称
如果您在嵌套目录中有一个组件,例如:
| components/
--| base/
----| foo/
------| Button.vue
... 那么组件的名称将基于其自身的路径目录和文件名,重复的部分将被删除。因此,组件的名称将是:
<BaseFooButton />
Button.vue
重命名为 BaseFooButton.vue
。如果您希望仅根据组件名称而不是路径自动导入组件,则需要使用扩展形式的配置对象将 pathPrefix
选项设置为 false
:
export default defineNuxtConfig({
components: [
{
path: '~/components',
+ pathPrefix: false,
},
],
});
这将使用与 Nuxt 2 中使用的相同策略注册组件。例如,~/components/Some/MyComponent.vue
将可用作 <MyComponent>
而不是 <SomeMyComponent>
。
动态组件
如果您想使用 Vue 的 <component :is="someComputedComponent">
语法,您需要使用 Vue 提供的 resolveComponent
辅助函数,或直接从 #components
导入组件并将其传递给 is
属性。
例如:
<script setup lang="ts">
import { SomeComponent } from '#components'
const MyButton = resolveComponent('MyButton')
</script>
<template>
<component :is="clickable ? MyButton : 'div'" />
<component :is="SomeComponent" />
</template>
resolveComponent
处理动态组件,请确保仅插入组件名称,它必须是一个字符串而不是一个变量。另外,虽然不推荐,但您可以全局注册所有组件,这将为所有组件创建异步块,并使它们在整个应用程序中可用。
export default defineNuxtConfig({
components: {
+ global: true,
+ dirs: ['~/components']
},
})
您还可以通过将它们放置在 ~/components/global
目录中来有选择地全局注册一些组件。
global
选项也可以针对每个组件目录进行设置。动态导入
要动态导入组件(也称为延迟加载组件),您只需将 Lazy
前缀添加到组件的名称中。如果组件不总是需要,这特别有用。
通过使用 Lazy
前缀,您可以将组件代码的加载延迟到正确的时机,这有助于优化 JavaScript 包的大小。
<script setup>
const show = ref(false)
</script>
<template>
<div>
<h1>Mountains</h1>
<LazyMountainsList v-if="show" />
<button v-if="!show" @click="show = true">Show List</button>
</div>
</template>
直接导入
如果需要绕过 Nuxt 的自动导入功能,您还可以从 #components
直接导入组件。
<script setup lang="ts">
import { NuxtLink, LazyMountainsList } from '#components'
const show = ref(false)
</script>
<template>
<div>
<h1>Mountains</h1>
<LazyMountainsList v-if="show" />
<button v-if="!show" @click="show = true">Show List</button>
<NuxtLink to="/">Home</NuxtLink>
</div>
</template>
自定义目录
默认情况下,只会扫描 ~/components
目录。如果您想添加其他目录,或更改在该目录的子文件夹中如何扫描组件,您可以将其他目录添加到配置中:
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'
]
})
组件扩展名
默认情况下,任何具有在 nuxt.config.ts 的 extensions 键中指定的扩展名 的文件都被视为组件。 如果您需要限制应注册为组件的文件扩展名,可以使用组件目录声明的扩展名键的扩展形式:
export default defineNuxtConfig({
components: [
{
path: '~/components',
+ extensions: ['.vue'],
}
]
})
客户端组件
如果一个组件只在客户端渲染,您可以在组件名后添加 .client
后缀。
| components/
--| Comments.client.vue
<template>
<div>
<!-- 此组件仅在客户端渲染 -->
<Comments />
</div>
</template>
#components
导入。从实际路径显式导入这些组件不会将它们转换为仅客户端组件。.client
组件仅在挂载后才会渲染。要在 onMounted()
的回调中访问渲染的模板,请在 onMounted()
钩子的回调中添加 await nextTick()
。服务器端组件
服务器端组件允许在客户端应用程序中进行单独组件的服务器渲染。即使您正在生成静态站点,也可以在 Nuxt 中使用服务器端组件。这使得可以构建复杂的站点,混合动态组件、服务器渲染的 HTML 甚至静态标记的块。
即使在服务器端渲染上,服务器端组件也可以单独使用或与客户端组件配对使用。
独立服务器端组件
独立服务器端组件始终在服务器上渲染,也被称为 Islands 组件。
当其 props 更新时,这将导致网络请求,以原地更新渲染的 HTML。
服务器端组件目前处于实验阶段,为了使用它们,您需要在 nuxt.config 中启用 'component islands' 功能:
export default defineNuxtConfig({
experimental: {
componentIslands: true
}
})
现在,您可以使用 .server
后缀注册仅服务器端的组件,并在应用程序的任何位置自动使用它们。
| components/
--| HighlightedMarkdown.server.vue
<template>
<div>
<!--
这将自动在服务器上渲染,意味着您的 markdown 解析和高亮
库不会包含在客户端捆绑包中。
-->
<HighlightedMarkdown markdown="# Headline" />
</div>
</template>
仅服务器端组件在幕后使用了 <NuxtIsland>
,这意味着 lazy
属性和 #fallback
插槽都传递给它。
服务器端组件上下文
在渲染服务器端组件或岛屿组件时,<NuxtIsland>
进行了一个提取请求,该请求返回一个 NuxtIslandResponse
。(如果在服务器上渲染,则为内部请求,如果在客户端导航时渲染,则为可以在网络选项卡中查看的请求。)
这意味着:
- 将在服务器端创建一个新的 Vue 应用程序以创建
NuxtIslandResponse
。 - 在渲染组件时,将创建一个新的“岛屿上下文”。
- 您无法从应用程序的其余部分访问“岛屿上下文”,也无法从岛屿组件中访问应用程序的其余部分的上下文。换句话说,服务器端组件或岛屿与应用程序的其余部分是_隔离_的。
- 在岛屿组件中,您可以通过
nuxtApp.ssrContext.islandContext
访问岛屿上下文。请注意,虽然岛屿组件仍然标记为实验性的,但此上下文的格式可能会发生变化。 - 插槽可以是交互式的,并且在
<div>
中使用display: contents;
进行包装。 ::
配对的客户端组件
在这种情况下,.server
+ .client
组件是组件的两个“半部分”,可以在服务器端和客户端分别使用高级用例来分别实现组件。
| components/
--| Comments.client.vue
--| Comments.server.vue
<template>
<div>
<!-- 这个组件将在服务器端渲染 Comments.server,然后在浏览器中挂载后渲染 Comments.client -->
<Comments />
</div>
</template>
<ClientOnly>
组件
Nuxt 提供了 <ClientOnly>
组件,用于仅在客户端渲染组件。
<template>
<div>
<Sidebar />
<ClientOnly>
<!-- 此组件仅在客户端渲染 -->
<Comments />
</ClientOnly>
</div>
</template>
在 <ClientOnly>
在客户端渲染之前,使用插槽作为回退。
<template>
<div>
<Sidebar />
<!-- 这将在服务器端渲染 "span" 元素 -->
<ClientOnly fallbackTag="span">
<!-- 此组件仅在客户端渲染 -->
<Comments />
<template #fallback>
<!-- 这将在服务器端渲染 -->
<p>Loading comments...</p>
</template>
</ClientOnly>
</div>
</template>
<DevOnly>
组件
Nuxt 提供了 <DevOnly>
组件,仅在开发环境中渲染组件。
该内容不会包含在生产构建中,并进行了 tree-shaking。
<template>
<div>
<Sidebar />
<DevOnly>
<!-- 仅在开发环境中渲染此组件 -->
<LazyDebugBar />
<!-- 如果您需要在生产环境中进行替换 -->
<!-- 请确保使用 `nuxt preview` 进行测试 -->
<template #fallback>
<div><!-- 用于 flex.justify-between 的空 div --></div>
</template>
</DevOnly>
</div>
</template>
<NuxtClientFallback>
组件
Nuxt 提供了 <NuxtClientFallback>
组件,如果其任何子组件在 SSR 中触发错误,则在客户端渲染其内容。
您可以指定 fallbackTag
,以便在服务器端无法渲染时渲染特定的标记。
<template>
<div>
<Sidebar />
<!-- 此组件将在客户端渲染 -->
<NuxtClientFallback fallback-tag="span">
<Comments />
<BrokeInSSR />
</NuxtClientFallback>
</div>
</template>
库作者
使用自动摇树和组件注册创建 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
文件中导入:
export default defineNuxtConfig({
modules: ['awesome-ui/nuxt']
})
... 并在我们的 pages/index.vue
中直接使用模块组件(以 awesome-
为前缀):
<template>
<div>
我的 <AwesomeButton>UI 按钮</AwesomeButton>!
<awesome-alert>这是一个提示!</awesome-alert>
</div>
</template>
它将仅在使用时自动导入组件,并在 node_modules/awesome-ui/components/
中更新组件时支持 HMR。