欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

vue 3初体验以及和vue 2的区别

程序员文章站 2022-07-12 20:54:08
...

前言

经过了漫长的迭代,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>

vue 3初体验以及和vue 2的区别
虽然代码顺序打乱,但是执行顺序还是和以前一样的

组件Api的使用

setup

setup替代了以前的 beforeCreate 和 created ,类似于初始化的功能

//props 接收的父组件传的参数,这就有点像react的props了
//ctx 这个参数表示的当前对象实例,也就个是变相的this
setup(props,ctx){
 console.log(props.msg, ctx);
}

props为父组件传过来的参数,ctx为组件上下文
vue 3初体验以及和vue 2的区别
如果你还想要更多当前组件相关的属性,还可以从组合Api 里引用 getCurrentInstance

     import {getCurrentInstance } from "@vue/composition-api";
     const  all  = getCurrentInstance()
     console.log(all);

vue 3初体验以及和vue 2的区别

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迁移

相关标签: vue