Vue2和Vue3的不同点总结

406 阅读4分钟

Vue2和Vue3的不同点

双向数据绑定原理不同

  • Vue2使用ES5的API Object.defineProperty(obj,property,descriptor)对数据进行劫持,结合发布订阅模式来实现
  • Vue3使用代理new Proxy(target,handler),拦截对对象的操作,之后任何的操作都必须经过这道‘’拦截‘的处理

Object.defineProperty和Proxy对比

  • Proxy性能优于Object.defineProperty。 Proxy代理的是整个对象(即Proxy 是在更高维度上拦截属性),Object.defineProperty只代理对象上的某个属性,如果是多层嵌套的数据需要循环递归绑定
  • 对象上定义新属性时,Proxy可以监听到,Object.defineProperty监听不到,需要借助$set方法
  • Object.defineProperty不能监听到数组某些方法的变化(push、unshift和splice),Proxy可以监听到
  • Proxy在ie浏览器存在兼容性问题

diff算法的优化

  • vue2.x中的虚拟dom是进行**「全量的对比」**,在运行时会对所有节点生成一个虚拟节点树,当页面数据发生变化,会遍历判断virtual dom所有节点(包括一些不会变化的节点)有没有发生变化;如果拥有复杂的父子关系的VNode,会不断地递归调用 patchVNode,不断堆叠而成的几毫秒,最终就会造成 VNode 更新缓慢
  • 动静结合 PatchFlag--在Vue3.0中,在这个模版编译时,编译器会在动态标签末尾加上 /* Text*/ PatchFlag。「也就是在生成VNode的时候,同时打上标记,在这个基础上再进行核心的diff算法」并且 PatchFlag 会标识动态的属性类型有哪些,Vue3.0对于不参与更新的元素,做静态标记并提示,只会被创建一次,在渲染时直接复用

cacheHandlers 事件侦听器缓存

  • vue2.x中,绑定事件每次触发都要重新生成全新的function去更新
  • Vue3中提供了事件缓存对象,cacheHandlers,当 cacheHandlers 开启,会自动生成一个内联函数,同时生成一个静态节点。当事件再次触发时,只需从缓存中调用即可,无需再次更新

根节点差异

  • Vue3支持碎片(Fragment),可以拥有多个根节点,Vue2只能有一个根节点

     {/* vue2 */}
    <template>
      <div>
        这是根节点
      </div>
    </template>
    ​
     {/* vue3 */}
    <template>
      <div>
        这是根节点1
      </div>
      <div>
        这是根节点2
      </div>
    </template>
    
  • vue3会自动将多个标签用fragment包裹

image-20221103120451767.png 注:多根节点需要自己显式定义attribute应该分布在哪里,使用v-bind="$attrs"来指定将attribute添加到某个根节点(非props的attribute),单个根节点时,attribute会自动添加到根节点上

ps:除了少写个标签,减少了DOM元素的嵌套层级,我不知道Fragment还有其他什么妙用,望有大佬告知

选项式API(Options API)和组合式(Composition API)

  • Vue2使用的是选项式Api,Vue3增加了组合式Api

  • 选项式Api---多个选项的对象来描述组件的逻辑,例如 datamethodsmounted。选项所定义的属性都会暴露在函数内部的 this 上,它会指向当前的组件实例()

    <script>
    export default {
      data() {
        return {
          count: 0
        }
      },
    ​
      methods: {
        increment() {
          this.count++
        }
      },
    ​
      mounted() {
        console.log(`The initial count is ${this.count}.`)
      }
    }
    </script>
    
  • 组合式Api----使用导入的 API 函数来描述组件逻辑,组合式 API 通常会与<script setup> 搭配使用,这个 setup attribute 是一个标识,告诉 Vue 需要在编译时进行一些处理,让我们可以更简洁地使用组合式 API

    <script setup>
    import { ref, onMounted } from 'vue'const count = ref(0)
    ​
    function increment() {
      count.value++
    }
    ​
    onMounted(() => {
      console.log(`The initial count is ${count.value}.`)
    })
    </script>
    
  • 选项式 API 以“组件实例”的概念为中心对于有面向对象语言背景的用户来说,这通常与基于类的心智模型更为一致。同时,它将响应性相关的细节抽象出来,并强制按照选项来组织代码,从而对初学者而言更为友好。

  • 组合式 API 的核心思想是直接在函数作用域内定义响应式状态变量,并将从多个函数中得到的状态组合起来处理复杂问题。这种形式更加自由,也需要你对 Vue 的响应式系统有更深的理解才能高效使用。相应的,它的灵活性也使得组织和重用逻辑的模式变得更加强大。

