内置组件 Transition
它可以将进入和离开动画应用到通过默认插槽传递给它的元素或组件上。
触发:由 v-if 所触发的切换、由 v-show 所触发的切换、由特殊元素 <component> 切换的动态组件
当一个 <Transition> 组件中的元素被插入或移除时,会发生下面这些事情:
- Vue 会自动检测目标元素是否应用了 CSS 过渡或动画。如果是,则一些 CSS 过渡 class 会在适当的时机被添加和移除。
- 如果有作为监听器的 JavaScript 钩子,这些钩子函数会在适当时机被调用。
- 如果没有探测到 CSS 过渡或动画、也没有提供 JavaScript 钩子,那么 DOM 的插入、删除操作将在浏览器的下一个动画帧后执行。
过渡 class
v-enter-from:进入动画的起始状态。在元素插入之前添加,在元素插入完成后的下一帧移除。
v-enter-active:进入动画的生效状态。应用于整个进入动画阶段。在元素被插入之前添加,在过渡或动画完成之后移除。这个 class 可以被用来定义进入动画的持续时间、延迟与速度曲线类型。
v-enter-to:进入动画的结束状态。在元素插入完成后的下一帧被添加 (也就是 v-enter-from 被移除的同时),在过渡或动画完成之后移除。
v-leave-from:离开动画的起始状态。在离开过渡效果被触发时立即添加,在一帧后被移除。
v-leave-active:离开动画的生效状态。应用于整个离开动画阶段。在离开过渡效果被触发时立即添加,在过渡或动画完成之后移除。这个 class 可以被用来定义离开动画的持续时间、延迟与速度曲线类型。
v-leave-to:离开动画的结束状态。在一个离开动画被触发后的下一帧被添加 (也就是 v-leave-from 被移除的同时),在过渡或动画完成之后移除
比如:
<button @click="show = !show">Toggle</button>
<Transition name="fade">
<p v-if="show">hello</p>
</Transition>
/* 下面我们会解释这些 class 是做什么的 */
.fade-enter-active,
.fade-leave-active {
transition: opacity 0.5s ease;
}
.fade-enter-from,
.fade-leave-to {
opacity: 0;
}
钩子函数
<Transition
@before-enter="onBeforeEnter"
@enter="onEnter"
@after-enter="onAfterEnter"
@enter-cancelled="onEnterCancelled"
@before-leave="onBeforeLeave"
@leave="onLeave"
@after-leave="onAfterLeave"
@leave-cancelled="onLeaveCancelled"
>
<!-- ... -->
</Transition>
过渡模式 :'in-out' | 'out-in' | 'default' out-in表示 先执行离开动画,然后执行进入动画,特殊场景下有作用
嵌套形式:
<Transition duration="550" name="nested">
<div v-if="show" class="outer">
<div class="inner">Hello</div>
</div>
</Transition>
内置组件 TransitionGroup
<TransitionGroup> 支持和 <Transition> 基本相同的 props、CSS 过渡 class 和 JavaScript 钩子监听器,但有以下几点区别:
默认情况下,它不会渲染一个容器元素。但你可以通过传入 tag prop 来指定一个元素作为容器元素来渲染。
过渡模式在这里不可用,因为我们不再是在互斥的元素之间进行切换。
列表中的每个元素都必须有一个独一无二的 key attribute。
CSS 过渡 class 会被应用在列表内的元素上,而不是容器元素上。
举例:
<TransitionGroup name="list" tag="ul">
<li v-for="item in items" :key="item">
{{ item }}
</li>
</TransitionGroup>
.list-move, /* 对移动中的元素应用的过渡 */
.list-enter-active,
.list-leave-active {
transition: all 0.5s ease;
}
.list-enter-from,
.list-leave-to {
opacity: 0;
transform: translateX(30px);
}
/* 确保将离开的元素从布局流中删除
以便能够正确地计算移动的动画。 */
.list-leave-active {
position: absolute;
}
内置组件 KeepAlive
默认情况下,一个组件实例在被替换掉后会被销毁。这会导致它丢失其中所有已变化的状态 —— 当这个组件再一次被显示时,会创建一个只带有初始状态的新实例。
<KeepAlive> 默认会缓存内部的所有组件实例,但我们可以通过 include
和 exclude
prop 来定制该行为。这两个 prop 的值都可以是一个以英文逗号分隔的字符串、一个正则表达式,或是包含这两种类型的一个数组
比如:
<!-- 以英文逗号分隔的字符串 -->
<KeepAlive include="a,b">
<component :is="view" />
</KeepAlive>
<!-- 正则表达式 (需使用 `v-bind`) -->
<KeepAlive :include="/a|b/">
<component :is="view" />
</KeepAlive>
<!-- 数组 (需使用 `v-bind`) -->
<KeepAlive :include="['a', 'b']">
<component :is="view" />
</KeepAlive>
它会根据组件的 name 选项进行匹配,所以组件如果想要条件性地被 KeepAlive 缓存,就必须显式声明一个 name 选项。
传入 max
prop 来限制可被缓存的最大组件实例数
比如:
<KeepAlive :max="10">
<component :is="activeComponent" />
</KeepAlive>
其生命周期
export default {
activated() {
// 在首次挂载、
// 以及每次从缓存中被重新插入的时候调用
},
deactivated() {
// 在从 DOM 上移除、进入缓存
// 以及组件卸载时调用
}
}
注意:activated 在组件挂载时也会调用,并且 deactivated 在组件卸载时也会调用,
两个钩子不仅适用于 <KeepAlive> 缓存的根组件,也适用于缓存树中的后代组件
举例
<script setup>
import { shallowRef } from 'vue'
import CompA from './CompA.vue'
import CompB from './CompB.vue'
const current = shallowRef(CompA)
</script>
<template>
<div class="demo">
<label><input type="radio" v-model="current" :value="CompA" /> A</label>
<label><input type="radio" v-model="current" :value="CompB" /> B</label>
<KeepAlive>
<component :is="current"></component>
</KeepAlive>
</div>
</template>
组件CompA
<script setup>
import { ref } from 'vue'
const count = ref(0)
</script>
<template>
<p>Current component: A</p>
<span>count: {{ count }}</span>
<button @click="count++">+</button>
</template>
组件CompB
<script setup>
import { ref } from 'vue'
const msg = ref('')
</script>
<template>
<p>Current component: B</p>
<span>Message is: {{ msg }}</span>
<input v-model="msg">
</template>
内置组件Teleport
以将一个组件内部的一部分模板“传送”到该组件的 DOM 结构外层的位置去。(可以将该模板挂载到指定位置)
to prop 来指定传送的目标,可以是一个 CSS 选择器字符串,也可以是一个 DOM 元素对象。
禁用:disabled prop ,设置为true时则表示禁用
多个共享
比如:
<Teleport to="#modals">
<div>A</div>
</Teleport>
<Teleport to="#modals">
<div>B</div>
</Teleport>
<!--渲染后的结果-->
<div id="modals">
<div>A</div>
<div>B</div>
</div>
常用用法modal弹框,请参考 https://cn.vuejs.org/examples/#modal
内置组件Suspense
待深入理解使用场景
单文件组件
Vue 的单文件组件 (即 *.vue 文件,英文 Single-File Component,简称 SFC) 是一种特殊的文件格式,使我们能够将一个 Vue 组件的模板、逻辑与样式封装在单个文件中。
如何看待关注点分离
前端开发的关注点不是完全基于文件类型分离的。前端工程化的最终目的都是为了能够更好地维护代码。
脚手架
Vite Vite 是一个轻量级的、速度极快的构建工具,对 Vue SFC 提供第一优先级支持。
Vue CLI 是官方提供的基于 Webpack 的 Vue 工具链
路由
推荐 Vue Router
也可以通过动态组件的方式,监听浏览器 hashchange 事件或使用 History API 来更新当前组件。
状态管理
推荐使用Pinia
测试
单元测试、组件测试、端到端测试(Cypress)
推荐 Vitest
服务端渲染SSR
SSR 是 Server-Side Rendering,即服务端渲染的英文缩写。
优势:更快的首屏加载、统一的心智模型、更好的 SEO
静态站点生成 (Static-Site Generation,缩写为 SSG),也被称为预渲染,是另一种流行的构建快速网站的技术。
通用的解决方案(推荐第三方框架:Nuxt、Quasar)
性能优化
页面加载优化(选用正确的架构、包体积与tree-shaking、代码分割)
更新优化(props的稳定性、v-once、v-memo)
通用优化(大型虚拟列表、减少大型不可变数据的响应性开销、避免不必要的组件抽象)
安全
首要规则:不要使用无法信赖的模板
边界情况
强制更新(? 你可能写错了)$forceUpdate
低级静态组件与 v-once
渲染机制
编译:Vue 模板被编译为了渲染函数:即用来返回虚拟 DOM 树的函数。这一步骤可以通过构建步骤提前完成,也可以通过使用运行时编译器即时完成。
挂载:运行时渲染器调用渲染函数,遍历返回的虚拟 DOM 树,并基于它创建实际的 DOM 节点。这一步会作为响应式副作用执行,因此它会追踪其中所用到的所有响应式依赖。
更新:当一个依赖发生变化后,副作用会重新运行,这时候会创建一个更新后的虚拟 DOM 树。运行时渲染器遍历这棵新树,将它与旧树进行比较,然后将必要的更新应用到真实 DOM 上去。
web之外
配合 Electron 或 Tauri 构建桌面应用
配合 Ionic Vue 构建移动端应用
使用 Quasar 用同一套代码同时开发桌面端和移动端应用
使用 Vue 的自定义渲染 API 来构建不同目标的渲染器,比如 WebGL 甚至是终端命令行!