双向数据绑定原理不同
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>
</template>
{/* vue3 */}
<template>
这是根节点1
</div>
这是根节点2
</div>
</template>
vue3会自动将多个标签用fragment包裹
注:多根节点需要自己显式定义attribute应该分布在哪里,使用v-bind="$attrs"
来指定将attribute添加到某个根节点(非props的attribute),单个根节点时,attribute会自动添加到根节点上
ps:除了少写个标签,减少了DOM元素的嵌套层级,我不知道Fragment还有其他什么妙用,望有大佬告知
选项式API(Options API)和组合式(Composition API)
Vue2使用的是选项式Api,Vue3增加了组合式Api
选项式Api---多个选项的对象来描述组件的逻辑,例如 data
、methods
和 mounted
。选项所定义的属性都会暴露在函数内部的 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>
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访问传递给组件的属性,使用listeners访问传递给组件的事件(需要结合inheritAttrs:false)。
vue3中:虚拟dom中,事件监听器仅仅是以on为前缀的属性
filters(过滤器)移除
Vue3取消了Vue2中的过滤器但是变相一下,可以在双括号表达式中使用方法
<span>{{ filters(item) }}</span>
Typescript支持
Vue3是基于TypeScript编写的;
Vue2默认是不支持TypeScript的,需要借助插件使用TypeScript;