随着前端框架的快速更新迭代,现在的主流前端框架之一Vue.js迎来了它的新版本3.0。在今年2020的5月28日,Vue.js的作者尤雨溪公布了Vue3的整个设计过程,让我们来了解一下吧。
简单的来说,这个框架的版本更新一定是为了弥补前一个版本的不足之处,回想一下Vue2的出现也已经有四年之久了,尤大的团队也一直在研究新的版本的Vue,也就是Vue3。
翻阅了一下他们的Vue3设计过程可以了解到版本更新的原因有以下两点:
那么Vue3到底更新了什么呢?它有哪些新的特性?它相对于Vue2的优势是什么?Vue3如何进行使用?
别急,本文就将带着大家提前体验一下Vue3,以上的问题也会一一得到解答,大家也可以从中感受一下Vue3的魅力。
在体验Vue3之前,我们先来了解一下Vu3到底有哪些亮点之处
总共有6大两点:
在原本的Vue2中,每次DOM某个地方需要更新都需要遍历整个虚拟DOM,然后判断哪个地方需要进行更新,然后再重新渲染。而Vue3选择了一种新的渲染策略,即采用某些方式使得每次需要更新DOM时,无需遍历整个虚拟DOM树就可以检测到改变而进行DOM更新。
这个就时为了实现按需打包,我们知道Vue框架里有很多的API和模块,但是一个项目中不可能用到所有的API和模块,所以该功能就可以实现在打包时去除掉Vue中没有被用到的模块和API,使得整个项目大小大幅度减小。
根据官方的说法,Vue3如果只写入了一个 Hello World
,即没有用到任何的模块API,打包后的大小大约为 13.5kb
;若用到了所有的Vue3所有的模块,打包后的大小也就只有大约 22.5kb
;而Vue2若只写入了 Hello World
,并没有用到任何的模块API,打包后的大小大约为 32kb
左右,这就是因为Vue2中没有 Tree shaking
的原因。
从中可以看出,Vue3比Vue2更轻量。
为了更好的用户使用,Vue3使用了TS重新对Vue框架进行了重写,增加了对TS更好的支持。
Composition API
是为了解决原本Vue项目中代码逻辑分散而导致不易维护的问题
首先先来看一个图
这幅图里颜色相同的区域表示的是实现同一个功能的代码区域
图中左侧的是Vue2的一个API,叫做 Options
,就是我们代码中的 data
、methods
、mounted
……这些存储数据或方法的对象
我们都知道,在大的项目中,我们要实现一个组件的完整功能,需要上百甚至上千行代码。例如,我们要做一个轮播图组件,现在把图中左侧这一列图像看成是轮播图组件的代码,假设这里有1000行代码。
首先我们在 methods
里写了实现轮播功能的方法,然后在 mounted
里写上在进入页面时自动开启轮播功能的代码,此时又想起来应该加一个功能,在鼠标移入该组件时应暂停轮播,所以又在 methods
里新增了一个方法,如图
这时你就会有这种感受,仅仅为了实现一个轮播的功能,却在这个页面中的不同地方写了不同的代码,那这样维护起来就特别的麻烦了,假设你的轮播功能出bug了,你需要排查问题,这时你先检查 实现轮播功能的代码
有无问题,然后又往下翻几百行代码找到 鼠标移入暂停轮播的代码
,检查一下是否有问题,再又往下翻几百行代码找到 进入页面开启轮播的代码
是否又问题。最终一顿分析才能查出bug。
这样一来,代码逻辑在页面中比较分散,很难维护,所以Vue3舍弃了这种 Options API
,而换用 Composition API
,也就是图中右侧的部分。
我们来看一下,刚才举的例子如果换用 Composition API
会时什么样
所有实现轮播这一功能的代码都放在一起,也就自然方便了维护
Custom Renderer API
也算是Vue3一个很不错的亮点了,它的作用就是将我们的代码绘制到 canvas
画布上
Vue3实现了不再限于模板中的单个根节点
在Vue2中大家应该遇到过这样的情况
这个报错的原因是因为,Vue2要求组件模板中只能有一个根节点,而不可以有多个根节点,如图
图中这种情况就是有两个根节点,所以会报错。所以我们可以通过给这两个标签外部加一个节点来解决报错问题,如图
这样就不会在报错了,但有时会觉得这样特别麻烦,所以Vue3解决这个报错问题,实现了模板中不限于单个根节点,即即使有多个根节点也不会报错
在Vue3中,重写了虚拟dom的实现,并且针对编译模板进行了优化。
在上面我们讲到了,在Vue2中,每次更新dom都需要重新遍历整个虚拟dom树,检测到变化点再去做相应的更新。但是Vue3在每次更新dom时就不需要遍历整个虚拟dom树了,这是为什么呢?
这里先放上两个网址,分别可以查看到Vue2和Vue3的模板编译是如何的:
Vue的渲染过程是先将html模板生成一个 render
函数,然后再根据该 render
函数进行渲染的,我们首先来看一下Vue2的模板编译情况
图中左侧部分就是我们平时写的html模板,右侧部分则是该html模板编译后生成的 render
函数
接下来我们再来看一下Vue3的模板编译情况是如何的
很明显的可以看到,对比Vue2的 render
函数,在图中的第7行代码中多出了一个数字 1
和 /* TEXT */
,这是针对html模板打上了一个标记,告诉程序这个位置的数据是动态的(html模板中的{{ msg }}
是可能会改变的,是一个动态的数据),所以之后如果要更新dom,就会针对打上标记的位置进行遍历检测。
现在我们再在html模板上写上一个静态的数据,看看它是如何编译模板的
我们可以看到,我先给最外部的 div
加上了一个动态的 class
属性,即:class="isShow"
,所以编译后的 render
函数中的第11行代码中,有一个数字 9
、 注释 /* TEXT, PROPS */
以及 ["class"]
,表示html模板该处的 text
文本部分是动态的,属性 class
也是动态的,所以在后面更新dom时,会对该处的这两个值进行遍历检测;另外我们给属性name
赋值了 box
,该值是一个静态固定的值,所以在图中右侧的 render
函数中我们并没有看到对其有任何的标记,所以在之后更新dom时,会自动忽略该处的值。
这就是Vue3通过标记来追踪动态数据的绑定,从而节约遍历虚拟dom的大部分开学。
结合官方的说法,Vue3比Vue2的页面渲染速度提升了1.3倍~2倍,SSR(服务器渲染)速度提高了2倍~3倍
这里放上两者性能的对比图
虽然目前为止Vue3还未正式发布,但我们已经可以提前体验Vue3了,为了更好地进行版本的迭代更新,Vue3对Vue2进行了很大程度的兼容,并且还提供了一个版本升级工具,可以将原本的Vue2项目很好的升级到Vu3。接下来我给大家介绍一下升级Vue3的步骤
我们先通过 vue-cli
脚手架的 vue create 项目名
来创建一个 vue2项目,这里建议大家在创建时把 vue-router
和 vuex
一并安装上,因为等会在升级时,会把这两个一并升级,因此代码会有所变化。
那么我们现在只需要在原来的 vue项目目录下通过命令 vue add vue-next
来将Vue2升级成Vue3
在升级之前,我先记录一下几个文件的代码,可以方便我们看看升级前和升级后的差别
main.js
文件
vue-router
的 index.js
文件
vuex
的 index.js
文件
稍微等待一下,Vue3就升级成功了,结果如图
那么此时我们来看看升级后的Vue文件有哪些变化
main.js
文件
vue-router
的 index.js
文件
vuex
的 index.js
文件
对比一下各个文件升级前和升级后的区别,我们可以很明显地看到:
Vue2的文件中都是 import Vue from 'vue'
导入了整个Vue,也就是把所有的模块API都导入了,但是用到的API可能就那么几个,所以这非常影响性能
Vue3的文件都是将用到的Vue中的模块API单独地导出,而不是导入整个Vue,类似图中的 import { createApp } from 'vue'
,这样就跟吃自助时吃多少拿多少的道理一样,非常得节省代码性能的消耗。
到这里,Vue3就算已经升级成功了,接下来我们就来体验一下Vue3的一些新特性把。
这里主要是来体验一下 Composition API
的,首先了解一下 Composition API
新特性的入口—— setup()
函数,该函数是为组件提供的新属性。
上面说了,这个API主要就是为了整合代码,使得为了实现相同功能的代码集中在一起便于维护查看,我们来用一个简单的例子来感受一下
我们要实现以下这个功能
首先看看在Vue2里是如何实现的
<template>
<div>
<div>{{ count }}</div>
<button @click="add">增加</button>
</div>
</template>
<script>
export default {
name: "demo",
data() {
return {
count: 0
}
},
methods: {
add() {
this.count ++
}
}
}
</script>
我们可以看到,首先数据 count
和 方法 add
是分开的,分别分布在 data
属性 和 methods
属性中的,这也就是证明了,实现一个功能时,代码时分开的,如果这个组件里有很多很多功能,就会比较难找了。
接下来我们再来看一下在Vue3中是如何实现这一功能的吧
<template>
<div>
<div>{{ count }}</div>
<button @click="add">增加</button>
</div>
</template>
<script>
// 导入ref函数
import {ref} from 'vue'
function increase() {
// 声明响应式数据count,值为0
const count = ref(0)
// 创建方法add
const add = () => {
count.value ++
}
// 导出数据和方法,便于外界访问
return {
count,
add
}
}
export default {
name: 'demo',
setup() {
//调用increase函数,并获取 count 和 add
let {count, add} = increase()
//return出需要被访问的值和方法
return {
count,
add
}
}
}
</script>
Vue3中没有再使用 data
属性,而是通过使用vue中的 ref()
函数来命名响应式数据的,ref()
函数返回的是一个对象,我们命名的数据是存储在这个对象的 value
属性里的,如图
同样的也没有再使用 methods
属性,而是直接通过 function
命名一个函数即可
同时,为了让代码整合在一起,我们在最外部命名了一个 increase
函数,里面存放了所有的数据和方法。
在Vue3中有一个新的属性 setup()
,它可以看作是一个生命周期,介于 beforeCreate
与 created
之间,在这个生命周期内被 return
的值和方法可以被外界访问到
所以在代码中,我们直接调用了刚才将功能代码整合在一起的 inscrease
函数,同时获取了函数内 return
的两个变量,这是因为这两个变量是需要被访问的,例如 <div>{{ count }}</div>
中需要访问 count
;<button @click="add">增加</button>
中需要访问 add
方法。
不要看这一个简单的功能中,似乎Vue3显得更麻烦,其实在一个功能非常多的项目中,这样的逻辑方式会使代码阅读与维护起来非常的方便。
好了,Vue3的尝鲜就到这里了,但Vue3的功能和API远远不止这些,相信大家对Composition API
也有了深刻的印象,后面我会再出一篇博客来更详细地介绍这个API的更多用法,欢迎大家继续关注我~