一、nuxt配置
nuxt.config.ts 文件位于 Nuxt 项目的根目录,可以覆盖或扩展应用程序的行为。
一个最小的配置文件导出了 defineNuxtConfig
函数,该函数包含一个包含您的配置的对象。 defineNuxtConfig
助手在全局范围内可用,无需导入。
示例
export default defineNuxtConfig({
// 我的 Nuxt 配置
})
该文件通常会在文档中提及,例如添加自定义脚本、注册模块或更改渲染模式。
注意:
您不必使用 TypeScript 来构建 Nuxt 应用程序。但是,强烈建议将
nuxt.config
文件的扩展名设为.ts
。这样,您可以从 IDE 中受益,避免在编辑配置时出现拼写错误和错误。从3.2.34版本开始,使用<script setup>的单文件组件将根据文件名自动推断其名称选项,从而无需手动声明名称。
二、选项参数
下面介绍每个选项参数用法:
alias
您可以通过定义额外的别名来访问JavaScript和CSS中的自定义目录来改进DX。
Type: object
默认的配置
{
"~": "/<srcDir>",
"@": "/<srcDir>",
"~~": "/<rootDir>",
"@@": "/<rootDir>",
"#shared": "/<rootDir>/shared",
"assets": "/<srcDir>/assets",
"public": "/<srcDir>/public",
"#build": "/<rootDir>/.nuxt",
"#internal/nuxt/paths": "/<rootDir>/.nuxt/paths.mjs"
}
注意:在webpack上下文中(图像源,CSS -但不是JavaScript),你必须通过在别名前加上~来访问别名。
注意:这些别名将自动添加到生成的 .nuxt/tsconfig.json 中。所以你可以得到完整的类型支持和路径自动完成。如果您需要扩展 ./.nuxt/tsconfig.json 提供的选项,请确保在这里或在 nuxt.config 中添加typescript.tsConfig 属性。
示例
export default {
alias: {
'images': fileURLToPath(new URL('./assets/images', import.meta.url)),
'style': fileURLToPath(new URL('./assets/style', import.meta.url)),
'data': fileURLToPath(new URL('./assets/other/data', import.meta.url))
}
}
analyzeDir
运行next analyze时,next将存储生成文件的目录。
如果指定了一个相对路径,它将相对于您的rootDir。
Type: string
Default: "/<rootDir>/.nuxt/analyze"
app
App配置
baseURL
next应用程序的基本路径。
Type: string
Default: "/"
示例
export default defineNuxtConfig({
app: {
baseURL: '/prefix/'
}
})
示例
NUXT_APP_BASE_URL=/prefix/ node .output/server/index.mjs
buildAssetsDir
构建的站点资源的文件夹名称,相对于baseURL(或cdnURL,如果设置了)。这是在构建时设置的,不应该在运行时自定义。
Type: string
Default: "/_nuxt/"
cdnURL
为公共文件夹提供服务的绝对URL(仅限生产环境)。
Type: string
Default: ""
示例
export default defineNuxtConfig({
app: {
cdnURL: 'https://mycdn.org/'
}
})
示例
NUXT_APP_CDN_URL=https://mycdn.org/ node .output/server/index.mjs
head
在每个页面上设置<head>的默认配置。
Type: object
默认配置
{
"meta": [
{
"name": "viewport",
"content": "width=device-width, initial-scale=1"
},
{
"charset": "utf-8"
}
],
"link": [],
"style": [],
"script": [],
"noscript": []
}
示例
app: {
head: {
meta: [
// <meta name="viewport" content="width=device-width, initial-scale=1">
{ name: 'viewport', content: 'width=device-width, initial-scale=1' }
],
script: [
// <script src="https://myawesome-lib.js"></script>
{ src: 'https://awesome-lib.js' }
],
link: [
// <link rel="stylesheet" href="https://myawesome-lib.css">
{ rel: 'stylesheet', href: 'https://awesome-lib.css' }
],
// please note that this is an area that is likely to change
style: [
// <style type="text/css">:root { color: red }</style>
{ children: ':root { color: red }', type: 'text/css' }
],
noscript: [
// <noscript>JavaScript is required</noscript>
{ children: 'JavaScript is required' }
]
}
}
keepalive
参数解析
页面间KeepAlive配置的默认值。
<KeepAlive>是一个内置组件,它允许我们在多个组件之间动态切换时有条件地缓存组件实例。
这可以在单个页面上用definePageMeta覆盖。只允许json序列化的值。
Type: boolean
Default: false
详情参考文档: Vue KeepAlive
示例如下:
缓存内部包装的动态切换组件
interface KeepAliveProps {
/**
* If specified, only components with names matched by
* `include` will be cached.
*/
include?: MatchPattern
/**
* Any component with a name matched by `exclude` will
* not be cached.
*/
exclude?: MatchPattern
/**
* The maximum number of component instances to cache.
*/
max?: number | string
}
type MatchPattern = string | RegExp | (string | RegExp)[]
技术细节
在交换机上创建新的组件实例通常是有用的行为,希望即使两个组件实例处于非活动状态也能保留它们。为了解决这个问题,我们可以用内置的<KeepAlive>组件封装动态组件:
当包装在动态组件周围时,<KeepAlive>会缓存不活动的组件实例,而不会销毁它们。
任何时候都只能有一个活动组件实例作为<KeepAlive>的直接子实例。
当一个组件在<KeepAlive>中被切换时,它的激活和取消激活的生命周期钩子将被相应地调用,提供了一个不被调用的mounted和unmounted的替代方案。这适用于<KeepAlive>的直接子节点以及它的所有子节点。
如图
基本用法
示例
<KeepAlive>
<component :is="view"></component>
</KeepAlive>
v-if
当与v-if / v-else分支一起使用时,一次只能呈现一个组件:
<KeepAlive>
<comp-a v-if="a > 1"></comp-a>
<comp-b v-else></comp-b>
</KeepAlive>
Transition
与<Transition>一起使用:
<Transition>
<KeepAlive>
<component :is="view"></component>
</KeepAlive>
</Transition>
include / exclude
默认情况下,<KeepAlive>将缓存内部的任何组件实例。我们可以通过include和exclude道具自定义这种行为。这两个道具都可以是一个逗号分隔的字符串,一个RegExp,或者一个包含以下两种类型的数组:
<!-- comma-delimited string -->
<KeepAlive include="a,b">
<component :is="view"></component>
</KeepAlive>
<!-- regex (use `v-bind`) -->
<KeepAlive :include="/a|b/">
<component :is="view"></component>
</KeepAlive>
<!-- Array (use `v-bind`) -->
<KeepAlive :include="['a', 'b']">
<component :is="view"></component>
</KeepAlive>
匹配是根据组件的名称选项来检查的,所以需要被KeepAlive有条件缓存的组件必须显式声明一个名称选项。
max
最大缓存实例
我们可以通过max prop限制可以缓存的组件实例的最大数量。当指定max时,<KeepAlive>的行为就像一个LRU缓存:如果缓存实例的数量即将超过指定的最大数量,最近访问最少的缓存实例将被销毁,为新的缓存实例腾出空间。
<KeepAlive :max="10">
<component :is="view"></component>
</KeepAlive>
Lifecycle
缓存实例的生命周期
当一个组件实例被从DOM中移除,但它是由<KeepAlive>缓存的组件树的一部分时,它会进入一个停用状态,而不是被卸载。当一个组件实例作为缓存树的一部分插入到DOM中时,它就会被激活。
保持活动状态的组件可以使用onActivated()和onDeactivated()为这两种状态注册生命周期钩子:
<script setup>
import { onActivated, onDeactivated } from 'vue'
onActivated(() => {
// called on initial mount
// and every time it is re-inserted from the cache
})
onDeactivated(() => {
// called when removed from the DOM into the cache
// and also when unmounted
})
</script>
注意:
挂载时也调用onActivated,卸载时调用onDeactivated。
这两个钩子不仅适用于<KeepAlive>缓存的根组件,还适用于缓存树中的后代组件。
layoutTransition
布局转换的默认值。
这可以在单个页面上用definePageMeta覆盖。只允许json序列化的值。
Type: boolean
Default: false
pageTransition
页面转换的默认值。
这可以在单个页面上用definePageMeta覆盖。只允许json序列化的值。
Type: boolean
Default: false
详情参考文档: Vue Transition docs
Transition
为单个元素或组件提供动画过渡效果。
介绍
Vue 提供了两个内置组件,可以帮助你制作基于状态变化的过渡和动画。内置组件可以直接在模板中使用,而不需要注册。它们也是可摇树的:它们只在使用时包含在构建中。
<Transition>
会在一个元素或组件进入和离开 DOM 时应用动画。
<TransitionGroup>
会在一个v-for
列表中的元素或组件被插入,移动,或移除时应用动画。除了这两个组件,我们也可以通过其他技术手段来应用动画,比如切换 CSS class 或用状态绑定样式来驱动动画。这些其他的方法会可以参考官方文档动画技巧章节,本文不再额外介绍。
内置组件
在渲染函数中使用它们时,需要显式导入它们。例如:
import { h, Transition } from 'vue'
h(Transition, {
/* props */
})
示例
interface TransitionProps {
/**
* Used to automatically generate transition CSS class names.
* e.g. `name: 'fade'` will auto expand to `.fade-enter`,
* `.fade-enter-active`, etc.
*/
name?: string
/**
* Whether to apply CSS transition classes.
* Default: true
*/
css?: boolean
/**
* Specifies the type of transition events to wait for to
* determine transition end timing.
* Default behavior is auto detecting the type that has
* longer duration.
*/
type?: 'transition' | 'animation'
/**
* Specifies explicit durations of the transition.
* Default behavior is wait for the first `transitionend`
* or `animationend` event on the root transition element.
*/
duration?: number | { enter: number; leave: number }
/**
* Controls the timing sequence of leaving/entering transitions.
* Default behavior is simultaneous.
*/
mode?: 'in-out' | 'out-in' | 'default'
/**
* Whether to apply transition on initial render.
* Default: false
*/
appear?: boolean
/**
* Props for customizing transition classes.
* Use kebab-case in templates, e.g. enter-from-class="xxx"
*/
enterFromClass?: string
enterActiveClass?: string
enterToClass?: string
appearFromClass?: string
appearActiveClass?: string
appearToClass?: string
leaveFromClass?: string
leaveActiveClass?: string
leaveToClass?: string
}
事件类型
@before-enter
@before-leave
@enter
@leave
@appear
@after-enter
@after-leave
@after-appear
@enter-cancelled
@leave-cancelled (v-show only)
@appear-cancelled
示例
简单元素
<Transition>
<div v-if="ok">toggled content</div>
</Transition>
通过更改key属性强制转换:
<Transition>
<div :key="text">{
{ text }}</div>
</Transition>
动态组件,与过渡模式+动画显示:
<Transition name="fade" mode="out-in" appear>
<component :is="view"></component>
</Transition>
监听过渡事件:
<Transition @after-enter="onTransitionComplete">
<div v-show="ok">toggled content</div>
</Transition>
实战实例
<Transition>
是一个内置组件,这意味着它在任意别的组件中都可以被使用,无需注册。它可以将进入和离开动画应用到通过默认插槽传递给它的元素或组件上。进入或离开可以由以下的条件之一触发:
- 由
v-if
所触发的切换 - 由
v-show
所触发的切换 - 由特殊元素
<component>
切换的动态组件 - 改变特殊的
key
属性
<button @click="show = !show">Toggle</button>
<Transition>
<p v-if="show">hello</p>
</Transition>
css">/* 下面我们会解释这些 class 是做什么的 */
.v-enter-active,
.v-leave-active {
transition: opacity 0.5s ease;
}
.v-enter-from,
.v-leave-to {
opacity: 0;
}
效果
点击出现文字
注意 : <Transition>
仅支持单个元素或组件作为其插槽内容。如果内容是一个组件,这个组件必须仅有一个根元素。
当一个 <Transition>
组件中的元素被插入或移除时,会发生下面这些事情:
1.Vue 会自动检测目标元素是否应用了 CSS 过渡或动画。如果是,则一些 CSS 过渡 class 会在适当的时机被添加和移除。
2.如果有作为监听器的 JavaScript 钩子,这些钩子函数会在适当时机被调用。
3.如果没有探测到 CSS 过渡或动画、也没有提供 JavaScript 钩子,那么 DOM 的插入、删除操作将在浏览器的下一个动画帧后执行。
css-based-transitions">基于CSS过渡效果
一共有 6 个应用于进入与离开过渡效果的 CSS class。
步骤详解
1.v-enter-from
:进入动画的起始状态。在元素插入之前添加,在元素插入完成后的下一帧移除。
2.v-enter-active
:进入动画的生效状态。应用于整个进入动画阶段。在元素被插入之前添加,在过渡或动画完成之后移除。这个 class 可以被用来定义进入动画的持续时间、延迟与速度曲线类型。
3.v-enter-to
:进入动画的结束状态。在元素插入完成后的下一帧被添加 (也就是v-enter-from
被移除的同时),在过渡或动画完成之后移除。
4.v-leave-from
:离开动画的起始状态。在离开过渡效果被触发时立即添加,在一帧后被移除。
5.v-leave-active
:离开动画的生效状态。应用于整个离开动画阶段。在离开过渡效果被触发时立即添加,在过渡或动画完成之后移除。这个 class 可以被用来定义离开动画的持续时间、延迟与速度曲线类型。
6.v-leave-to
:离开动画的结束状态。在一个离开动画被触发后的下一帧被添加 (也就是v-leave-from
被移除的同时),在过渡或动画完成之后移除。
v-enter-active
和 v-leave-active
给我们提供了为进入和离开动画指定不同速度曲线的能力,将在下面示例。
为过渡效果命名
我们可以给 <Transition>
组件传一个 name
prop 来声明一个过渡效果名:
<Transition name="fade">
...
</Transition>
对于一个有名字的过渡效果,对它起作用的过渡 class 会以其名字而不是 v
作为前缀。比如,上方例子中被应用的 class 将会是 fade-enter-active
而不是 v-enter-active
。这个“fade”过渡的 class 应该是这样:
css">.fade-enter-active,
.fade-leave-active {
transition: opacity 0.5s ease;
}
.fade-enter-from,
.fade-leave-to {
opacity: 0;
}
css-transitions">CSS的transition
<Transition>
一般都会搭配原生 CSS 过渡一起使用,正如你在上面的例子中所看到的那样。这个 transition
CSS 属性是一个简写形式,使我们可以一次定义一个过渡的各个方面,包括需要执行动画的属性、持续时间和速度曲线。
下面是一个更高级的例子,它使用了不同的持续时间和速度曲线来过渡多个属性:
<Transition name="slide-fade">
<p v-if="show">hello</p>
</Transition>
css">/*
进入和离开动画可以使用不同
持续时间和速度曲线。
*/
.slide-fade-enter-active {
transition: all 0.3s ease-out;
}
.slide-fade-leave-active {
transition: all 0.8s cubic-bezier(1, 0.5, 0.8, 1);
}
.slide-fade-enter-from,
.slide-fade-leave-to {
transform: translateX(20px);
opacity: 0;
}
css-animations">CSS的animation
原生 CSS 动画和 CSS transition 的应用方式基本上是相同的,只有一点不同,那就是 *-enter-from
不是在元素插入后立即移除,而是在一个 animationend
事件触发时被移除。
对于大多数的 CSS 动画,我们可以简单地在 *-enter-active
和 *-leave-active
class 下声明它们。下面是一个示例:
<Transition name="bounce">
<p v-if="show" style="text-align: center;">
Hello here is some bouncy text!
</p>
</Transition>
css">.bounce-enter-active {
animation: bounce-in 0.5s;
}
.bounce-leave-active {
animation: bounce-in 0.5s reverse;
}
@keyframes bounce-in {
0% {
transform: scale(0);
}
50% {
transform: scale(1.25);
}
100% {
transform: scale(1);
}
}
动画场景不再展示,有兴趣可以自己实践一下。
自定义过渡 class
你也可以向 <Transition>
传递以下的 props 来指定自定义的过渡 class:
enter-from-class
enter-active-class
enter-to-class
leave-from-class
leave-active-class
leave-to-class
你传入的这些 class 会覆盖相应阶段的默认 class 名。这个功能在你想要在 Vue 的动画机制下集成其他的第三方 CSS 动画库时非常有用,比如 Animate.css:
<!-- 假设你已经在页面中引入了 Animate.css -->
<Transition
name="custom-classes"
enter-active-class="animate__animated animate__tada"
leave-active-class="animate__animated animate__bounceOutRight"
>
<p v-if="show">hello</p>
</Transition>
同时使用 transition和animation
Vue 需要附加事件监听器,以便知道过渡何时结束。可以是 transitionend
或 animationend
,这取决于你所应用的 CSS 规则。如果你仅仅使用二者的其中之一,Vue 可以自动探测到正确的类型。
然而在某些场景中,你或许想要在同一个元素上同时使用它们两个。举例来说,Vue 触发了一个 CSS 动画,同时鼠标悬停触发另一个 CSS 过渡。此时你需要显式地传入 type
prop 来声明,告诉 Vue 需要关心哪种类型,传入的值是 animation
或 transition
:
<Transition type="animation">...</Transition>
深层级过渡与显式过渡时长
尽管过渡 class 仅能应用在 <Transition>
的直接子元素上,我们还是可以使用深层级的 CSS 选择器,在深层级的元素上触发过渡效果:
示例
<Transition name="nested">
<div v-if="show" class="outer">
<div class="inner">
Hello
</div>
</div>
</Transition>
css">/* 应用于嵌套元素的规则 */
.nested-enter-active .inner,
.nested-leave-active .inner {
transition: all 0.3s ease-in-out;
}
.nested-enter-from .inner,
.nested-leave-to .inner {
transform: translateX(30px);
opacity: 0;
}
/* ... 省略了其他必要的 CSS */
我们甚至可以在深层元素上添加一个过渡延迟,从而创建一个带渐进延迟的动画序列:
css">/* 延迟嵌套元素的进入以获得交错效果 */
.nested-enter-active .inner {
transition-delay: 0.25s;
}
然而,这会带来一个小问题。默认情况下,<Transition>
组件会通过监听过渡根元素上的第一个transitionend
或者 animationend
事件来尝试自动判断过渡何时结束。而在嵌套的过渡中,期望的行为应该是等待所有内部元素的过渡完成。
在这种情况下,你可以通过向 <Transition>
组件传入 duration
prop 来显式指定过渡的持续时间 (以毫秒为单位)。总持续时间应该匹配延迟加上内部元素的过渡持续时间:
<Transition :duration="550">...</Transition>
如果有必要的话,你也可以用对象的形式传入,分开指定进入和离开所需的时间:
<Transition :duration="{ enter: 500, leave: 800 }">...</Transition>
性能考量
你可能注意到我们上面例子中展示的动画所用到的 CSS 属性大多是 transform
和 opacity
之类的。用这些属性制作动画非常高效,因为:
他们在动画过程中不会影响到 DOM 结构,因此不会每一帧都触发昂贵的 CSS 布局重新计算。
大多数的现代浏览器都可以在执行 transform
动画时利用 GPU 进行硬件加速。
相比之下,像 height
或者 margin
这样的属性会触发 CSS 布局变动,因此执行它们的动画效果更昂贵,需要谨慎使用。
JavaScript 钩子
你可以通过监听 <Transition>
组件事件的方式在过渡过程中挂上钩子函数:
示例
<Transition
@before-enter="onBeforeEnter"
@enter="onEnter"
@after-enter="onAfterEnter"
@enter-cancelled="onEnterCancelled"
@before-leave="onBeforeLeave"
@leave="onLeave"
@after-leave="onAfterLeave"
@leave-cancelled="onLeaveCancelled"
>
<!-- ... -->
</Transition>
// 在元素被插入到 DOM 之前被调用
// 用这个来设置元素的 "enter-from" 状态
function onBeforeEnter(el) {}
// 在元素被插入到 DOM 之后的下一帧被调用
// 用这个来开始进入动画
function onEnter(el, done) {
// 调用回调函数 done 表示过渡结束
// 如果与 CSS 结合使用,则这个回调是可选参数
done()
}
// 当进入过渡完成时调用。
function onAfterEnter(el) {}
// 当进入过渡在完成之前被取消时调用
function onEnterCancelled(el) {}
// 在 leave 钩子之前调用
// 大多数时候,你应该只会用到 leave 钩子
function onBeforeLeave(el) {}
// 在离开过渡开始时调用
// 用这个来开始离开动画
function onLeave(el, done) {
// 调用回调函数 done 表示过渡结束
// 如果与 CSS 结合使用,则这个回调是可选参数
done()
}
// 在离开过渡完成、
// 且元素已从 DOM 中移除时调用
function onAfterLeave(el) {}
// 仅在 v-show 过渡中可用
function onLeaveCancelled(el) {}
这些钩子可以与 CSS 过渡或动画结合使用,也可以单独使用。
在使用仅由 JavaScript 执行的动画时,最好是添加一个 :css="false"
prop。这显式地向 Vue 表明可以跳过对 CSS 过渡的自动探测。除了性能稍好一些之外,还可以防止 CSS 规则意外地干扰过渡效果:
<Transition
...
:css="false"
>
...
</Transition>
在有了 :css="false"
后,我们就自己全权负责控制什么时候过渡结束了。这种情况下对于 @enter
和 @leave
钩子来说,回调函数 done
就是必须的。否则,钩子将被同步调用,过渡将立即完成。
相关CSS库
GSAP 库
Anime.jsAnime.js
Motion One
可复用过渡效果
得益于 Vue 的组件系统,过渡效果是可以被封装复用的。要创建一个可被复用的过渡,我们需要为 <Transition>
组件创建一个包装组件,并向内传入插槽内容:
<!-- MyTransition.vue -->
<script>
// JavaScript 钩子逻辑...
</script>
<template>
<!-- 包装内置的 Transition 组件 -->
<Transition
name="my-transition"
@enter="onEnter"
@leave="onLeave">
<slot></slot> <!-- 向内传递插槽内容 -->
</Transition>
</template>
<style>
/*
必要的 CSS...
注意:避免在这里使用 <style scoped>
因为那不会应用到插槽内容上
*/
</style>
现在 MyTransition
可以在导入后像内置组件那样使用了:
<MyTransition>
<div v-if="show">Hello</div>
</MyTransition>
出现时过渡
如果你想在某个节点初次渲染时应用一个过渡效果,你可以添加 appear
prop:
<Transition appear>
...
</Transition>