Skip to content

Commit 3a450c4

Browse files
committed
feat: Vue性能优化方法
1 parent e027c69 commit 3a450c4

File tree

1 file changed

+98
-119
lines changed

1 file changed

+98
-119
lines changed

public/08-vue-perf/README.md

+98-119
Original file line numberDiff line numberDiff line change
@@ -1,41 +1,48 @@
11
## 你了解哪些Vue性能优化方法?
22

3-
### 答题思路:根据题目描述,这里主要探讨Vue代码层面的优化
3+
### 分析
44

5+
这是一道综合实践题目,写过一定数量的代码之后小伙伴们自然会开始关注一些优化方法,答得越多肯定实践经验也越丰富,是很好的题目。
6+
7+
### 答题思路:
8+
9+
根据题目描述,这里主要探讨Vue代码层面的优化
510

611
### 回答范例
7-
- 路由懒加载
12+
13+
- 我这里主要从Vue代码编写层面说一些优化手段,例如:代码分割、服务端渲染、组件缓存、长列表优化等
14+
15+
- 最常见的路由懒加载:有效拆分App尺寸,访问时才异步加载
816

917
```js
10-
const router = new VueRouter({
18+
const router = createRouter({
1119
routes: [
20+
// 借助webpack的import()实现异步组件
1221
{ path: '/foo', component: () => import('./Foo.vue') }
1322
]
1423
})
1524
```
1625

1726

1827

19-
- keep-alive缓存页面
28+
- `keep-alive`缓存页面:避免重复创建组件实例,且能保留缓存组件状态
2029

2130
```vue
22-
<template>
23-
<div id="app">
24-
<keep-alive>
25-
<router-view/>
26-
</keep-alive>
27-
</div>
28-
</template>
31+
<router-view v-slot="{ Component }">
32+
<keep-alive>
33+
<component :is="Component"></component>
34+
</keep-alive>
35+
</router-view>
2936
```
3037

3138

3239

33-
- 使用v-show复用DOM
40+
- 使用`v-show`复用DOM:避免重复创建组件
3441

