[重构倒数第11天] - 如何在 Vue 中写出高效能的网页渲染方式 ?

前言

该系列是为了让看过Vue官方文件或学过Vue但是却不知道怎麽下手去重构现在有的网站而去规画的系列文章,在这边整理了许多我自己使用Vue重构很多网站的经验分享给读者们。

我们在开发网页的时候都希望我们的网页不管是在第一次进来的时候快速的将画面给渲染出来,又或是当我们在操作 ui 的时候,画面上面更新流畅且不会卡顿,今天我们就要来谈一谈几种提升页面渲染效能的方式,正所谓积少成多,当这些小细节累积起来的时候,节省掉的效能其实也是很可观的,就让我们来看一下Vue3 中对於效能上面的优化的操作吧!

MIKE VUE

第一种 : computed 用的好,资料处理没烦恼!

我在前面的章节不知道介绍过几次 computed 了,但是 computed 是真的很重要,所以才又提到了,我们再来复习一下 computed 这个功能,我们再来看一下官方的说明。

computed 是一个计算属性,设计它的初衷是用於简单运算的,在模板中放入太多的逻辑会让模板过重且难以维护,所以会需要透过computed 来重新处理过那些复杂的资料,官方文件有提到说

computed 属性是基於Vue绑定的资料依赖关系缓存的
官方文件 : https://v3.vuejs.org/guide/computed.html#computed-properties

这意味者 computed 只在透过 Vue 绑定的资料发生改变时它们才会重新去执行处理计算,所以今天你的资料只要是 Vue 绑定的资料,都可以被计算处理过。

我们在前面已经知道透过 computed 的缓存,可以避免重复性的函式执行,减少渲染上面的效能浪费,除来逻辑上面的计算以外,computed也可以搭配 reactive来使用,可以更方便的去重组资料,又不用重新去宣告新的 ref 变数来储存,我们来看一下下面这个例子。

下面这是我打非同步所取得的资料格式。

[
  {
    createdAt: "2021-09-16T01:52:45.780Z",
    name: "Regina Dooley",
    avatar: "https://cdn.fakercloud.com/avatars/kolmarlopez_128.jpg",
    post_date: 1631766938728,
    photo: "http://placeimg.com/640/480",
    content: "connect redundant driver",
    type: "cat",
    id: "1"
  },
  {
    createdAt: "2021-09-16T00:20:33.453Z",
    name: "Tricia Lang",
    avatar: "https://cdn.fakercloud.com/avatars/vaughanmoffitt_128.jpg",
    post_date: 1631766938728,
    photo: "http://placeimg.com/640/480",
    content: "index auxiliary alarm",
    type: "fish",
    id: "2"
  },
	// 以下省略
]

我现在有个需求,我希望依照现在拿到的资料,另外再产生三份不同的资料,一个是把资料变成map的资料格式,另外两个是依照 type 来产生另外两个分类好的 array,如果是一般的做法肯定会写好几个 function 或是宣告几个专门来处理及存放资料的变数,然後当今天重新再打一次 API 的时候,你的资料还要同时同步去做处理转换格式分类这些事情.这些我们全部可以透过 computed+ reactive 来组合完成。

我们来看看 code

const userInfo = reactive({
  data: [],
  dataMap: computed(() => {
    const map = {};
    for (const item of userInfo.data) {
      map[item.id] = item;
    }
    return map;
  }),
  catType: computed(() => {
    return userInfo.data.filter((item) => item.type === "cat");
  }),
  fishType: computed(() => {
    return userInfo.data.filter((item) => item.type === "fish");
  }),
});

你会发现我这边在 reactive 里面定义的资料用了 computed 来做计算,所以今天我打 API 拿资料的时候,我只要去负责更新 data 的资料就好,其他的资料会因为data被更新了後,computed就会自动帮我重新计算,所以今天如果资料没有被改变,它也就不会重新去执行,你可以看看实际完成的范例,透过这样的方式定义资料我们就只要专注在更新资料,其他处理交给 computed

codesandbox 范例:https://codesandbox.io/s/vue-performance-update1-0fqru?file=/src/App.vue

Computed vs Methods

前面的章节我们有提到 Computed 也有许多地方跟 Methods 很像,而且 Methods 能传入参数,文件上面也有特别针对这件事情去说明,有兴趣的可以看这边。

官方文件: https://v3.vuejs.org/guide/computed.html#computed-caching-vs-methods
上次提到的地方:https://ithelp.ithome.com.tw/articles/10262040

第二种 : 唯一的 key 就是为了让 Vue 记住你!

key 是一个在 vue 里面比较特殊的 attribute,专门用来比较 Virtual DOM 的新旧节点,所以当今天使用了 key 的话,他会依照 key 的顺序变化重新排列元件,并且那些不存在的 key 的元件给销毁,如果不给 key ,Vue 就会大范围修改或是重复更新相同的元件,造成不必要的效能浪费。

key 是需要唯一的识别码,可以用 number 或是 string。

最常会用到 key 的地方就是 v-for 的列表这边。

<ul>
  <li v-for="item in DataArray" :key="item.id">...</li>
</ul>

在很多网站上面都会有需要资料的列表,还有列表之间的操作,不管是删除、新增、还是重新排序、甚至是修改,这些的操作都会影响到列表的更新,所以今天只要透过 key 的绑定,vue 就会知道被修改的是那一个 DOM,进而只去对该物件修改而已,就不会大范围的去重新渲染没有改变资料的地方了。

