vue 3初体验以及和vue 2的区别
前言
经过了漫长的迭代,Vue 3.0终于在上2020-09-18发布了,带了翻天覆地的变化,使用了Typescript 进行了大规模的重构,带来了Composition API RFC版本,类似React Hook 一样的写Vue,可以自定义自己的hook ,让使用者更加的灵活,接下来总结一下vue 3.0 带来的部分新特性以及和vue 2.0的区别在哪里
vue 3的新特性
1,setup()
2,ref 、toRef、 toRefs
3,reactive()
4,computed()
5,watch、watchEffect
6,函数组件
7,other
vue 3 和vue 2的区别
1,生命周期的变化
Vue2.x | Vue3 |
---|---|
beforeCreate | 使用 setup() |
created | 使用 setup() |
beforeMount | onBeforeMount |
mounted | onMounted |
beforeUpdate | onBeforeUpdate |
updated | onUpdated |
beforeDestroy | onBeforeUnmount |
destroyed | onUnmounted |
errorCaptured | onErrorCaptured |
整体来看其实变化不大,使用setup代替了之前的beforeCreate和created,其他生命周期名字有些变化,功能都是没有变化的
2,使用proxy代替defineProperty
我们知道vue 2双向绑定的核心是:Object.defineProperty()。但是vue 2对数组对象的深层监听无法实现,因为组件每次渲染都是将data里的数据通过defineProperty进行响应式或者双向绑定上,之前没有后加的属性是不会被绑定上,也就不会触发更新渲染。我们看下语法
Object.defineProperty( Obj, 'name', {
enumerable: true, //可枚举
configurable: true, //可配置
// writable:true, //跟可配置不能同时存在
// value:'name', //可写死直
get: function () {
return def
},
set: function ( val ) {
def = val
}
} )
我们再来看下Proxy的语法
//两个参数,对象,13个配置项
const handler = {
get: function(obj, prop) {
return prop in obj ? obj[prop] : 37;
},
set:function(){ },
...13个配置项
};
const p = new Proxy({}, handler);
p.a = 1;
p.b = undefined;
console.log(p.a, p.b); // 1, undefined
console.log('c' in p, p.c); // false, 37
我们可以明显的看出defineProperty只能响应首次渲染时候的属性,而Proxy需要的是整体,不需要关心里面有什么属性
备注:defineProperty兼容到IE8,其他浏览器会有些许问题,但是Proxy除了IE,其他浏览器全部兼容,其实IE应该基本没人用了。
3,Diff算法的提升
vue 2提供类似于HTML的模板语法,它是将模板编译成渲染函数来返回虚拟DOM树。Vue框架通过递归遍历两个虚拟DOM树,并比较每个节点上的每个属性,来确定实际DOM的哪些部分需要更新所以会出现DOM的更新仍然涉及许多不必要的CPU工作
vue3对这个问题进行了3个方面的优化:
一
首先,在DOM树级别。我们注意到,在没有动态改变节点结构的模板指令(例如v-if和v-for)的情况下,节点结构保持完全静态。如果我们将一个模板分成由这些结构指令分隔的嵌套“块”,则每个块中的节点结构将再次完全静态。当我们更新块中的节点时,我们不再需要递归遍历DOM树 - 该块内的动态绑定可以在一个平面数组中跟踪。这种优化通过将需要执行的树遍历量减少一个数量级来规避虚拟DOM的大部分开销
二
其次,编译器积极地检测模板中的静态节点、子树甚至数据对象,并在生成的代码中将它们提升到渲染函数之外。这样可以避免在每次渲染时重新创建这些对象,从而大大提高内存使用率并减少垃圾回收的频率。
三
在元素级别。编译器还根据需要执行的更新类型,为每个具有动态绑定的元素生成一个优化标志。例如,具有动态类绑定和许多静态属性的元素将收到一个标志,提示只需要进行类检查。运行时将获取这些提示并采用专用的快速路径。
总结:这些技术大大改进了我们的渲染更新基准,Vue 3有时占用的CPU时间不到Vue 2的十分之一
4,typeScript的支持
vue3 借鉴了react hook实现了更*的编程方式,提出了Composition API,Composition API不需要通过指定一长串选项来定义组件,而是允许用户像编写函数一样*地表达、组合和重用有状态的组件逻辑,同时提供出色的TypeScript支持
解决了vue2.没有类型系统这个概念以及对于规模很大的项目,没有类型声明,后期维护和代码的阅读都是头疼的事情。
5,打包体积的变化
vue2:运行时打包是23k,但这只是没安装依赖的时候,随着依赖包和框架特性的增多,有时候不必要的,未使用的代码文件都被打包了进去,所以后期项目大了,打包文件会特别多还很大。
vue3: 通过将大多数全局API和内部帮助程序移动到Javascript的module.exports属性上实现这一点。这允许现代模式下的module bundler能够静态地分析模块依赖关系,并删除与未使用的module.exports属性相关的代码。模板编译器还生成了对树抖动友好的代码,只有在模板中实际使用某个特性时,该代码才导入该特性的帮助程序。
尽管增加了许多新特性,但Vue 3被压缩后的基线大小约为10 KB,不到Vue 2的一半
6,其他API和功能的改动
注释:这些小改动就不做更细的说明,只列举下。 详细使用看vue2的迁移部分
vue3整体梳理
组件基本结构分析
<template>
<div>
<h1>{{ msg }}</h1>
<h1>{{age}}</h1>
<button @click="increment">
count: {{ state.count }}, double: {{ state.double }},three:{{ three }},refnum:{{refnum}}
</button>
</div>
</template>
<script lang="ts">
//这里就是Vue3的组合Api了,这里跟react的 import { useState ,useEffect } from 'react' 有些类似,需要用啥引啥
import {ref, reactive, computed ,watchEffect,watch,defineComponent} from "@vue/composition-api";
export default defineComponent({
name: "HelloWorld",
props: {
msg: String,
},
//上面对比的时候说过,setup相当于beforeCreate 和created,简单理解就是初始化
setup() {
//这里通过reactive使state成为相应状态(后面会详细介绍)
const state = reactive({
count: 0,
//计算属性computed的使用更灵活了
double: computed(() => state.count * 2),
});
//computed也可以单独拿出来使用
const three = computed(() => state.count * 3)
//ref跟reactive作用一样都是用来双向绑定的,ref的颗粒度更小(后面详细对比)
const refnum = ref()
//这里的watchEffect只要里面的变量发生了改变就会执行,并且第一次渲染会立即执行,没有变化前后返回参数,无法监听整个reactive
watchEffect(() => {
refnum.value = state.count;
console.log(state, "watchEffect");
});
//watch里第一个参数是监听需要的变量,第二个是执行的回调函数,
watch(refnum,(a,b)=>{
console.log(a,b,'watch,a,b')
})
//所有的方法里再也不需要用this了,这是很爽的
function increment() {
state.count++;
}
//组中模板中需要的变量,都要通过return给暴露出去,就像当初data({return { } }) 是一样的
return {
state,
increment,
three,
refnum
};
},
});
</script>
!!!computed也在代码中使用了,具体用法请看注释(后面不再详细讲解)
生命周期的使用
生命周期命名改变了更有语义化了,使用方法也改变,使用前需要我们在组合Api里获取。
<script>
import {
reactive,
computed,
onMounted,
onBeforeMount,
onBeforeUpdate,
onUpdated,
onUnmounted,
onBeforeUnmount,
} from "@vue/composition-api";
export default {
setup() {
const state = reactive({
count: 0,
double: computed(() => state.count * 2),
});
function increment() {
state.count++;
}
onUpdated(() => {
console.log("onUpdated");
});
onUnmounted(() => {
console.log("onUnmounted");
});
onBeforeUnmount(() => {
console.log("onBeforeUnmount");
});
onBeforeUpdate(() => {
console.log("onBeforeUpdate1");
});
onMounted(() => {
console.log("onMounted");
});
onBeforeMount(() => {
console.log("onBeforeMount");
});
console.log("setup");
return {
state,
increment,
};
},
};
</script>
虽然代码顺序打乱,但是执行顺序还是和以前一样的
组件Api的使用
setup
setup替代了以前的 beforeCreate 和 created ,类似于初始化的功能
//props 接收的父组件传的参数,这就有点像react的props了
//ctx 这个参数表示的当前对象实例,也就个是变相的this
setup(props,ctx){
console.log(props.msg, ctx);
}
props为父组件传过来的参数,ctx为组件上下文
如果你还想要更多当前组件相关的属性,还可以从组合Api 里引用 getCurrentInstance
import {getCurrentInstance } from "@vue/composition-api";
const all = getCurrentInstance()
console.log(all);
ref 、toRef、 toRefs
import { ref , toRef , toRefs } from '@vue/composition-api'
setup(){
const obj = {age:12}
//初始化设置个响应式变量tor,函数中读取值要tor.value
let tor = ref(0)
//这里将对象转化成响应性,并设置key值,函数中读取值要toR._object
let toR = toRef(obj,'toR')
const state = reactive({
num:1,
name:'baby张'
})
return {
tor,
roR,
//toRefs针对的是使用了reactive的响应式对象,可以理解为将对象拆分成多个ref并进行双向绑定,外界可以读取到响应式的所有属性
...toRefs(state)
}
}
ref 就当作简单的双向绑定变量 toRef 就是把不是响应式的对象转化成响应式 toRefs 就是把响应式的reactive对象,分解成无数的 ref 双向绑定
备注:ref 双向绑定的数据,在函数里读取的时候需要 .value获取 2. dom里不需要我们+value 框架替我们自动解构了 3. 组件return的时候将 reactive的对象 toRefs ,可以使代码更简洁,又不会丢失双向绑定
reactive
1,reactive 内部是可以使用计算属性等各种方法,它只是把数据双向绑定了而已
2,reactive 后return 的数据最好是用toRefs 转化一下
3,跟 ref 混合使用时候可以用isRef 判断类型
watch、watchEffect
//这里的watchEffect只要里面的变量发生了改变就会执行,并且第一次渲染会立即执行,没有变化前后返回参数,无法监听整个reactive
watchEffect(() => {
refnum.value = state.count;
console.log(state, "watchEffect");s
});
//watch里第一个参数是监听需要的变量,第二个是执行的回调函数,
watch(refnum,(a,b)=>{
console.log(a,b,'watch,a,b')
})
1.watch 需要具体监听参数,watchEffect 不需要传入监听参数
2.watch 的回调函数跟以前一样有前后对比的参数,watchEffect 啥都没有
3.watch 只有监听属性变化才执行,watchEffect 第一次会立即执行
4.watch 和 watchEffect 都无法监听未被双向绑定的属性
5.watch 可以直接监听 ref 和 reactive 绑定的对象,watchEffect 不可以(ref的值要.value,reactive的值要具体到内部属性),只会执行第一次
Typescript的支持
TS的支持也是Vue3的重中之重,在vue2版本ts里应该好多人用过vue-property-decorator 或者Facebook的Flow,来写vue里的TS,有些装饰器器和属性也比较难以理解,比如:@Emit @Inject @Provice @Prop @Watch @Model Mixins 都需要一些学习,才能下手
Other
面我主要在大的方向给大家做了介绍,其实还有好多细节的改动。请移步
一步组件、指令、solt、过度class…更多更改看官网Vue2迁移
上一篇: vscode基础插件推荐