跳到主要内容

4.1-优化

Create by fall on 01 Sep 2022 Recently revised in 29 Aug 2023

组件更新

组件更新的时机:

vue 中,组件会在其有一个以上 props 改变时更新。

<!-- 任意一个 prop 改变,都会触发更新-->
<ListItem
v-for="item in list"
:id="item.id"
:active-id="activeId" />

为了避免每次数据更改导致重新渲染,可以通过

<ListItem
v-for="item in list"
:id="item.id"
:active-id="activeId===item.id" />
// 仅当当前 ID 是 item.id 时,触发 vue 的更新

异步引入组件

Vue3 的异步组件需要通过 defineAsyncComponent 进行引入和模块拆分

<script>
import {defineAsyncComponent as asyncPart} from 'vue'
const AsyncComponent = asyncPart(()=>import('./components/MyChart.vue'))
const AsyncComponent = asyncPart(()=>{
return new Promise((resolve,reject)=>{
// ...
resolve(/* 获取的组件 */)
})
})
</script>
<template>
<AsyncComponent></AsyncComponent>
</template>

v-memo

组件懒加载

一般会使用 vue-router 进行拆分

例如:

在路由中,我们会使用:import()

new createRouter({
history: createWebHistory(import.meta.env.BASE_URL),
base: import.meta.env.BASE_URL,
routes: [
{
path: '/home',
name: 'home',
component: () => import('@/views/MainView.vue'),
children: pageRoutes
},
{
path: '/',
name: 'redirect',
redirect: '/home'
}
]
})

在 vue 文件,或者 main 文件内,如果想要对内容进行拆分,需要使用 defineAsyncComponent() 方法

import {  defineAsyncComponent } from 'vue'
app.component('FormItem', defineAsyncComponent(() => import('./views/right-panel/FormItem.vue')))

//
import { defineAsyncComponent } from 'vue'
const ChartCanvas = defineAsyncComponent(() => import('./chart-canvas/ChartCanvas.vue'))
interface AsyncComponentOptions {
loader: AsyncComponentLoader
loadingComponent?: Component // 加载时展示
errorComponent?: Component // 出错时的展示(超时或者错误)
delay?: number
timeout?: number // 超时时间
suspensible?: boolean
onError?: (
error: Error,
retry: () => void,
fail: () => void,
attempts: number
) => any
}

keep-alive

实现组件缓存,组件切换时,不会对当前组件进行卸载。

使用场景是嵌套 router-view

<keep-alive>
<router-view></router-view>
</keep-alive>

keep-alive 标签总共可以传递三个参数,includeexclude 分别表示,匹配成功的内容会不会被缓存,max 表示限制缓存的最大个数,默认为 10 个。

keep-alive 是通过 name 来进行判断和匹配缓存的,所以必须指定组件的 name

<keep-alive :include="params1" max="max">
<router-view></router-view>
</keep-alive>
<script setup>
const params1 = 'a,b'
const params2 = /a|b/
const params3 = ['a', 'b']
const max = 10 // 最大缓存数
</script>

keep-alive 包含的组件/路由中,会多出两个生命周期的钩子:activateddeactivatedactivated 会在组件第一次渲染时调用,之后如果激活了,也会去调用。

$route.meta.keepAlive 可以用来判断当前路由是否被缓存,可以利用这点添加骨架屏,以保证用户的体验。

Teleport

一套内置组件,可以将组件内部的一部分传送到 DOM 结构外层。

因为 position 的定位会因为 relative 而失效、z-index 等一系列原因,使用 <Teleport> 嵌套即可传送内容至所需的组件,避免受到一些组件的制约。

使用时一定要确保 to 的内容被渲染出来,如果是多个 Teleport 会依次渲染到目标

<template>
<button @click="open = true">Open Modal</button>
<Teleport :to="to" :disabled="disabled">
<div v-if="open" class="modal">
<p>Hello from the modal!</p>
<button @click="open = false">Close</button>
</div>
</Teleport>
</template>
<script setup>
const to = 'body' // CSS 选择器字符串,也可以是一个 DOM 元素对象。
// const to = '#tpp' // 传送到 id 为 tpp 的标签
const disabled = false // 表示是否禁用
</script>
<style>
.modal {
position: fixed;
z-index: 999;
top: 20%;
left: 50%;
width: 300px;
margin-left: -150px;
}
</style>

Suspense

模板编译器

组件模板如果是写在页面的 HTML 中,或者是字符串,Vue 需要将模板编译器运行在浏览器中。

如果提前进行了编译,就无须在浏览器中进行编译。

为了减小打包出的体积,vue 提供了多种格式的 构建文件 减小了文件的体积

  • 前缀为 vue.runtime.* 的文件是只包含运行时的版本:不包含编译器,当使用这个版本时,所有的模板都必须由构建步骤预先编译。
  • 名称中不包含 .runtime 的文件则是完全版:即包含了编译器,并支持在浏览器中直接编译模板。然而,体积也会因此增长大约 14kb。

追踪运行时错误

应用级错误处理 可以用来向追踪服务报告错误:

import { createApp } from 'vue'
const app = createApp(...)
app.config.errorHandler = (err, instance, info) => {
// 向追踪服务报告错误
}

虚拟DOM

当数据量达到极多的时候,交给 DOM 进行操作会导致应用变慢、卡顿

分析相关功能

PageSpeed Insights

app.config.performance 设置为 true 可一将 vue 特有的性能标记在 Chrome 开发者工具的性能时间线上。