很多人会说既然 key 是需要唯一的值,那我就拿 v-for 的索引来做就好了啊! 拜托不要阿!

// 错误的写法
<ul>
  <li v-for="(item, idx) in DataArray" :key="idx">...</li>
</ul>

你拿阵列的索引来当作你的 key ,但是今天遇到了排序或是删除的情况,索引是跟着 array 的,所以这时候的执行就会发生问题,拜托千万不要用索引当作你的key,甚至我还看过下面这种写法

// 错误的写法
<ul>
  <li v-for="(item, idx) in DataArray" :key="'test-' + idx">...</li>
</ul>

这样有差吗XDD 还不是拿索引来作为key的其中一个元素,所以开发上面要特别注意。

第三种 : 看好了世界! 关於 v-once 我只执行一次 !

我们再做网页的时候常常会有很多页面或是元件没有需要动态去替换,甚至是写死的内容,但是往往会因为周遭的组件或是父层而影响到去重新渲染。我们可以再组件或是 DOM元素上面使用 v-once这个方法,来达到这些挂载 v-once的组件不会重复的去渲染,它就只会渲染一次,下了 v-once的组件或是DOM元素内的所有子节点也都不会被重新渲染,可以说是节省掉许多额外的效能消耗。

<header v-once>
    <img src="logo.svg" class="avatar" />
    <nav>
        <a>HOME</a>
        <a>ABOUT</a>
        <a>ADDRESS</a>
    </nav>
</header>

例如我们网站的 header 或是 footer 都很常内容都是固定的,所以这类型就很适合使用 v-once这个功能。

<ul>
  <li v-for="i in list" v-once>
  	// ...
  </li>
</ul>

或是很多的列表其实也不需要做更新,所以也很常利用 v-forv-once来做搭配,这样一来页面其他的地方更新,也不会来影响到这些原本就是静态的内容。

第四种 : 渲染优化的新功能 v-memo

v-memo 是 vue3.2 才有的一个新功能,主要功能跟 v-once 非常类似,但不一样的地方是 v-once 是只要用了就会直接停止渲染後续更新行为,但是v-memo 是有条件的停止後续的渲染,我们来看一下官网上面的案例是如何使用。

<div v-memo="[valueA, valueB]">
    // ...
</div>

这边的 v-memo可以传入一笔或多笔的资料去进行记忆比对,当如果阵列里面每一个value跟上次渲染的时候一样,它的所有子元件跟节点就都不会重新去渲染,所以今天如果是里面的内容会依照资料的不同而进行渲染的话, v-memo的做法就可以再一定程度上面达到渲染优化的效果。

v-memo官方文件: https://v3.vuejs.org/api/directives.html#v-memo

But...

我尝试了用 v-memo 写一个范例,但是不管我怎麽测试都还是有一点状况,甚至也有国外的开发者在 issues上面去询问有关 v-memo 使用上的问题,所以我猜测可能是还有一些问题需要被解决,我在写这篇文章的时候 Vue 是3.2.11版本,希望之後的版本可以解决这个问题,或是官方可以针对 v-memo 再多做一些详细的解说及用法,之後我有实际测试出来更详细的资讯我会再补上来的。

根据 Vue 的爸爸 Evan You 所说,v-memo 的功能出现大幅度提高了 Vue 在前端框架效能速度的排名,成为最快的主流框架之一。

VUE

原文 : https://blog.vuejs.org/posts/vue-3.2.html

先告一个段落

我们今天说了几个在Vue的开发上面能针对操作上面的更新渲染的效能提升方式,希望大家在开发的时候也能多多注意这些细节,好啦! 我们明天见吧!

QRcode

那如果对於Vue3不够熟的话呢?

Ps. 购买的时候请登入或注册该平台的会员,然後再使用下面连结进入网站点击「立即购课」,这样才可以让我获得更多的课程分润,还可以帮助我完成更多丰富的内容给各位。

我有开设了一堂专门针对Vue3从零开始教学的课程,如果你觉得不错的话,可以购买我课程来学习
https://hiskio.com/bundles/9WwPNYRpz?s=tc

那如果对於JS基础不熟的朋友,我也有开设JS的入门课程,可以参考这个课程
https://hiskio.com/bundles/b9Rovqy7z?s=tc

订阅Mike的频道享受精彩的教学与分享

Mike 的 Youtube 频道
Mike的medium
MIke 的官方 line 帐号,好友搜寻 @mike_cheng


<<:  [Day-11] 巢状式if小练习

>>:  Day05:【TypeScript 学起来】TS 指定型别的三种方法

[Day 18] 资料产品生命周期管理-自动决策

如同前面所说,资料模型需要运用到实际环境中才会发挥价值 Initiation 延续之前辅助决策的初始...

(30) 试着学 Hexo - 奇淫技巧 - 财富自由

前言 接下来这一篇当作讲讲废话,因此标题也很 X 话,但其实写部落格是真的可以赚一点点钱的唷。 写部...

Day29 - [Shioaji] 超入门!永丰证券程序交易API快速上手 (2)

今天来看一下如何使用Shioaji问回历史交易资料,不过在此先提醒一下,上一篇有讲到的永丰讲师的Yo...

Day20:Flow 想在其他的执行绪执行,可以吗?

Flow 是属於 coroutine 范围项目,coroutine 中一个重要的特点可以轻易的切换执...

Day 12 - 在 FRRouting 上设定 BGP

在 VyOS 上设定好 BGP 後,我们来 FRRouting 上设定吧! 环境 我们这次内网使用 ...