由浅入深破解 vue3.0 新特性

2020年09月18日,vue3.0正式发布。做为一个大的版本更新,Vue3.0相比于 Vue2.0,天然有着不小的变化。前端

其中,Vue3的一大核心特性是引入了Composition API(组合式API),那么相比于vue2.0,Composition API有什么不同?vue

1、Composition API

组合式 API和配置式 API有什么区别?

vue2.0(配置式 API)

在Vue2.x中,组件的主要逻辑是经过一些配置项来编写,包括一些内置的生命周期方法或者组件方法react

export default {
  name: 'test',
  components: {},
  props: {},
  data () {
    return {}
  },
  created(){},
  mounted () {},
  watch:{},
  methods: {}
}
复制代码

咱们一般将components、data、以及各类钩子和watch分开来写,而后经过options的形式传给vue实例。面试

vue 3.0(组合式 API)

setup() 函数是 vue3 中,专门为组件提供的新属性。它为咱们使用 vue3 的 Composition API 新特性提供了统一的入口,通俗点来讲就是啥玩意都能写到setup()里面。算法

import { fetchGetList } from '@/api/repositories'
import { ref, onMounted, watch, toRefs } from 'vue'

setup (props) {
  const repositories = ref([])
  const getList = async () => {
    repositories.value = await fetchGetList()
  }
  onMounted(getUserRepositories)
  watch(getUserRepositories)
  return {
    repositories,
    getUserRepositories
  }
}
复制代码

为何要选择组合式api?

咱们在进行组件式编程,同一个组件内可能要写很是多的功能,好比弹框、getList、add、update之类,在vue2.0时代,咱们的组件代码可能会这么写:typescript

vue2.0

export default {
  name: '',
  components: {
  },
  props: {
  },
  data() {
    return {
      // 踢足球
      football: '',
      // 打篮球
      basketball: '',
      // 打台球
      ....
    }
  },
  created() {
    // 踢足球
    // 打篮球
  },
  methods: {
    // 踢足球
    playFootball() {
      console.log(this.football)
    },
    // 打篮球
    playBasketball() {
      console.log(this.basketball)
    }
    // 打台球
    ....
  }
}
</script>
复制代码

分散在各个地方的逻辑片断,使咱们的组件愈来愈难以阅读,常常为了看一个功能要疯狂上下滑动屏幕,在各个区块里翻找和修改。编程

mixins

在vue2.0中还能够用mixins来进行抽象,可是用的时间长了,mixins就没那么香了api

Mixins的优势:

能够将代码按照功能组织区分缓存

Mixins的缺点:

存在冲突隐患,你有可能在使用过程当中出现属性或函数的重名冲突markdown

依赖关系不清晰,特别是在多个Mixins存在交流的状况下。

逻辑复用不够灵活,若是你须要在不一样的组件间差别化或配置化使用Mixins的话。

vue3.0

那么vue3.0的组合式 API应该怎么写呢:

<script>
export default {
  setup(props, ctx) {
    // 踢足球
    const useFootball = function(){
    }
    // 打篮球
    const useBasketball = function(){
    }
    return {
      useFootball,
      useBasketball
    }
  }
};
</script>
复制代码

没有了各类分散的区块,咱们能够写更少的代码,也更容易将能够复用的逻辑从组件里抽出到函数里。

Composition API的基础语法

ref或者reactive代替data中的变量

在Vue2.x中经过组件data的方法来定义一些当前组件的数据:

data() {
  return {
    name: 'test',
    list: [],
  }
},
复制代码

在Vue3中经过ref或者reactive建立响应式对象:

import {ref,reactive} from 'vue'
...
setup(){
  const name = ref('test')
  const state = reactive({
    list: []
  })
  return {
      name,
      state
  }
}
...
复制代码

ref将给定的值建立一个响应式的数据对象并赋值初始值(int或者string),reactive能够直接定义复杂响应式对象。为何reactive能够定义复杂的响应式对象这个后面会有说明。