3542
```vue
3643
<template>
3744
<div class="cell">
38-
<!--这种情况用v-show复用DOM,比v-if效果好-->
45+
<!-- 这种情况用v-show复用DOM,比v-if效果好 -->
3946
<div v-show="value" class="on">
4047
<Heavy :n="10000"/>
4148
</div>
@@ -48,82 +55,98 @@
4855

4956

5057

51-
- v-for 遍历避免同时使用 v-if
58+
- `v-for` 遍历避免同时使用 `v-if`:实际上在Vue3中已经是个错误写法
5259

5360
```vue
5461
<template>
5562
<ul>
5663
<li
5764
v-for="user in activeUsers"
65+
<!-- 避免同时使用,vue3中会报错 -->
66+
<!-- v-if="user.isActive" -->
5867
:key="user.id">
5968
{{ user.name }}
6069
</li>
6170
</ul>
6271
</template>
6372
<script>
64-
export default {
65-
computed: {
66-
activeUsers: function () {
67-
return this.users.filter(function (user) {
68-
return user.isActive
69-
})
70-
}
71-
}
73+
export default {
74+
computed: {
75+
activeUsers: function () {
76+
return this.users.filter(user => user.isActive)
77+
}
7278
}
79+
}
7380
</script>
7481
```
7582

7683

7784

78-
- 长列表性能优化
85+
- v-once和v-memo:不再变化的数据使用`v-once`
7986

80-
- 如果列表是纯粹的数据展示,不会有任何改变,就不需要做响应化
87+
```vue
88+
<!-- single element -->
89+
<span v-once>This will never change: {{msg}}</span>
90+
<!-- the element have children -->
91+
<div v-once>
92+
<h1>comment</h1>
93+
<p>{{msg}}</p>
94+
</div>
95+
<!-- component -->
96+
<my-component v-once :comment="msg"></my-component>
97+
<!-- `v-for` directive -->
98+
<ul>
99+
<li v-for="i in list" v-once>{{i}}</li>
100+
</ul>
101+
```
81102

82-
```js
83-
export default {
84-
data: () => ({
85-
users: []
86-
}),
87-
async created() {
88-
const users = await axios.get("/api/users");
89-
this.users = Object.freeze(users);
90-
}
91-
};
92-
```
93-
94-
95-
96-
- 如果是大数据长列表,可采用虚拟滚动,只渲染少部分区域的内容
97-
98-
```html
99-
<recycle-scroller
100-
class="items"
101-
:items="items"
102-
:item-size="24"
103-
>
104-
<template v-slot="{ item }">
105-
<FetchItemView
106-
:item="item"
107-
@vote="voteItem(item)"
108-
/>
109-
</template>
110-
</recycle-scroller>
111-
```
112-
113-
> 参考[vue-virtual-scroller](https://github.com/Akryum/vue-virtual-scroller)、[vue-virtual-scroll-list](https://github.com/tangbc/vue-virtual-scroll-list)
103+
按条件跳过更新时使用`v-momo`:下面这个列表只会更新选中状态变化项
114104

115-
105+
```vue
106+
<div v-for="item in list" :key="item.id" v-memo="[item.id === selected]">
107+
<p>ID: {{ item.id }} - selected: {{ item.id === selected }}</p>
108+
<p>...more child nodes</p>
109+
</div>
110+
```
116111

117-
- 事件的销毁
112+
> https://vuejs.org/api/built-in-directives.html#v-memo
113+
114+
118115

119-
Vue 组件销毁时,会自动解绑它的全部指令及事件监听器,但是仅限于组件本身的事件。
116+
- 长列表性能优化:如果是大数据长列表,可采用虚拟滚动,只渲染少部分区域的内容
120117

118+
```html
119+
<recycle-scroller
120+
class="items"
121+
:items="items"
122+
:item-size="24"
123+
>
124+
<template v-slot="{ item }">
125+
<FetchItemView
126+
:item="item"
127+
@vote="voteItem(item)"
128+
/>
129+
</template>
130+
</recycle-scroller>
121131
```
122-
created() {
123-
this.timer = setInterval(this.refresh, 2000)
124-
},
125-
beforeDestroy() {
126-
clearInterval(this.timer)
132+
133+
> 一些开源库:
134+
>
135+
> - [vue-virtual-scroller](https://github.com/Akryum/vue-virtual-scroller)
136+
> - [vue-virtual-scroll-grid](https://github.com/rocwang/vue-virtual-scroll-grid)
137+
138+
139+
140+
- 事件的销毁:Vue 组件销毁时,会自动解绑它的全部指令及事件监听器,但是仅限于组件本身的事件。
141+
142+
```js
143+
export default {
144+
created() {
145+
this.timer = setInterval(this.refresh, 2000)
146+
},
147+
beforeUnmount() {
148+
clearInterval(this.timer)
149+
}
127150
}
128151
```
129152

@@ -143,38 +166,20 @@
143166

144167
- 第三方插件按需引入
145168

146-
像element-ui这样的第三方组件库可以按需引入避免体积太大
169+
`element-plus`这样的第三方组件库可以按需引入避免体积太大
147170

148171
```js
149-
import Vue from 'vue';
150-
import { Button, Select } from 'element-ui';
172+
import { createApp } from 'vue';
173+
import { Button, Select } from 'element-plus';
151174

152-
Vue.use(Button)
153-
Vue.use(Select)
175+
const app = createApp()
176+
app.use(Button)
177+
app.use(Select)
154178
```
155179

156180

157181

158-
- 无状态的组件标记为函数式组件
159-
160-
```vue
161-
<template functional>
162-
<div class="cell">
163-
<div v-if="props.value" class="on"></div>
164-
<section v-else class="off"></section>
165-
</div>
166-
</template>
167-
168-
<script>
169-
export default {
170-
props: ['value']
171-
}
172-
</script>
173-
```
174-
175-
176-
177-
- 子组件分割
182+
- 子组件分割策略:较重的状态组件适合拆分
178183

179184
```vue
180185
<template>
@@ -199,37 +204,11 @@
199204
</script>
200205
```
201206

202-
203-
204-
- 变量本地化
207+
但同时也不宜过度拆分组件,尤其是为了所谓组件抽象将一些不需要渲染的组件特意抽出来,组件实例消耗远大于纯dom节点。参考:https://vuejs.org/guide/best-practices/performance.html#avoid-unnecessary-component-abstractions
205208

206-
```vue
207-
<template>
208-
<div :style="{ opacity: start / 300 }">
209-
{{ result }}
210-
</div>
211-
</template>
212209

213-
<script>
214-
import { heavy } from '@/utils'
215-
216-
export default {
217-
props: ['start'],
218-
computed: {
219-
base () { return 42 },
220-
result () {
221-
const base = this.base // 不要频繁引用this.base
222-
let result = this.start
223-
for (let i = 0; i < 1000; i++) {
224-
result += heavy(base)
225-
}
226-
return result
227-
}
228-
}
229-
}
230-
</script>
231-
```
232210

233-
211+
- 服务端渲染/静态网站生成:SSR/SSG
212+
213+
如果SPA应用有首屏渲染慢的问题,可以考虑SSR、SSG方案优化。参考[SSR Guide](https://vuejs.org/guide/scaling-up/ssr.html)
234214

235-
- SSR

0 commit comments

Comments
 (0)