前端学习8 Vue2 和 Vue3
1.生命周期
对于生命周期来说,整体上变化不大,只是大部分生命周期钩子名称上 + “on”,功能上是类似的。不过有一点需要注意,Vue3 在组合式API(Composition API,下面展开)中使用生命周期钩子时需要先引入,而 Vue2 在选项API(Options API)中可以直接调用生命周期钩子。
import { onMounted } from 'vue'; // 使用前需引入生命周期钩子
// 可将不同的逻辑拆开成多个onMounted,依然按顺序执行,不会被覆盖
onMounted(() => {
// ...
});
beforeCreate() | setup() |
created() | setup() |
beforeMount() | onBeforeAMount() |
mounted() | onMounted() |
beforeUpdate() | onBeforeUpdate() |
undated() | onUpdated() |
beforeDestroy() | onBeforeunmount() |
destroyed() | onUnmounted() |
2.API
Vue2是选项API(Options API),一个逻辑会散乱在文件不同位置(data、props、computed、watch、生命周期钩子等),导致代码的可读性变差。当需要修改某个逻辑时,需要上下来回跳转文件位置。
Vue3组合式API(Composition API)则很好地解决了这个问题,可将同一逻辑的内容写到一起,增强了代码的可读性、内聚性,其还提供了较为完美的逻辑复用性方案。所有逻辑在setup函数中,使用 ref、watch 等函数组织代码。
3.setup函数
setup函数是组合式API的入口函数,默认导出配置选项,setup函数声明,返回模板需要数据与函数。
1.setup 函数是 Vue3 特有的选项,作为组合式API的起点
2.从组件生命周期看,它在 beforeCreate 之前执行
3.函数中 this 不是组件实例,是 undefined
4.如果数据或者函数在模板中使用,需要在 setup 返回
5.今后在vue3的项目中几乎用不到 this , 所有的东西通过函数获取。
4.响应式系统
Vue的响应式系统是其核心特性之一,它使得Vue能够智能地追踪数据变化并自动更新视图。Vue的响应式系统基于JavaScript对象的getter和setter属性,通过这些属性,Vue能够在数据变化时通知并更新视图。
Vue2通过Object.defineProperty来实现,vue3通过Proxy来实现数据劫持。数据劫持允许Vue监听数据的变化,当数据发生变化时,Vue会执行与数据相关的视图更新。
4.1 Object.defineProperty
通过递归遍历对象的每个属性,为每个属性设置 getter 和 setter,拦截属性的读取和修改操作。
object.defineProperty允许你定义或修改对象上的一个属性,并且可以指定该属性的访问器方法(getter和setter)。当属性被读取或设置时,相应的getter或setter将被调用。
所以他的缺点就是1.无法监听到数组的变化。2.必须遍历对象的每个属性。3.必须深层遍历嵌套的对象。
4.2 proxy
proxy创建一个对象的代理,拦截并自定义对象的基本操作(如属性访问、赋值、删除等),无需递归遍历。
ES6 原生提供 Proxy 构造函数,用来生成 Proxy 实例。
var proxy = new Proxy(target, handler);
// target 表示所要拦截的目标对象(任何类型的对象,包括原生数组,函数,甚至另一个代理))
// handler 通常以函数作为属性的对象,各属性中的函数分别定义了在执行各种操作时代理的行为
proxy主要使用的函数有以下几种:
get(target,propkey,receiver) 拦截对象属性的读取;
set(target,propkey,value,receiver) 拦截对象属性的设置;
deleteProperty(target,propKey):拦截delete proxy[propKey]的操作,返回一个布尔值;
4.2.1 get()
get()接受三个参数,依次为目标对象、属性名和 proxy 实例本身,最后一个参数可选。
var person = {
name: "张三"
};
var proxy = new Proxy(person, {
get: function(target, propKey) {
return Reflect.get(target,propKey)
}
});
proxy.name // "张三"
4.2.2 set()
set方法用来拦截某个属性的赋值操作,可以接受四个参数,依次为目标对象、属性名、属性值和 Proxy 实例本身。
其必须返回布尔值,表示是否成功删除。
// 创建一个普通用户对象
const user = {
name: "John",
age: 25
};
// 定义 Proxy 的处理器对象,包含 set 捕获器
const handler = {
set(target, property, value, receiver) {
// 1. 对 age 属性进行验证
if (property === 'age') {
if (typeof value !== 'number') {
throw new TypeError('年龄必须是一个数字');
}
if (value < 0) {
throw new RangeError('年龄不能为负数');
}
if (value > 150) {
throw new RangeError('年龄不能超过 150');
}
}
// 2. 合法时更新属性
const result = Reflect.set(target, property, value, receiver);
// 3. 记录变更日志
console.log(`属性 ${property} 被设置为 ${value}`);
return result; // 返回操作结果(布尔值)
}
};
// 创建代理对象
const userProxy = new Proxy(user, handler);
// 测试合法操作
userProxy.age = 30;
// 输出: "属性 age 被设置为 30"
console.log(userProxy.age); // 输出: 30
// 测试非法操作
try {
userProxy.age = -5; // 抛出 RangeError
} catch (error) {
console.error(error.message); // 输出: "年龄不能为负数"
}
try {
userProxy.age = "thirty"; // 抛出 TypeError
} catch (error) {
console.error(error.message); // 输出: "年龄必须是一个数字"
}
4.2.3 deleteProperty()
deleteProperty 是 JavaScript Proxy 对象的一个捕获器(trap),用于拦截对对象属性的 delete 操作。
const target = { id: 1, name: "John", role: "admin" };
const handler = {
deleteProperty(target, property) {
if (property === 'id') {
throw new Error('禁止删除 id 属性');
}
return Reflect.deleteProperty(target, property);
}
};
const proxy = new Proxy(target, handler);
// 正常删除
delete proxy.name; // 成功,target 变为 { id: 1, role: "admin" }
// 尝试删除 id
try {
delete proxy.id; // 抛出错误:禁止删除 id 属性
} catch (error) {
console.error(error.message);
}
5.多根节点
Vue2只能存在一个根节点,需要用一个div来包裹;Vue3 支持多个根节点,也就是 fragment。
// Vue2只能存在一个根节点,需要用一个<div>来包裹着
<template>
<div>
<header></header>
<main></main>
<footer></footer>
</div>
</template>
// Vue3支持多个根节点
<template>
<header></header>
<main></main>
<footer></footer>
</template>
#前端##前端入门#