1. 双向数据绑定原理发生了改变
vue2的双向数据绑定是利用了es5 的一个API Object.definepropert() 对数据进行劫持 结合发布订阅模式来实现的。vue3中使用了es6的proxyAPI对数据进行处理。
相比与vue2,使用proxy API 优势有:defineProperty只能监听某个属性,不能对全对象进行监听;可以省去for in 、闭包等内容来提升效率(直接绑定整个对象即可);可以监听数组,不用再去单独的对数组做特异性操作,vue3可以检测到数组内部数据的变化。
2.Vue3支持碎片(Fragments)
vue2中必须要有根标签
vue3中可以没有根标签,会默认将多个根标签包裹在一个fragement虚拟标签中,有利于减少内存。
就是说在组件可以拥有多个根节点。
vue2
<template>
<div class='form-element'>
<h2> {{ title }} </h2>
</div>
</template>
vue3
<template>
<div class='form-element'>
</div>
<h2> {{ title }} </h2>
</template>
3.v-if和v-for的优先级
在vue2中v-for的优先级高于v-if,可以放在一起使用,但是不建议这么做,会带来性能上的浪费
在vue3中v-if的优先级高于v-for,一起使用会报错。可以通过在外部添加一个标签,将v-for移到外层.
4.key在template和v-if上的使用
vue2中:在使用v-if、vi-else、v-else-if时,为了保证dom节点渲染的正确性,通常需要在对应的节点添加不同的key,以确保vue在进行虚拟dom对比时是准确的;vue2中template在v-for循环时是不能设置key的,否则会产生警告(需要给子节点设置key)。
vue3中:在使用v-if、vi-else、v-else-if时,不用提供唯一的key对dom节点进行区分,因为vue内部会自动生成唯一的key,如果你提供了key,那你就要保证它的唯一性;vue3中template在v-for循环时,key应该设置在template标签上
5.$listeners被移除
vue2中:使用attrs访问传递给组件的属性,使用listeners访问传递给组件的事件(需要结合inheritAttrs:false)。
vue3中:虚拟dom中,事件监听器仅仅是以on为前缀的属性
6.Teleport
允许我们将指定内容渲染在指定的html标签上
Teleport一般被翻译成瞬间移动组件,实际上是不好理解的.我把他理解成"独立组件",
他可以那你写的组件挂载到任何你想挂载的DOM上,所以是很自由很独立的
7. Composition API
组合式API和选项式API
在vue2中采用选项式API,将数据和函数集中起来处理,将功能点切割了当逻辑复杂的时候不利于代码阅读。
在vue3中采用组合式API,将同一个功能的代码集中起来处理,使得代码更加有序,有利于代码的书写和维护,更加简便和整洁
8.sync修饰符
vue2中:由于vue中是单向数据流,父子组件在传值时想要实现v-model的效果就要用到.sync修饰符来实现"双向绑定"
vue3中:对v-model进行了改造,不再需要 .sync 修饰符即可达到数据双向绑定的效果。在vue3中支持多个 v-model属性,默认使用 modelValue 作为 prop,update:modelValue作为事件,当多个v-model绑定时,书写为例:v-model:title="title",此时 title 作为prop,update:title 作为事件
9.全局API
vue2中:有许多的全局API,如:Vue.directive、Vue.component、Vue.config、Vue.mixin等
vue3中:提供的是实例API,通过createApp创建vue实例,原来在Vue原型上的API都被挂载到了vue实例上,如:app.directive、app.component、app.config、app.mixin等
10.Vue.prototype 替换为 config.globalProperties
vue2中:绑定全局的变量、方法等:Vue.prototype.$ajax = xxxx
vue3中:const app = createApp({}); app.config.globalProperties.$ajax = xxxx
11. 建立数据data
vue2是把数据放入data中,vue3就需要使用一个新的setup()方法,此方法在组件初始化构造得时候触发。使用一下三个步骤来简=建立反应性数据: 1. 从vue引入reactive;使用reactive() 方法来声明数据为响应性数据;3. 使用setup()方法来返回我们得响应性数据,从而template可以获取这些响应性数据。
12.生命周期
vue2 --------------- vue3
beforeCreate -> setup()
Created -> setup()
beforeMount -> onBeforeMount
mounted -> onMounted
beforeUpdate -> onBeforeUpdate
updated -> onUpdated
beforeDestroyed -> onBeforeUnmount
destroyed -> onUnmounted
activated -> onActivated
deactivated -> onDeactivated
13.this
vue2中:无时无刻都要使用this
vue3中:因为setup函数的存在,所有的props、data等都不需要用this进行访问(vue3对vue2绝大多数是兼容的,如果你用了vue2相关的东西,那你还是需要像vue2一样书写)
13.typescript支持
vue2中:默认是不支持typescript的。
vue3中:支持使用typescript,使用typescript在构建大型项目时,能够很好的提高项目开发的质量。
14. 父子传参不同,setup()函数特性
setup()函数接收两个参数:props、context(包含attrs、slots、emit)
setup函数是处于生命周期beforeCreated和created俩个钩子函数之前
执行setup时,组件实例尚未被创建(在setup()内部,this不会是该活跃实例得引用,即不指向vue实例,Vue为了避免我们错误得使用,直接将setup函数中得this修改成了undefined)
与模板一起使用时,需要返回一个对象
因为setup函数中,props是响应式得,当传入新的prop时,它将会被更新,所以不能使用es6解构,因为它会消除prop得响应性,如需解构prop,可以通过使用setup函数中得toRefs来完成此操作。
父传子,用props,子传父用事件 Emitting Events。在vue2中,会调用this$emit然后传入事件名和对象;在vue3中得setup()中得第二个参数content对象中就有emit,那么我们只要在setup()接收第二个参数中使用分解对象法取出emit就可以在setup方法中随意使用了。
在setup()内使用响应式数据时,需要通过 .value 获取
import { ref } from 'vue'
const count = ref(0)
console.log(count.value)
从setup() 中返回得对象上得property 返回并可以在模板中被访问时,它将自动展开为内部值。不需要在模板中追加.value。
setup函数只能是同步的不能是异步的。