本章主题: 掌握 Vue组件的高级用法、自定义插件和自定义指令的使用、SSR 同构的概念
一、组件的高级用法
1.1 动态组件
场景: 根据业务形态决定组件的类型
html
<template>
<component :is="component" :key="component"></component>
</template>
面试官: 动态组件的生命周期是什么样子的? | 动态组件是否会缓存? | 动态组件是否会存在不刷新的情况?
异步组件不会预加载 & 切换展示时才会初始化生命周期。
切换异步组件是一次性操作 | 每一次的切换都会更新生命周期(重新渲染实例)
面试官: 如何优化组件的加载?
加载文件 => 1. 独立拆包 2. 按需加载
面试官追问: 渲染时优化除了动态组件还有哪些方式?
控制引用 => 动态组件 | 异步加载组件 | 打包优化(external)
结论: 动态组件具备性能优势动态组件( 一种类型 ) & 异步组件指加载时机
动态指类型动态, 异步指加载时机不同。
动态占位 + 运行时切换 => 控制实时渲染 + 空间保留。
不会影响首屏渲染 和 缓存遗留。
1.2 内置高级组件
模板层的拓展
1.2.1 keepalive 缓存组件
面试官: 动态组件如何缓存? 持久化? 保留组件状态 | 如何实现组件状态的缓存 / 反销毁?
keep-alive - 保留实例 & 状态
追问: 控制缓存变量?
keep-alive 三个参数 include / exclude / max
include 需要缓存的组件: 字符串 | 数组 | 正则
exclude 不需要缓存的组件
max 先到先得 max="10" 我只缓存前 10 个。涉及缓存的一定要考虑阈值。
面试官: keep-alive 的使用场景
取决于业务中对于实例、生命周期的要求。Exclude
否则 KeepAlive
面试官: keep-alive 的实现原理
存在内存中, 实例名称(key): VNode(value)
LRU 算法策略:最近使用的进行永久存储, 达到极值删除最长时间没有使用的实例
html
<keep-alive include exclude max>
<router-view></router-view>
</keep-alive>
1.2.2 teleport 传送门组件
需求: 将组件渲染在与 app 同级的位置 , 即 body 下 和 其它任何地方
html
<!-- 使用 teleport 将模态窗口渲染到 body -->
<teleport to="body">
<div v-if="showModal" class="modal-overlay" @click="closeModal">
<div class="modal-content" @click.stop>
<h2>模态窗口</h2>
<p>这是一个使用 Vue Teleport 渲染的模态窗口。</p>
<button @click="closeModal">关闭</button>
</div>
</div>
</teleport>
1.2.3 suspense 等待加载组件 | pending 组件
异步组件有异步加载时间的。加载需要等待。
需求: 感知加载和加载完成。
作用: 判断异步组件是否加载成功
html
<template>
<Suspense>
<!--使用异步组件-->
<AsyncDialog />
<template #fallback>
<div>loading</div>
</template>
</Suspense>
</template>
优化加载体验
1.2.4 transition 过度态
html
<template>
<transition name="run">
<Suspense>
<!--使用异步组件-->
<AsyncDialog />
<template #fallback>
<div>loading</div>
</template>
</Suspense>
</transition>
</template>
三、自定义插件
custom.js
js
export default {
// app.use 就会调用 install
install: (app, options) => {
// app vue 实例
// options 传参
console.log(`app use`,app, options)
// app.config.globalProperties 拓展
app.config.globalProperties.$myPlugin = () => {
console.log("hello my plugin", options.version)
}
// 全局挂载如何使用呢?
}
}
main.js
js
import defaultPlugin from "custom.js"
app.use(defaultPlugin,{})
底层实现, 非代码层面的功能统一注入。
四、自定义指令
全局代码指令
如 v-if v-for v-show....
permission.jsimport directive from "../plugins/permission.js"
app.use(directive)
js
export default {
install: (app) => {
// app.directive 指令生成器
// <button v-permission="1">删除</button>
app.directive('permission', (el, binding){
// el 获取到绑定的节点
// binding => 1
// 1.代表管理员
if (binding.value === 1) return
// 非管理员账号 - 不展示当前按钮
if (el.parentNode) {
el.parentNode.removeChild(el)
} else {
el.style.display = 'none'
}
})
}
}
追问: 插件 & 指令 使用场景的区别
指令能实现的能力, 插件一定能实现。
插件是更底层的一种 vue 的拓展方式。
指令主要专注于 节点的 操作。
- 层级上插件更底层, 接近设计模式
- 指令更贴近节点
五、服务端渲染 SSR
生成服务
同构代码
entry-client.js
entry-service.js
app.js
作用维护状态