生命周期差异

  • vue3中可以继续使用vue2.x中的生命周期钩子,但是有两个被改名:beforeDestroy改名为beforeUnmount、destroyed改名为unmounted

  • vue3也提供了Composition API形式的生命周期钩子,与vue2.x中钩子对应关系如下

    beforeCreate ====>setup()
    ​
    created =========>setup()
    ​
    beforeMount =====>onBeforeMount
    ​
    mounted ========>onMounted
    ​
    beforeUpdate ====>onBeforeUpdate
    ​
    updated ========>onUpdated
    ​
    beforeUnmount ===>onBeforeUnmount
    ​
    unmounted =======>onUnmounted
    ​
    activated =======>onActivated
    ​
    deactivated =====>onDeactivated
    

    vue3的组合式api中,setup中的函数执行相当于在选项api中的beforeCreate和created中执行,除了beforeCreate和created外,其他生命周期的使用都需要提前引入(轻量化)

Teleport---“传送门

Vue3中内置的一个组件,可以将一个组件的一部分模板“传送”到该组件的 DOM 层次结构之外的 DOM 节点中

teleport中存在两个参数:一个是to:表示指定传送的目标,另一个是disabled:表示是否禁用teleport的功能

<Teleport to="body">
    ........
</Teleport>

多个 <Teleport> 组件可以将其内容挂载在同一个目标元素上,而顺序就是简单的顺次追加,后挂载的将排在目标元素下更后面的位置上。

style中使用变量

vue3可以在样式用使用变量

<script setup>
const fontSize = '14px'
</script>
<template>
  <p>hello</p>
</template>
<style scoped>
p {
  color: v-bind('fontSize');
}
</style>

createApp()和new Vue()

  • vue2的组件系统设计中,所有的vue实例是共享一个Vue构造函数对象的(包括全局指令/全局组件等)
  • 而Vue3的createApp方法可以返回一个提供应用上下文的应用实例,应用实例挂载的整个组件树共享同一个上下文
  • createApp有一种微前端的味道

v-if和v-for的优先级

  • 在vue2中:当v-if和v-for同时使用时,v-for的优先级高于v-if(因此我们通常需要计算属性先对数据进行加工处理,以达到性能优化的目的)
  • 在vue3中:当v-if和v-for同时使用时,v-if的优先级高于v-for

Vue.prototype 替换为 config.globalProperties

  • vue2中:绑定全局的变量、方法等:Vue.prototype.prototypeName = xxxx
  • vue3中:const app = createApp({}) app.config.globalProperties.prototypeName = xxxx

$listeners被移除

  • vue2中:使用attrs访问传递给组件的属性,使用attrs访问传递给组件的属性,使用listeners访问传递给组件的事件(需要结合inheritAttrs:false)。
  • vue3中:虚拟dom中,事件监听器仅仅是以on为前缀的属性

filters(过滤器)移除

  • Vue3取消了Vue2中的过滤器但是变相一下,可以在双括号表达式中使用方法

    <span>{{ filters(item) }}</span>
    

Typescript支持

  • Vue3是基于TypeScript编写的;
  • Vue2默认是不支持TypeScript的,需要借助插件使用TypeScript;