setup()中使用props和this:

在Vue2.x中,组件的方法中能够经过this获取到当前组件的实例,并执行data变量的修改,方法的调用,组件的通讯等等

可是在Vue3中,setup()在beforeCreate和created时机就已调用,没法使用和Vue2.x同样的this,可是能够经过接收setup(props,ctx)的方法,获取到当前组件的实例和props:

export default {
  props: {
    name: String,
  },
  setup(props,ctx) {
    console.log(props.name)
    ctx.emit('event')
  },
}
复制代码

2、vue3.0的优化(更快、更小)

PatchFlag(静态标记)、hoistStatic(静态提高)

vue2.0的源码在处理虚拟DOM时,选择的是将template模板内的全部内容遍历,生成虚拟DOM,当有内容发生变化的时候,经过diff算法进行更新。可是HTML中除了双向绑定的动态数据,还有很是多的静态内容,每次都要参与遍历就会很是浪费性能。

image.png 能够看到vue3.0在生成虚拟DOM的时候,第二个 div 标签为绑定的变量,因此打上了 1 标签,表明的是 TEXT(文字),从而会将内容分为静态资源和动态内容,从而更新的时候只diff动态的部分。

具体的请看源码

image.png

咱们平时在开发过程当中写函数的时候,定义一些写死的变量时,都会将变量提高出去定义,Vue 3.0 在这方面也作了一样的优化

这表明了这个变量只会被建立一次,然后只须要引用就行了,从而提高性能

image.png

cacheHandler(事件缓存)

默认状况下 @click 事件被认为是动态变量,因此每次更新视图的时候都会追踪它的变化。

可是正常状况下,咱们的 @click 事件在视图渲染前和渲染后,都是同一个事件,基本上不须要去追踪它的变化,因此 Vue 3.0 对此做出了相应的优化叫事件监听缓存。

因而可知, 设置了cacheHandler后,静态标记为8的的动态节点变成了静态节点,从而不参与diff,提高了性能。

image.png

image.png

响应式对象(Proxy对象与reactive)

从字面意思来理解,Proxy对象是目标对象的一个代理器,任何对目标对象的操做(实例化,添加/删除/修改属性等等),都必须经过该代理器。所以咱们能够把来自外界的全部操做进行拦截和过滤或者修改等操做。

引用大佬的例子来展现下Proxy对象的功能:

let foo = {
    a:1,
    b:2
}
let handler = {
    set:(obj,key,value)=>{
        console.log('set')
        obj[key] = value
        return true
    }
}

let p = new Proxy(foo,handler)

p.a = 3 // 打印出console.log('set')
复制代码

相信全部的前端面试的时候都被问过这个问题,vue的双向数据绑定是怎么实现的?

标准答案应该都差很少:

Vue实现数据双向绑定主要利用的就是: 数据劫持和发布订阅模式。所谓数据劫持,就是利用JavaScript的访问器属性,即Object.defineProperty()方法,当对对象的属性进行赋值时,Object.defineProperty就能够经过set方法劫持到数据的变化,而后通知发布者(主题对象)去通知全部观察者,观察者收到通知后,就会对视图进行更新。

在Vue2.x中,使用Object.defineProperty()来实现响应式对象,对于一些复杂的对象,还须要循环递归的给每一个属性增长上getter/setter监听器,这使得组件的初始化很是耗时。vue3中,composition-api提供了一种建立响应式对象的方法reactive,其内部就是利用了Proxy API来实现的,这样就能够不用针对每一个属性来一一进行添加,减小开销提高性能。

reactive的源码

image.png

vue3.0更新的核心功能除了上面的内容,还包括Tree shaking支持、以及对typescript的支持,以及Fragments、等等小的东西,固然还有最重要的vite,都是值得了解一下的。

相关文章
相关标签/搜索