一、响应式-双向数据绑定原理发生了改变
Vue2 的双向数据绑定是利用ES5的一个APIObject.definePropert()
对数据进行劫持结合发布订阅模式的方式来实现的。Vue3中使用了ES6的Proxy API对数据代理。
Vue2使用defineProperty存在一些问题
- 对数组拦截有问题,需要做特殊处理
- 不能拦截新增、删除的属性
- defineProperty方案在初始化时候,需要深度递归遍历待处理的对象才能对它进行完全拦截,明显增加了初始化的时间。
Proxy代理
- 对数组进行拦截,还能对Map,Set实现拦截
- Proxy是懒处理行为,没有嵌套对象时,不会实施拦截,也使之初始化速度和内存得到改善。
- 由于Proxy是ES6的新特性,它在一些旧版本的浏览器中可能不被完全支持。而Object.defineProperty是ES5的标准,因此在大多数现代浏览器中都可以正常工作。
1.1 Vue2的响应式原理
Vue 2使用了一个名为Object.definePropert()
的API来实现数据的响应式。在Vue 2中,当你将一个对象传递给Vue实例作为其data选项时,Vue会遍历这个对象的属性,并使用Object.defineProperty()
为每个属性添加getter和setter方法。这样一来,当你访问或修改这些属性时,Vue就能够追踪到变化,并触发视图的更新。
数据劫持的概念是指在访问或修改对象属性时拦截这些操作并进行一些额外的处理。在Vue 2中,数据劫持是通过使用Object.defineProperty()
的getter和setter方法实现的。当你访问一个属性时,getter方法会被触发,而当你修改一个属性时,setter方法会被触发。通过在getter和setter方法中进行依赖收集和派发更新,Vue能够实现数据的响应式。
1.2 Vue3的响应式原理
Vue3对其响应式系统进行了重写,引入了一个名为Proxy的新API来实现数据的响应式。Proxy是ES6中的一个新特性,它允许你拦截对对象的访问、修改和删除等操作,并在拦截函数中执行自定义的逻辑。
在Vue 3中,当你将一个对象传递给Vue实例作为其data选项时,Vue会使用Proxy代理这个对象,并对对象的属性进行拦截。这样一来,当你访问或修改这些属性时,拦截函数会被触发,并且你可以在拦截函数中执行一些额外的逻辑,比如依赖收集和派发更新。
二、生命周期钩子Lifecyle Hooks
Vue2--------------vue3
beforeCreate -> setup()
created -> setup()
beforeMount -> onBeforeMount
mounted -> onMounted
beforeUpdate -> onBeforeUpdate
updated -> onUpdated
beforeDestroy -> onBeforeUnmount
destroyed -> onUnmounted
activated -> onActivated
deactivated -> onDeactivated
- setup() :开始创建组件之前,在beforeCreate和created之前执行。创建的是data和method
- onBeforeMount() : 组件挂载到节点上之前执行的函数。
- onMounted() : 组件挂载完成后执行的函数。
- onBeforeUpdate(): 组件更新之前执行的函数。
- onUpdated(): 组件更新完成之后执行的函数。
- onBeforeUnmount(): 组件卸载之前执行的函数。
- onUnmounted(): 组件卸载完成后执行的函数
若组件被<keep-alive>包含,则多出下面两个钩子函数。
- onActivated(): 被包含在中的组件,会多出两个生命周期钩子函数。被激活时执行 。
- onDeactivated(): 比如从 A组件,切换到 B 组件,A 组件消失时执行。
三、两种API风格
Vue2选项式 API 、Vue3组合式 API
3.1 选项式 API (Options API)
使用选项式 API,我们可以用包含多个选项的对象来描述组件的逻辑,例如 data
、methods
和 mounted
。选项所定义的属性都会暴露在函数内部的 this
上,它会指向当前的组件实例。
<script>
export default {
// data() 返回的属性将会成为响应式的状态
// 并且暴露在 `this` 上
data() {
return {
count: 0
}
},
// methods 是一些用来更改状态与触发更新的函数
// 它们可以在模板中作为事件处理器绑定
methods: {
increment() {
this.count++
}
},
// 生命周期钩子会在组件生命周期的各个不同阶段被调用
// 例如这个函数就会在组件挂载完成后被调用
mounted() {
console.log(`The initial count is ${this.count}.`)
}
}
</script>
<template>
<button @click="increment">Count is: {{ count }}</button>
</template>
3.2 组合式 API (Composition API)
通过组合式 API,我们可以使用导入的 API 函数来描述组件逻辑。在单文件组件中,组合式 API 通常会与 <script setup>
搭配使用。这个 setup
attribute 是一个标识,告诉 Vue 需要在编译时进行一些处理,让我们可以更简洁地使用组合式 API。比如,<script setup>
中的导入和顶层变量/函数都能够在模板中直接使用。
下面是使用了组合式 API 与 <script setup>
改造后和上面的模板完全一样的组件:
<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>
<template>
<button @click="increment">Count is: {{ count }}</button>
</template>
四、数据定义
在Vue2中,数据需要在data选项中定义,并且只有在data中定义的数据才会被Vue的响应式系统追踪和更新。
// Vue 2
export default {
data() {
return {
message: 'Hello, Vue 2!'
}
}
}
而在Vue 3中,可以直接使用ref或reactive函数来定义响应式数据,这样无需将数据放在data选项中。
// Vue 3
import { ref } from 'vue';
export default {
setup() {
const message = ref('Hello, Vue 3!');
// 组件逻辑
return {
message
};
}
}
在Vue 2中,组件的方法需要在methods选项中定义。
// Vue 2
export default {
methods: {
handleClick() {
// 处理点击事件的逻辑
}
}
}
而在Vue 3中,可以直接在setup函数中定义组件的方法,并将其返回。
// Vue 3
export default {
setup() {
const handleClick = () => {
// 处理点击事件的逻辑
}
// 组件逻辑
return {
handleClick
};
}
}
五、TypeScript
在Vue 2中,使用TypeScript需要进行额外的配置和安装相应的类型声明文件。Vue 2对于TypeScript的支持相对较弱,需要手动声明组件的类型。
Vue 3对TypeScript有更好的原生支持。Vue 3的API被设计为完全兼容TypeScript,可以更方便地编写类型安全的代码。