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包裹
注:多根节点需要自己显式定义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>
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中:使用listeners访问传递给组件的事件(需要结合inheritAttrs:false)。
- vue3中:虚拟dom中,事件监听器仅仅是以on为前缀的属性
filters(过滤器)移除
-
Vue3取消了Vue2中的过滤器但是变相一下,可以在双括号表达式中使用方法
<span>{{ filters(item) }}</span>
Typescript支持
- Vue3是基于TypeScript编写的;
- Vue2默认是不支持TypeScript的,需要借助插件使用TypeScript;