Loading... # nuxt3目录结构详解 在 Nuxt.js 3 中,一个应用程序的文件夹结构具有一定的规范性。以下是 Nuxt.js 3 的文件夹结构及其用途的详细解释: ## .nuxt 目录 Nuxt 使用`.nuxt/`目录在开发中生成您的Vue应用程序。 你不应该碰里面的任何文件,因为整个目录将在运行`nuxt dev`时重新创建。 ## .output 目录 Nuxt在为生产构建应用程序时创建`.output`目录。 你不应该碰里面的任何文件,因为整个目录将在运行`nuxt build`时重新创建。 使用此目录将Nuxt应用程序部署到生产环境。 ## assets 目录 `assets/` 目录用于添加构建工具(webpack或Vite)将处理的所有网站资产。 该目录通常包含以下类型的文件: - Stylesheets (CSS, SASS, etc.) - Fonts - Images 它不会从[`public/`](https://nuxt.com/docs/guide/directory-structure/public)目录中提供。 如果你想从服务器上提供资产,我们建议看一下[`public/`](https://nuxt.com/docs/guide/directory-structure/public)目录 ## Components 目录 `components/`目录是您放置所有Vue组件的地方,然后可以在您的页面或其他组件中导入这些组件([了解更多](https://vuejs.org/guide/essentials/component-basics.html#components-basics)) Nuxt自动导入你的`components`目录中的任何组件(以及你可能正在使用的任何模块注册的组件)。 ``` | components/ --| TheHeader.vue --| TheFooter.vue ``` ```vue layouts/default.vue <template> <div> <TheHeader /> <slot /> <TheFooter /> </div> </template> ``` ### Custom directories 默认情况下,只扫描~/components目录。如果要添加其他目录,或更改在该目录的子文件夹中扫描组件的方式,可以向配置中添加其他目录: ```javascript nuxt.config.ts export default defineNuxtConfig({ components: [ { path: '~/components/special-components', prefix: 'Special' }, '~/components' ] }) ``` > Any nested directories need to be added first as they are scanned in order. > > 任何嵌套的目录都需要在按顺序扫描时先添加。 ### Component extensions 默认情况下,在`nuxt.config.ts`的扩展键中指定了扩展名的任何文件都被视为组件。如果需要限制应注册为组件的文件扩展名,可以使用组件目录声明的扩展形式及其扩展键: ```javascript export default defineNuxtModule({ components: [ { path: '~/components', + extensions: ['.vue'], } ] }) ``` ### Component Names 如果你在嵌套目录中有一个组件,例如: ``` | 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>`。 ### Dynamic Components 如果你想使用Vue `<component :is="someComputedComponent">`语法,那么你将需要使用Vue提供的`resolveComponent`辅助方法。 例如: ```vue <template> <component :is="clickable ? MyButton : 'div'" /> </template> <script setup> const MyButton = resolveComponent('MyButton') </script> ``` 如果你正在使用`resolveComponent`来处理动态组件,请确保除了组件名称之外不插入任何内容,组件名称必须是字符串而不是变量。 或者,尽管不推荐,您可以全局注册所有组件,这将为所有组件创建异步块,并使它们在整个应用程序中可用。 ```vue export default defineNuxtConfig({ components: { + global: true, + dirs: ['~/components'] }, }) ``` 您还可以通过将某些组件放在 `~/components/global`目录中来选择性地全局注册它们。 `global`选项也可以为每个组件目录设置。 ### Dynamic Imports 要动态导入一个组件(也称为惰性加载组件),你所需要做的就是在组件名称前添加`Lazy`前缀。 ``` layouts/default.vue <template> <div> <TheHeader /> <slot /> <LazyTheFooter /> </div> </template> ``` 如果不总是需要该组件,这尤其有用。通过使用`Lazy`前缀,你可以延迟加载组件代码,直到合适的时刻,这有助于优化你的JavaScript包大小。 ``` pages/index.vue <template> <div> <h1>Mountains</h1> <LazyMountainsList v-if="show" /> <button v-if="!show" @click="show = true">Show List</button> </div> </template> <script> export default { data() { return { show: false } } } </script> ``` ### Direct Imports 如果你想要或需要绕过Nuxt的自动导入功能,你也可以显式地从`#components`导入组件。 ```vue pages/index.vue <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> <script setup> import { NuxtLink, LazyMountainsList } from '#components' const show = ref(false) </script> ``` ### ClientOnly Component Nuxt 提供了`<ClientOnly>`组件,目的是只在客户端呈现一个组件。若要只在客户端导入组件,请在客户端插件中注册该组件。 ```vue pages/example.vue <template> <div> <Sidebar /> <ClientOnly> <!-- this component will only be rendered on client-side --> <Comments /> </ClientOnly> </div> </template> ``` 使用槽位作为回退,直到`<ClientOnly>`挂载到客户端。 ```vue pages/example.vue <template> <div> <Sidebar /> <!-- This renders the "span" element on the server side --> <ClientOnly fallbackTag="span"> <!-- this component will only be rendered on client side --> <Comments /> <template #fallback> <!-- this will be rendered on server side --> <p>Loading comments...</p> </template> </ClientOnly> </div> </template> ``` ### .client Components 如果组件只能在客户端呈现,则可以添加`.client` 后缀到您的组件。 ``` | components/ --| Comments.client.vue ``` ```vue pages/example.vue <template> <div> <!-- this component will only be rendered on client side --> <Comments /> </div> </template> ``` 此功能仅适用于Nuxt自动导入和 `#components`导入。从它们的实际路径显式导入这些组件并不会将它们转换为仅针对客户端的组件。 `.client` 组件只有在被挂载后才被渲染。要使用`onMounted()`访问呈现的模板,在 `onMounted()` 钩子的回调中添加`await nextTick()`。 ### .server Components `.server` 组件既可以单独使用,也可以与`.client`组件配对使用。 ### Standalone server components Standalone server components will always be rendered on the server. When their props update, this will result in a network request that will update the rendered HTML in-place. > A video made by [LearnVue](https://go.learnvue.co/) for the Nuxt documentation. Server components are currently experimental and in order to use them, you need to enable the 'component islands' feature in your nuxt.config: ``` nuxt.config.ts export default defineNuxtConfig({ experimental: { componentIslands: true } }) ``` Now you can register server-only components with the `.server` suffix and use them anywhere in your application automatically. ``` | components/ --| HighlightedMarkdown.server.vue ``` ``` pages/example.vue <template> <div> <!-- this will automatically be rendered on the server, meaning your markdown parsing + highlighting libraries are not included in your client bundle. --> <HighlightedMarkdown markdown="# Headline" /> </div> </template> ``` Slots are not supported by server components in their current state of development. ### Paired with a .client component 在这种情况下,`.server` + `.client` 组件是组件的两部分,可以在高级用例中用于服务器端和客户端组件的独立实现。 ``` | components/ --| Comments.client.vue --| Comments.server.vue ``` ``` pages/example.vue <template> <div> <!-- this component will render Comments.server server-side then Comments.client once mounted in client-side --> <Comments /> </div> </template> ``` 组件的客户端部分能够为服务器呈现的HTML'hydrate'是很重要的。也就是说,它应该在初始加载时呈现相同的HTML,否则您将遇到水合不匹配的情况。 ### DevOnly Component Nuxt提供了`<DevOnly>` 组件,只在开发过程中渲染组件。 这些内容将不包含在生产构建和 tree-shaken中。 ```vue pages/example.vue <template> <div> <Sidebar /> <DevOnly> <!-- this component will only be rendered during development --> <LazyDebugBar /> </DevOnly> </div> </template> ``` ### Library Authors 制作具有自动摇树和组件注册功能的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 } from '@nuxt/kit' import { fileURLToPath } from 'node:url' export default defineNuxtModule({ hooks: { 'components:dirs'(dirs) { // Add ./components dir to the list dirs.push({ path: fileURLToPath(new URL('./components', import.meta.url)), prefix: 'awesome' }) } } }) ``` 就是这样!现在在你的项目中,你可以在你的`nuxt.config`文件中导入你的UI库作为Nuxt模块: ``` export default { modules: ['awesome-ui/nuxt'] } ``` 并直接在我们的`pages/index.vue`中使用模块组件(前缀为`awesome-): ``` <template> <div> My <AwesomeButton>UI button</AwesomeButton>! <awesome-alert>Here's an alert!</awesome-alert> </div> </template> ``` It will automatically import the components only if used and also support HMR when updating your components in `node_modules/awesome-ui/components/`. ## Composables 目录 Nuxt 3使用`composables/`目录使用[auto-imports](https://nuxt.com/docs/guide/concepts/auto-imports)自动将Vue组合导入到应用中! 在底层,Nuxt自动生成文件`.nuxt/imports.d.ts`来声明类型。 注意,为了让Nuxt生成类型,你必须运行`nuxi prepare`, `nuxi dev` 或 `nuxi build`。如果你在没有运行开发服务器的情况下创建了一个可组合对象,TypeScript会抛出一个错误,比如`Cannot find name 'useBar'.` ### Usage **Method 1:** Using named export ```typescript composables/useFoo.ts export const useFoo = () => { return useState('foo', () => 'bar') } ``` **Method 2:** Using default export ```typescript composables/use-foo.ts or composables/useFoo.ts // It will be available as useFoo() (camelCase of file name without extension) export default function () { return useState('foo', () => 'bar') } ``` **用法:** 你现在可以在 `.js`, `.ts` 和 `.vue` 文件中使用自动导入组合 ```vue app.vue <template> <div> {{ foo }} </div> </template> <script setup> const foo = useFoo() </script> ``` ### 示例 #### Nested Composables 你可以在使用自动导入的另一个可组合对象中使用一个可组合对象: ```typescript composables/test.ts export const useFoo = () => { const nuxtApp = useNuxtApp() const bar = useBar() } ``` #### 访问插件注入 你可以从可组合文件中访问[plugin injections](https://nuxt.com/docs/guide/directory-structure/plugins#automatically-providing-helpers) ```typescript composables/test.ts export const useHello = () => { const nuxtApp = useNuxtApp() return nuxtApp.$hello } ``` ### 如何扫描文件 Nuxt只扫描 `composables/` 目录的顶层文件,例如: ``` composables | - index.ts // scanned | - useFoo.ts // scanned | - nested | --- utils.ts // not scanned ``` 只有`composables/index.ts` 和 `composables/useFoo.ts`会被搜索导入。 为了让自动导入工作于嵌套模块,你可以重新导出它们(推荐)或配置扫描器包含嵌套目录: **示例:** 从`composables/index.ts`中重新导出您需要的组合的文件: ```typescript composables/index.ts // Enables auto import for this export export { utils } from './nested/utils.ts' ``` **示例:** 扫描`composables/`文件夹内的嵌套目录: ```typescript nuxt.config.ts export default defineNuxtConfig({ imports: { dirs: [ // Scan top-level modules 'composables', // ... or scan modules nested one level deep with a specific name and file extension 'composables/*/index.{ts,js,mjs,mts}', // ... or scan all modules within given directory 'composables/**' ] } }) ``` ## Content 目录 [Nuxt Content模块](https://content.nuxtjs.org/)读取项目中的`content/` 目录并解析`.md`, `.yml`, `.csv` and `.json`文件为您的应用程序创建一个基于文件的CMS。 - 使用内置组件渲染您的内容。 - 使用类似mongodb的API查询您的内容。 - 使用带有MDC语法的Markdown文件中的Vue组件。 - 自动生成导航。 ### 开始 #### 安装 在项目中安装 `@nuxt/content`模块: ``` yarn add --dev @nuxt/content 或 npm install --save-dev @nuxt/content 或 pnpm add -D @nuxt/content ``` Then, add `@nuxt/content` to the `modules` section of `nuxt.config.ts`: ```typescript nuxt.config.ts export default defineNuxtConfig({ modules: [ '@nuxt/content' ], content: { // https://content.nuxtjs.org/api/configuration } }) ``` #### 创建内容 Place your markdown files inside the `content/` directory in the root directory of your project: ```markdown content/index.md # Hello Content ``` 模块自动加载并解析它们。 #### 渲染页面 要呈现内容页面,使用 `ContentDoc`组件添加一个[catch-all路由](https://nuxt.com/docs/guide/directory-structure/pages/#catch-all-route): ```vue pages/[...slug].vue <template> <main> <ContentDoc /> </main> </template> ``` ## Layouts 目录 Nuxt提供了一个可定制的布局框架,可以在整个应用程序中使用,非常适合将常见的UI或代码模式提取到可重用的布局组件中。 布局放在`layouts/`目录中,使用时将通过异步导入自动加载。布局是通过添加`<NuxtLayout>`到您的`app.vue`,或者设置一个`layout`属性作为页面元数据的一部分(如果你使用`~/pages`集成),或者手动指定它作为`<NuxtLayout>`的一个prop。(**注意**: 布局名称被规范化为串格式,因此 `someLayout` 变成`some-layout`。) 如果你的应用只有一个布局,我们建议使用[app.vue](https://nuxt.com/docs/guide/directory-structure/app)。 不像其他组件,你的布局必须有一个根元素,以允许Nuxt在布局变化之间应用过渡-这个根元素不能是`<slot />`。 ### 启用默认布局 Add a `~/layouts/default.vue`: ```vue layouts/default.vue <template> <div> 一些在所有页面共享的默认布局 <slot /> </div> </template> ``` 在布局文件中,布局的内容将加载在`<slot />`中,而不是使用特殊的组件。 如果你使用`app.vue`你还需要添加 `<NuxtLayout>`: ```vue app.vue <template> <NuxtLayout> some page content </NuxtLayout> </template> ``` ### 设置另一种布局 ``` -| layouts/ ---| default.vue ---| custom.vue ``` 你可以像这样直接覆盖默认布局: ```vue app.vue <template> <NuxtLayout :name="layout"> <NuxtPage /> </NuxtLayout> </template> <script setup> // 您可以根据API调用或登录状态来选择此选项 const layout = "custom"; </script> ``` 或者,你可以像这样覆盖默认的每页布局: ```vue pages/index.vue <script> // This will work in both `<script setup>` and `<script>` definePageMeta({ layout: "custom", }); </script> ``` ```vue app.vue <template> <NuxtLayout> <NuxtPage /> </NuxtLayout> </template> ``` ```vue layouts/custom.vue <template> <div> Some *custom* layout <slot /> </div> </template> ``` ```vue layouts/default.vue <template> <div> A *default* layout <slot /> </div> </template> ``` 了解更多关于[定义页面元数据](https://nuxt.com/docs/guide/directory-structure/pages#page-metadata)的信息。 ### 动态更改布局 还可以为布局使用ref或computed属性。 ```vue <template> <div> <button @click="enableCustomLayout">Update layout</button> </div> </template> <script setup> function enableCustomLayout () { setPageLayout('custom') } definePageMeta({ layout: false, }); </script> ``` ### 在每页的基础上重写布局 如果您正在使用`~/pages`集成,您可以通过设置`layout: false`,然后在页面内使用`<NuxtLayout>`组件来获得完全控制。 ```vue pages/index.vue <template> <div> <NuxtLayout name="custom"> <template #header> Some header template content. </template> The rest of the page </NuxtLayout> </div> </template> <script setup> definePageMeta({ layout: false, }); </script> ``` ```vue layouts/custom.vue <template> <div> <header> <slot name="header"> Default header content </slot> </header> <main> <slot /> </main> </div> </template> ``` ## Middleware 目录 Nuxt提供了一个可定制的**路由中间件**框架,可以在整个应用程序中使用,非常适合在导航到特定路由之前提取想要运行的代码。 路由中间件运行在Nuxt应用程序的Vue部分中。尽管名称相似,但它们与服务器中间件完全不同,服务器中间件运行在应用程序的Nitro服务器部分中。 路由中间件有三种: 1. 匿名(或内联)路由中间件,直接在使用它们的页面中定义。 2. 命名路由中间件,放置在`middleware/` 目录中,在页面上使用时会通过异步导入自动加载。(**注意**:路由中间件名称被规范化为串串形式,因此`someMiddleware` 变成 `some-middleware`。) 3. 全局路由中间件,放置在 `middleware/`目录中(带有`.global`后缀),并将在每次路由更改时自动运行。 前两种路由中间件可以[在`definePageMeta`中定义](https://nuxt.com/docs/guide/directory-structure/pages)。 ### 格式 路由中间件是导航守卫,它接收当前路由和下一个路由作为参数。 ```typescript export default defineNuxtRouteMiddleware((to, from) => { if (to.params.id === '1') { return abortNavigation() } return navigateTo('/') }) ``` Nuxt提供了两个全局可用的辅助函数,它们可以直接从中间件返回: 1. `navigateTo (to: RouteLocationRaw | undefined | null, options?: { replace: boolean, redirectCode: number, external: boolean )` - 在插件或中间件中重定向到给定的路由。也可以直接调用它来执行页面导航。 2. `abortNavigation (err?: string | Error)` - 终止导航,并显示一条可选的错误消息。 不像[vue-router](https://router.vuejs.org/guide/advanced/navigation-guards.html#global-before-guards)中的导航守卫,第三个`next()`参数不会被传递,重定向或路由取消是通过从中间件返回值来处理的。可能的返回值有: - nothing - 不会阻塞导航,并且会移动到下一个中间件功能(如果有的话),或者完成路由导航 - `return navigateTo('/')` or `return navigateTo({ path: '/' })` - 重定向到给定的路径,并将重定向代码设置为[`302` Found](https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/302),如果重定向发生在服务器端 - `return navigateTo('/', { redirectCode: 301 })` - 重定向到给定的路径,并将重定向代码设置为[`301` Moved permanent](https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/301),如果重定向发生在服务器端 - `return abortNavigation()` - 停止当前导航 - `return abortNavigation(error)` - 拒绝有错误的当前导航 我们建议使用上面的帮助函数来执行重定向或停止导航。[vue-router](https://router.vuejs.org/guide/advanced/navigation-guards.html#global-before-guards)中描述的其他可能的返回值可能可以工作,但将来可能会有破坏性的更改。 ### 动态添加中间件 可以使用`addRouteMiddleware()`辅助函数手动添加全局或命名路由中间件,例如从插件中添加。 ```typescript export default defineNuxtPlugin(() => { addRouteMiddleware('global-test', () => { console.log('这个全局中间件是在一个插件中添加的,将在每次路由更改时运行') }, { global: true }) addRouteMiddleware('named-test', () => { console.log('这个命名中间件是在插件中添加的,它将覆盖任何同名的现有中间件') }) }) ``` ### 示例:命名路由中间件 ``` -| middleware/ ---| auth.ts ``` 在页面文件中,可以引用这个路由中间件 ```vue <script setup> definePageMeta({ middleware: ["auth"] // or middleware: 'auth' }) </script> ``` 现在,在导航到该页面完成之前, `auth` 路由中间件将运行。 ## Node modules 目录 包管理器([`npm`](https://docs.npmjs.com/cli/v7/commands/npm)或[`yarn`](https://yarnpkg.com/)或[`pnpm`](https://pnpm.io/cli/install))创建`node_modules/`目录来存储项目的依赖项。 ## Pages 目录 Nuxt提供了一个基于文件的路由,在您的web应用程序中使用[Vue Router](https://router.vuejs.org/)在底层创建路由。 这个目录是 **可选的** ,这意味着如果你只使用[`app.vue`](https://nuxt.com/docs/guide/directory-structure/app), [`vue-router`](https://router.vuejs.org/)不会被包括在内(除非你在`nuxt.config`中设置了`pages: true`或者有一个[`app/router.options.ts`](https://nuxt.com/docs/guide/directory-structure/pages#router-options)),减少应用程序的包大小。 ### 使用 页面是Vue组件,可以使用 `.vue`, `.js`, `.jsx`, `.ts` or `.tsx`扩展名 ``` pages/index.vue <template> <h1>Index page</h1> </template> ``` ```typescript // https://vuejs.org/guide/extras/render-function.html export default defineComponent({ render () { return h('h1', 'Index page') } }) ``` ```tsx // https://nuxt.com/docs/examples/advanced/jsx // https://vuejs.org/guide/extras/render-function.html#jsx-tsx export default defineComponent({ render () { return <h1>Index page</h1> } }) ``` The `pages/index.vue` file will be mapped to the `/` route of your application. 如果你正在使用[app.vue](https://nuxt.com/docs/guide/directory-structure/app),确保使用`<NuxtPage/>`组件来显示当前页面: ```vue app.vue <template> <div> <!-- Markup shared across all pages, ex: NavBar --> <NuxtPage /> </div> </template> ``` Pages**必须有一个根元素**,以允许页面之间的路由transitions。(HTML注释也被认为是元素。) 这意味着当路由被服务器渲染或静态生成时,您将能够正确地看到它的内容,但是当您在客户端导航期间导航到该路由时,路由之间的转换将失败,您将看到路由将不会被渲染。 下面是一些例子来说明只有一个根元素的页面是什么样子的: ```vue pages/working.vue <template> <div> <!-- 这个页面正确地只有一个根元素 --> Page content </div> </template> ``` ```vue pages/bad-1.vue <template> <!-- 由于此注释,当客户端导航期间路由更改时,此页面将不会呈现 --> <div>Page content</div> </template> ``` ```vue pages/bad-2.vue <template> <div>This page</div> <div>有多个根元素</div> <div>并且不会在客户端导航期间的路由更改时呈现</div> </template> ``` ### 动态 Routes 如果您将任何内容放在方括号内,它将被转换为[dynamic route](https://router.vuejs.org/guide/essentials/dynamic-matching.html)参数。您可以在文件名或目录中混合和匹配多个参数,甚至是非动态文本。 If you want a parameter to be optional, you must enclose it in double square brackets - for example, `~/pages/[[slug]]/index.vue` or `~/pages/[[slug]].vue` will match both `/` and `/test`. 如果您希望参数是 *可选的* ,则必须将其括在双方括号中——例如,`~/pages/[[slug]]/index.vue` 或 `~/pages/[[slug]].vue`将同时匹配 `/` 和 `/test`。 ### 示例 ``` -| pages/ ---| index.vue ---| users-[group]/ -----| [id].vue ``` 根据上面的例子,你可以通过`$route`对象访问组件中的 group/id: ```vue pages/users-[group]/[id].vue <template> <p>{{ $route.params.group }} - {{ $route.params.id }}</p> </template> ``` 导航到`/users-admins/123`将呈现: ```html <p>admins - 123</p> ``` 如果你想使用Composition API访问路由,有一个全局的`useRoute`函数,它将允许你访问路由,就像选项API中的`this.$route`一样。 ```vue <script setup> const route = useRoute() if (route.params.group === 'admins' && !route.params.id) { console.log('Warning! Make sure user is authenticated!') } </script> ``` ### Catch-all Route If you need a catch-all route, you create it by using a file named like [...slug].vue. This will match all routes under that path. ```vue pages/[...slug].vue <template> <p>{{ $route.params.slug }}</p> </template> ``` 导航到`/hello/world`将呈现: ```html <p>["hello", "world"]</p> ``` ### 嵌套 Routes 可以使用 `<NuxtPage>`来显示[嵌套路由](https://next.router.vuejs.org/guide/essentials/nested-routes.html)。 示例: ``` -| pages/ ---| parent/ ------| child.vue ---| parent.vue ``` 这个文件树将生成这些路由: ```javascript [ { path: '/parent', component: '~/pages/parent.vue', name: 'parent', children: [ { path: 'child', component: '~/pages/parent/child.vue', name: 'parent-child' } ] } ] ``` 要显示`child.vue`组件,你必须在`pages/parent.vue`中插入`<NuxtPage>`组件: ```vue pages/parent.vue <template> <div> <h1>I am the parent view</h1> <NuxtPage :foobar="123" /> </div> </template> ``` #### Child Route Keys 如果你想要更多的控制`<NuxtPage>`组件被重新渲染(例如,对于transitions),你可以通过`pageKey`道具传递一个字符串或函数,或者你可以通过`definePageMeta`定义一个`key`值: ```vue pages/parent.vue <template> <div> <h1>I am the parent view</h1> <NuxtPage :page-key="someKey" /> </div> </template> ``` 换个: ```vue pages/child.vue <script setup> definePageMeta({ key: route => route.fullPath }) </script> ``` ### Page Metadata 你可能想在你的应用程序中为每个路由定义元数据。你可以使用`definePageMeta`宏来实现这一点,它将在`<script>`和`<script setup>`中工作: ```vue <script setup> definePageMeta({ title: 'My home page' }) </script> ``` 这些数据可以通过`route.meta`对象在应用程序的其余部分中访问。 ```vue <script setup> const route = useRoute() console.log(route.meta.title) // My home page </script> ``` 如果使用嵌套路由,那么来自所有这些路由的页面元数据将被合并到单个对象中。有关路由元的更多信息,请参见[vue-router docs](https://router.vuejs.org/guide/advanced/meta.html#route-meta-fields)。 类似于`definetriggers`或`defineProps`(参见[Vue docs](https://vuejs.org/api/sfc-script-setup.html#defineprops-defineemits)), `definePageMeta`是一个**编译器宏**。它将被编译掉,因此您不能在组件中引用它。相反,传递给它的元数据将从组件中提升出来。因此,页面元对象不能引用组件(或组件上定义的值)。但是,它可以引用导入的绑定。 ```vue <script setup> import { someData } from '~/utils/example' const title = ref('') definePageMeta({ title, // This will create an error someData }) </script> ``` #### Special Metadata 当然,你可以在整个应用程序中定义元数据供自己使用。但是一些用`definePageMeta`定义的元数据有一个特定的目的: ##### alias 您可以定义页面别名。它们允许您从不同的路径访问同一个页面。它可以是字符串,也可以是vue-router文档中定义的字符串数组(https://router.vuejs.org/guide/essentials/redirect-and-alias.html#alias)。 ##### keepalive 如果你在你的`definePageMeta`中设置`KeepAlive: true`, Nuxt将自动包装你的页面[Vue 组件](https://vuejs.org/guide/built-ins/keep-alive.html#keepalive)。例如,如果您希望跨路由更改保持页面状态,那么在具有动态子路由的父路由中这样做可能很有用。 当你的目标是为父路由保留状态时,使用以下语法:`<NuxtPage keepalive />`。你也可以设置传递给' '的道具(查看完整列表[这里](https://vuejs.org/api/built-in-components.html#keepalive))。 你可以为这个属性设置一个默认值[在你的`nuxt.config`中](https://nuxt.com/docs/api/configuration/nuxt-config#keepalive)。 ##### key [See above](https://nuxt.com/docs/guide/directory-structure/pages#child-route-keys). ##### layout 您可以定义用于呈现路由的布局。这可以是false(禁用任何布局),一个字符串或一个ref/computed,如果你想让它以某种方式响应。[关于布局的更多信息](https://nuxt.com/docs/guide/directory-structure/layouts)。 ##### layoutTransition and pageTransition 你可以为包装页面和布局的`<transition>`组件定义转换属性,或者传递`false`来禁用该路由的`<transition>`包装。您可以在[这里](https://vuejs.org/api/built-in-components.html#transition)看到可传递的选项列表,或者阅读[关于过渡如何工作的更多信息](https://vuejs.org/guide/built-ins/transition.html#transition)。 你可以为这些属性设置默认值[在你的`nuxt.config`中](https://nuxt.com/docs/api/configuration/nuxt-config#layouttransition)。 ##### middleware 可以在加载此页面之前定义要应用的中间件。它将与任何匹配的父/子路由中使用的所有其他中间件合并。它可以是字符串、函数(遵循[全局前保护模式](https://router.vuejs.org/guide/advanced/navigation-guards.html#global-before-guards)的匿名/内联中间件函数)或字符串/函数数组。[关于命名中间件的更多信息](https://nuxt.com/docs/guide/directory-structure/middleware)。 ##### name 您可以为该页的路由定义一个名称。 ##### path 如果您有一个比文件名更复杂的模式,您可以定义一个路径匹配器。更多信息请参见[`vue-router`文档](https://router.vuejs.org/guide/essentials/route-matching-syntax.html#custom-regex-in-params)。 #### Typing Custom Metadata 如果要为页面添加自定义元数据,您可能希望以类型安全的方式这样做。可以增加`definePageMeta`接受的对象的类型: ```typescript index.d.ts declare module '#app' { interface PageMeta { pageType?: string } } // 在扩充类型时,确保导入/导出某些内容总是很重要的 export {} ``` ### 页面导航 要在应用程序的页面之间导航,你应该使用`<NuxtLink>`组件。 该组件包含在Nuxt中,因此您不必像导入其他组件那样导入它。 一个简单的链接到你的pages文件夹中的index.vue页面: ``` <template> <NuxtLink to="/">Home page</NuxtLink> </template> ``` ### Router 选项 可以自定义[vue-router选项](https://router.vuejs.org/api/interfaces/routeroptions.html)。 #### Using app/router.options 这是指定路由器选项的推荐方法。 ```typescript app/router.options.ts import type { RouterConfig } from '@nuxt/schema' // https://router.vuejs.org/api/interfaces/routeroptions.html export default <RouterConfig> { } ``` ##### 自定义 Routes 您可以选择使用一个接受扫描路由并返回定制路由的函数来覆盖路由。 如果返回`null` 或 `undefined`, Nuxt将退回到默认路由。(用于修改输入数组) ```typescript app/router.options.ts import type { RouterConfig } from '@nuxt/schema' // https://router.vuejs.org/api/interfaces/routeroptions.html export default <RouterConfig> { routes: (_routes) => [ { name: 'home', path: '/', component: () => import('~/pages/home.vue') } ], } ``` ##### 自定义历史记录(高级) 您可以选择使用接受基url并返回历史模式的函数来覆盖历史模式。 如果返回`null` or `undefined`, Nuxt将退回到默认的历史记录。 ```typescript app/router.options.ts import type { RouterConfig } from '@nuxt/schema' import { createMemoryHistory } from 'vue-router' // https://router.vuejs.org/api/interfaces/routeroptions.html export default <RouterConfig> { history: base => process.client ? createMemoryHistory(base) : null /* default */ } ``` #### 使用 nuxt.config **注意:** 只有JSON可序列化选项是可配置的: - `linkActiveClass` - `linkExactActiveClass` - `end` - `sensitive` - `strict` - `hashMode` ```typescript nuxt.config.ts export default defineNuxtConfig({ router: { // https://router.vuejs.org/api/interfaces/routeroptions.html options: {} } }) ``` #### Hash 模式 (SPA) 您可以在SPA模式下启用哈希历史。在这种模式下,路由器在内部传递的实际URL之前使用一个哈希字符(#)。当启用时,**URL永远不会发送到服务器**,**SSR不支持**。 ``` nuxt.config.ts export default defineNuxtConfig({ ssr: false, router: { options: { hashMode: true } } }) ``` ### Programmatic Navigation Nuxt 3允许通过`navigateTo()` 实用方法进行编程导航。使用此实用工具方法,您将能够在应用程序中以编程方式导航用户。这对于从用户获取输入并在整个应用程序中动态导航用户非常有用。在本例中,我们有一个名为`navigateTo()`的简单方法,当用户提交搜索表单时调用它。 **注意:** 确保在`navigateTo` 上总是`await`,或者通过从函数返回来链接它的结果。 ```vue <script setup> const router = useRouter(); const name = ref(''); const type = ref(1); function navigate(){ return navigateTo({ path: '/search', query: { name: name.value, type: type.value } }) } </script> ``` ## Plugins 目录 Nuxt自动读取您的`plugins`目录中的文件,并在创建Vue应用程序时加载它们。你可以在文件名中使用`.server`或`.client`后缀来只在服务器端或客户端加载插件。 `plugins/`目录下的所有插件都是自动注册的,所以你不应该将它们单独添加到你的`nuxt.config`目录中。 ### 注册了哪些文件 只有在`plugins/`目录的顶层的文件(或任何子目录中的索引文件)才会被注册为插件。 例如: ``` plugins | - myPlugin.ts | - myOtherPlugin | --- supportingFile.ts | --- componentToRegister.vue | --- index.ts ``` 只有`myPlugin.ts` 和 `myOtherPlugin/index.ts`会被注册。 ### 创建组件 传递给插件的唯一参数是 [`nuxtApp`](https://nuxt.com/docs/api/composables/use-nuxt-app). ```typescript export default defineNuxtPlugin(nuxtApp => { // Doing something with nuxtApp }) ``` ### 插件注册令 您可以通过在文件名前面加上一个数字来控制插件注册的顺序。 例如: ``` plugins/ | - 1.myPlugin.ts | - 2.myOtherPlugin.ts ``` 在本例中,`2.myOtherPlugin.ts`将能够访问`1.myPlugin.ts`注入的任何内容。 这在一个插件依赖于另一个插件的情况下非常有用。 ### 在插件中使用可组合文件 你可以在 Nuxt plugins中使用[composables](https://nuxt.com/docs/guide/directory-structure/composables): ```typescript export default defineNuxtPlugin((NuxtApp) => { const foo = useFoo() }) ``` 然而,请记住有一些限制和区别: - **如果一个可组合的插件依赖于后来注册的另一个插件,它可能无法工作** - **原因:** 插件按顺序调用,先于所有其他插件。你可以使用一个依赖于另一个尚未被调用的插件的可组合。 - **如果一个可组合文件依赖于Vue.js的生命周期,它将无法工作** - **原因:** 通常情况下,Vue.js组合组件被绑定到当前组件实例,而插件只被绑定到`nuxtApp`实例。 ### 自动提供辅助函数 如果你想在`NuxtApp`实例上提供一个帮助器,请在`provide`键下从插件中返回它。例如: ```typescript export default defineNuxtPlugin(() => { return { provide: { hello: (msg: string) => `Hello ${msg}!` } } }) ``` 在另一个文件中,你可以这样做: ```vue <template> <div> {{ $hello('world') }} </div> </template> <script setup lang="ts"> // alternatively, you can also use it here const { $hello } = useNuxtApp() </script> ``` ### 输入插件 如果你从插件中返回你的helper,它们会自动被输入;你会发现它们为返回的`useNuxtApp()`和在你的模板中键入。 如果你 *需要* 在另一个插件中使用提供的帮助程序,你可以调用`useNuxtApp()`来获得类型化版本。但通常情况下,应该避免这样做,除非您确定插件的顺序。 #### Advanced 对于高级用例,你可以像这样声明注入属性的类型: ```typescript index.d.ts declare module '#app' { interface NuxtApp { $hello (msg: string): string } } declare module '@vue/runtime-core' { interface ComponentCustomProperties { $hello (msg: string): string } } export { } ``` ### Vue 插件 如果你想使用Vue插件,比如[vue-gtag](https://github.com/MatteoGabriele/vue-gtag)来添加谷歌Analytics标签,你可以使用Nuxt插件来做到这一点。 > 有一个开放的RFC使这更容易! 查看 [nuxt/nuxt#17143](https://github.com/nuxt/nuxt/discussions/17143) 首先,安装你想要的插件。 ``` yarn add --dev vue-gtag-next ``` 然后创建一个插件文件`plugins/vue-gtag.client.js`。 ```javascript import VueGtag from 'vue-gtag-next' export default defineNuxtPlugin((nuxtApp) => { nuxtApp.vueApp.use(VueGtag, { property: { id: 'GA_MEASUREMENT_ID' } }) }) ``` ### Vue Diectives 类似地,您可以在插件中注册自定义Vue指令。例如,在 `plugins/directive.ts`中: ```typescript export default defineNuxtPlugin((nuxtApp) => { nuxtApp.vueApp.directive('focus', { mounted (el) { el.focus() }, getSSRProps (binding, vnode) { // you can provide SSR-specific props here return {} } }) }) ``` ## Public 目录 `public/`目录直接服务于服务器根目录,包含必须保留其名称的公共文件(例如:`robots.txt`)或可能不会更改(例如:`favicon.ico`)。 ## Server 目录 Nuxt自动扫描`~/server/api`, `~/server/routes`, 和 `~/server/middleware`目录中的文件,以注册具有HMR支持的API和服务器处理程序。 每个文件都应该导出一个用`defineEventHandler()`定义的默认函数。 处理程序可以直接返回JSON数据,一个`Promise`或使用`event.node.res.end()`发送响应。 Read more in [Nitro Route Handling Docs](https://nitro.unjs.io/guide/introduction/routing). ### 实例 创建一个新文件`server/api/hello.ts`: ```typescript server/api/hello.ts export default defineEventHandler((event) => { return { api: 'works' } }) ``` 你现在可以使用`await $fetch('/api/hello')`通用地调用这个API。 ### Server 路由 `~/server/api`中的文件在它们的路由中会自动以`/api`作为前缀。 对于添加没有`/api`前缀的服务器路由,您可以将它们放到 `~/server/routes`目录中。 **示例:** ```typescript server/routes/hello.ts export default defineEventHandler(() => 'Hello World!') ``` 对于上面的例子, `/hello`路由可以在http://localhost:3000/hello 上访问。 ### Server 中间件 Nuxt将自动读入`~/server/middleware`中的任何文件,为项目创建服务器中间件。 中间件处理程序将在每个请求上运行,然后再运行任何其他服务器路由,以添加或检查标头、记录请求或扩展事件的请求对象。 中间件处理程序不应返回任何内容(也不应关闭或响应请求),而只检查或扩展请求上下文或抛出错误。 **示例:** ```typescript server/middleware/log.ts export default defineEventHandler((event) => { console.log('New request: ' + event.node.req.url) }) ``` ```typescript server/middleware/auth.ts export default defineEventHandler((event) => { event.context.auth = { user: 123 } }) ``` ### Server 插件 Nuxt将自动读取`~/server/plugins`目录中的任何文件,并将它们注册为Nitro插件。这允许扩展Nitro的运行时行为并与生命周期事件挂钩。 **示例:** ```typescript server/plugins/nitroPlugin.ts export default defineNitroPlugin((nitroApp) => { console.log('Nitro plugin', nitroApp) }) ``` Read more in [Nitro Plugins](https://nitro.unjs.io/guide/advanced/plugins). ### Server 工具 服务器路由是由[unjs/h3](https://github.com/unjs/h3)提供的,它附带了一组方便的助手。 Read more in [Available H3 Request Helpers](https://www.jsdocs.io/package/h3#package-index-functions). 您可以自己在`~/server/utils`目录中添加更多的helper。 ### 使用示例 #### 匹配路由参数 服务器路由可以在文件名的括号内使用动态参数,比如`/api/hello/[name].ts`并通过`event.context.params`访问。 **示例:** ```typescript server/api/hello/[name].ts export default defineEventHandler((event) => `Hello, ${event.context.params.name}!`) ``` 你现在可以使用 `await $fetch('/api/hello/nuxt')`调用这个API,并得到`Hello, nuxt!`。 #### 匹配 HTTP Method 句柄文件名可以用`.get`, `.post`, `.put`, `.delete`作为后缀,…匹配请求的[HTTP方法](https://developer.mozilla.org/en-US/docs/Web/HTTP/Methods)。 ```typescript server/api/test.get.ts export default defineEventHandler(() => 'Test get handler') ``` ```typescript server/api/test.post.ts export default defineEventHandler(() => 'Test post handler') ``` Given the example above, fetching `/test` with: - **GET** method: Returns `Test get handler` - **POST** method: Returns `Test post handler` - Any other method: Returns 405 error #### Catch-all Route 全覆盖路由有助于处理备用路由。例如,创建一个名为`~/server/api/foo/[...].ts` 的文件,将为所有不匹配任何路由处理程序的请求注册一个catch-all路由,例如`/api/foo/bar/baz`。 **示例:** ```typescript server/api/foo/[...].ts export default defineEventHandler(() => `Default foo handler`) ``` ```typescript server/api/[...].ts export default defineEventHandler(() => `Default api handler`) ``` #### 用Body处理请求 ```typescript server/api/submit.post.ts export default defineEventHandler(async (event) => { const body = await readBody(event) return { body } }) ``` 你现在可以使用`$fetch('/api/submit', { method: 'post', body: { test: 123 } })`通用地调用这个API。 我们在文件名中使用`submit.post.ts`只是为了匹配能够接受请求体的`POST`方法的请求。当在GET请求中使用`readBody`时,`readBody`将抛出`405 Method Not Allowed` HTTP错误。 #### 处理带有Query参数的请求 Sample query `/api/query?param1=a¶m2=b` ```typescript server/api/query.get.ts export default defineEventHandler((event) => { const query = getQuery(event) return { a: query.param1, b: query.param2 } }) ``` #### 错误处理 如果没有抛出错误,则返回状态代码`200 OK`。任何未捕获的错误将返回一个`500 Internal Server Error`HTTP错误。 要返回其他错误代码,请抛出带有 `createError`的异常。 ```typescript server/api/validation/[id].ts export default defineEventHandler((event) => { const id = parseInt(event.context.params.id) as number if (!Number.isInteger(id)) { throw createError({ statusCode: 400, statusMessage: 'ID should be an integer', }) } return 'All good' }) ``` #### 返回其他状态码 要返回其他状态码,可以使用`setResponseStatus`。 For example, to return `202 Accepted` ```typescript server/api/validation/[id].ts export default defineEventHandler((event) => { setResponseStatus(event, 202) }) ``` #### 访问 Runtime Config ```typescript server/api/foo.ts export default defineEventHandler((event) => { const config = useRuntimeConfig() return { key: config.KEY } }) ``` #### 访问 Request Cookies ```typescript export default defineEventHandler((event) => { const cookies = parseCookies(event) return { cookies } }) ``` ### 高级用法示例 #### Nitro 配置 您可以在`nuxt.config`中使用`nitro`键直接设置[nitro配置](https://nitro.unjs.io/config)。 这是一个高级选项。自定义配置可能会影响生产部署,因为当Nitro在Nuxt的小版本中升级时,配置接口可能会随着时间的推移而改变。 ```typescript nuxt.config.ts export default defineNuxtConfig({ // https://nitro.unjs.io/config nitro: {} }) ``` #### 使用嵌套路由器 ```typescript server/api/hello/[...slug].ts import { createRouter, defineEventHandler, useBase } from 'h3' const router = createRouter() router.get('/test', defineEventHandler(() => 'Hello World')) export default useBase('/api/hello', router.handler) ``` #### 发送 Streams (实验性) **注意:** 这是一个实验特性,只在Node.js环境中可用。 ```typescript server/api/foo.get.ts import fs from 'node:fs' import { sendStream } from 'h3' export default defineEventHandler((event) => { return sendStream(event, fs.createReadStream('/path/to/file')) }) ``` #### 返回一个legacy处理程序或中间件 ```typescript server/api/legacy.ts export default (req, res) => { res.end('Legacy handler') } ``` 使用[unjs/h3](https://github.com/unjs/h3)可以支持遗留处理程序,但建议尽可能避免使用遗留处理程序。 ```typescript server/middleware/legacy.ts export default (req, res, next) => { console.log('Legacy middleware') next() } ``` 不要将`next()`回调与`async`或返回`Promise`的legacy中间件结合使用! #### Server 存储 Nitro提供了一个跨平台[存储层](https://nitro.unjs.io/guide/introduction/storage)。为了配置额外的存储挂载点,你可以使用`nitro.storage`。 ##### 示例:使用Redis ```typescript nuxt.config.ts export default defineNuxtConfig({ nitro: { storage: { 'redis': { driver: 'redis', /* redis connector options */ port: 6379, // Redis port host: "127.0.0.1", // Redis host username: "", // needs Redis >= 6 password: "", db: 0, // Defaults to 0 tls: {} // tls/ssl } } } }) ``` 创建一个新文件 `server/api/test.post.ts`: ```typescript server/api/test.post.ts export default defineEventHandler(async (event) => { const body = await readBody(event) await useStorage().setItem('redis:test', body) return 'Data is set' }) ``` 创建一个新文件 `server/api/test.get.ts`: ```typescript server/api/test.get.ts export default defineEventHandler(async (event) => { const data = await useStorage().getItem('redis:test') return data }) ``` 创建一个新文件 `app.vue`: ```vue app.vue <template> <div> <div>Post state: {{ resDataSuccess }}</div> <div>Get Data: {{ resData.text }}</div> </div> </template> <script setup lang="ts"> const { data: resDataSuccess } = await useFetch('/api/test', { method: 'post', body: { text: 'Nuxt is Awesome!' } }) const { data: resData } = await useFetch('/api/test') </script> ``` ## Utils 目录 Nuxt 3 使用 `utils/` 目录在整个应用程序中使用[auto-imports](https://nuxt.com/docs/guide/concepts/auto-imports)自动导入辅助函数和其他实用程序! `utils/` 目录的主要目的是允许在Vue组合函数和其他自动导入的实用函数之间进行语义区分。`utils/` 自动导入的工作方式和被扫描的方式与[组合文件/目录](https://nuxt.com/docs/guide/directory-structure/composables)相同。你可以在文档的那个部分看到例子和更多关于它们如何工作的信息。 ## .env文件 Nuxt CLI在开发模式下以及运行`nuxi build`和`nuxi generate`时内置了[dotenv](https://github.com/motdotla/dotenv)支持。 除了任何进程环境变量外,如果您的项目根目录中有一个`.env`文件,它将在构建、开发和生成时自动加载,并且在`nuxt.config`文件和模块中设置的任何环境变量都将可访问。 如果您想使用不同的文件 - 例如,使用`.env.local`或`.env.production` - 您可以在使用`nuxi`时传递`--dotenv`标志来实现。例如: ``` npx nuxi dev --dotenv .env.local ``` 与上面一样,这仅适用于开发模式以及运行`nuxi build`和`nuxi generate`。 在开发模式下更新`.env`文件时,Nuxt实例会自动重新启动以将新值应用于`process.env`。 请注意,从`.env`文件中删除变量或完全删除`.env`文件将不会取消已设置的值。 但是,在构建服务器之后,您需要在运行服务器时自己设置环境变量。此时将不会读取您的`.env`文件。如何设置环境变量因每个环境而异。在Linux服务器上,您可以使用终端`DATABASE_HOST=mydatabaseconnectionstring node .output/server/index.mjs`传递环境变量作为参数。或者您可以使用`source .env && node .output/server/index.mjs`引用您的env文件。 请注意,对于纯静态站点,在项目预渲染之后无法设置运行时配置。 如果您想在构建时使用环境变量但不关心以后更新这些变量(或者只需要在应用程序内部以反应方式更新它们),则`appConfig`可能是更好的选择。您可以在您的`nuxt.config`中定义`appConfig`(使用环境变量),也可以在您的项目中的`~/app.config.ts`文件中定义`appConfig`。 ## .gitignore 文件 一个`.gitignore`的文件指定了git应该忽略的未跟踪文件。在[git文档](https://git-scm.com/docs/gitignore)中了解更多信息。 我们建议有一个 `.gitignore`的文件,包含**至少**以下条目: ``` .gitignore # Nuxt dev/build outputs .output .nuxt # Node dependencies node_modules # System files *.log ``` ## nuxtignore 文件 在构建阶段,`.nuxtignore`文件可以让Nuxt忽略项目根目录(`rootDir`)中的`layouts`, `pages`, `components`, `composables` 和 `middleware`文件。`.nuxtignore`文件遵循与`.gitignore` 和 `.eslintignore`文件相同的规范,其中每一行都是一个glob模式,指示应该忽略哪些文件。 **注意**: 你也可以在你的`nuxt.config`中配置[`ignoreOptions`](https://nuxt.com/docs/guide/directory-structure/nuxt.config#ignoreoptions), [`ignorePrefix`](https://nuxt.com/docs/guide/directory-structure/nuxt.config#ignoreprefix)和[`ignore`](https://nuxt.com/docs/guide/directory-structure/nuxt.config#ignore) 。 ### 示例 ``` .nuxtignore # ignore layout foo.vue layouts/foo.vue # ignore layout files whose name ends with -ignore.vue layouts/*-ignore.vue # ignore page bar.vue pages/bar.vue # ignore page inside ignore folder pages/ignore/*.vue # ignore route middleware files under foo folder except foo/bar.js middleware/foo/*.js !middleware/foo/bar.js ``` ## App Config File Nuxt 3提供了一个`app.config`配置文件公开应用程序中的响应性配置,能够在生命周期内的运行时更新它,或者使用nuxt插件并使用HMR(热模块替换)编辑它。 你可以使用`app.config.ts`文件 轻松提供运行时应用配置。它可以有`.ts`, `.js`, or `.mjs` 的扩展。 ```typescript app.config.ts export default defineAppConfig({ foo: 'bar' }) ``` 不要把任何秘密的值在`app.config`文件。它公开给用户客户端。 ### 定义应用程序配置 To expose config and environment variables to the rest of your app, you will need to define configuration in `app.config` file. 要将配置和环境变量暴露给应用程序的其余部分,你需要在'`app.config` 文件配置。 **示例:** ```typescript app.config.ts export default defineAppConfig({ theme: { primaryColor: '#ababab' } }) ``` 当添加'theme'到`app.config`, Nuxt使用Vite或webpack来捆绑代码。我们可以使用[useAppConfig](https://nuxt.com/docs/api/composables/use-app-config)在服务器和浏览器中通用地访问`theme`。 ``` const appConfig = useAppConfig() console.log(appConfig.theme) ``` #### 手动输入App配置 Nuxt尝试从提供的应用程序配置自动生成一个typescript接口。 也可以手动输入app config: ```typescript index.d.ts declare module '@nuxt/schema' { interface AppConfigInput { /** Theme configuration */ theme?: { /** Primary app color */ primaryColor?: string } } } // 在扩充类型时,确保导入/导出某些内容总是很重要的 export {} ``` ## app.vue 文件 `app.vue`文件是Nuxt 3应用程序中的主要组件。 ### 最小的使用 在Nuxt 3中,[pages/](https://nuxt.com/docs/guide/directory-structure/pages)目录是可选的。如果不存在,Nuxt将不包含[vue-router](https://router.vuejs.org/)依赖项。这在处理着陆页面或不需要路由的应用程序时非常有用。 ```vue app.vue <template> <h1>Hello World!</h1> </template> ``` ### 使用Pages 如果你有一个[`pages/`](https://nuxt.com/docs/guide/directory-structure/pages)目录,使用`<NuxtPage>`组件来显示当前页面: ```vue app.vue <template> <div> <NuxtLayout> <NuxtPage/> </NuxtLayout> </div> </template> ``` 因为Nuxt 3在`<NuxtPage>`使用[`suspense`](https://vuejs.org/guide/built-ins/suspense.html#suspense),所以它不能被设置为根元素。 记住那个 `app.vue` 作为Nuxt应用程序的主要组件。你添加的任何东西(JS和CSS)都是全局的,包含在每个页面中。 如果你想在页面之间自定义页面结构,请查看[`layouts/`](https://nuxt.com/docs/guide/directory-structure/layouts)目录。 ## nuxt.Config.ts 文件 Nuxt可以用一个`nuxt.config`文件轻松配置,该文件可以有`js`, `ts` or `mjs`扩展名。 ``` export default defineNuxtConfig({ // My Nuxt config }) ``` `defineNuxtConfig` 辅助函数是全局可用的,无需导入。 如果你喜欢,你可以显式地从`nuxt/config`导入`defineNuxtConfig`: ``` import { defineNuxtConfig } from 'nuxt/config' export default defineNuxtConfig({ // My Nuxt config }) ``` 为了确保您的配置是最新的,当检测到主配置文件`env`, `nuxtignore` and `nuxtrc` dotfile 中的更改时,Nuxt将完全重新启动。 ## package.json 文件 package.json文件包含应用程序的所有依赖项和脚本。 ## tsconfig.json 配置文件 Nuxt自动生成一个.nuxt/tsconfig.json文件,包含你在Nuxt项目中使用的解析别名,以及其他合理的默认值。你可以通过在你的项目的根目录中创建一个tsconfig.json获益,它包含以下内容: ```json { "extends": "./.nuxt/tsconfig.json" } ``` 根据需要,可以自定义该文件的内容。但是,建议不要覆盖`target`,` module`和`moduleResolution`。此外,请注意,如果你需要自定义你的“路径”,这将覆盖自动生成的路径别名。相反,我们建议你将任何路径别名添加到你的nuxt.conf中的alias属性中,在那里它们将被拾取并添加到自动生成的`tsconfig`中。 猜你想看 每日一学:PHP 中的array_replace函数详解 每日一学:PHP 中的array_key_last函数详解 免费获取亚马逊国外云桌面的保姆级流程 蓝易云暑期大采购活动 每日一学:PHP 中的array_pop函数详解 CSS3 Flex布局使用说明 JavaScript计时器 每日一学:PHP 中的array_diff_uassoc函数详解 vue2使用ajax发送网络请求 2022年12月9日宝塔严重未知安全性漏洞 最后修改:2023 年 05 月 02 日 © 允许规范转载 赞 0 如果觉得我的文章对你有用,请随意赞赏
1 条评论
export default defineEventHandler((event) => {
console.log('New request: ' + event.node.req.url)
}) 博主,怎么拿到 event.node.res中的响应体并保存在store中?我尝试在这个中间件文件中import引入pinia,但是会报错。并且我在vscode终端打印,event.node.res,我也无法看到他的内容,只是【obj,obj】