Vue2和Vue3
- Vue2 的
Options API
- Vue3 的
Composition API
Vue2
优点
- 响应式数据
- Options API
- SFC
- Vuex/Vue-Router
缺点
在一个组件仅承担单一逻辑的时候,使用 Options API 来书写组件是很清晰的。
但是在我们实际的业务场景中,一个父组件总是要包含多个子组件,父组件需要给子组件传值、处理子组件事件、直接操作子组件以及处理各种各样的调接口的逻辑,这时候我们的父组件的逻辑就会变得复杂。
我们从代码维护者的角度出发,假设这个时候有 10 个函数方法,自然我们要把他们放入到methods中,而这个 10 个函数方法又分别操作 10 个数据,这个 10 个数据又分别需要进行Watch操作。
这时候,我们根据Vue2的Options API的写法,就写完了 10 个method、10 个data、10 个watch,我们就将本来 10 个的函数方法,分割在 30 个不同的地方。
这时候父组件的代码,对代码维护者来说是很不友好的。
Vue3
优点
- 更强的性能,更好的 tree shaking
- Composition API + setup
- 更好地支持 TypeScript
缺点
使用Composition API在setup
这个舞台上尽情的表演之后,可能存在一个问题:那就是如何优雅地组织代码?
代码不能优雅的组织,在代码量上去之后,也一样很难维护。
SFC 写法变化
Vue2 一个普通的 Vue 文件
<template>
<div>
<p>{{ person.name }}</p>
<p>{{ car.name }}</p>
</div>
</template>
<script>
export default {
name: "Person",
data() {
return {
person: {
name: "小明",
sex: "male",
},
car: {
name: "宝马",
price: "40w",
}
};
},
watch:{
'person.name': (value) => {
console.log(`名字被修改了, 修改为 ${value}`)
},
'person.sex': (value) => {
console.log(`性别被修改了, 修改为 ${value}`)
}
},
methods: {
changePersonName() {
this.person.name = "小浪";
},
changeCarPrice() {
this.car.price = "80w";
}
},
};
</script>
采用 Vue3 Composition API 进行重写
<template>
<p>{{ person.name }}</p>
<p>{{ car.name }}</p>
</template>
<script lang="ts" setup>
import { reactive, watch } from "vue";
// person的逻辑
const person = reactive<{ name: string; sex: string }>({
name: "小明",
sex: "male",
});
watch(
() => [person.name, person.sex],
([nameVal, sexVal]) => {
console.log(`名字被修改了, 修改为 ${nameVal}`);
console.log(`名字被修改了, 修改为 ${sexVal}`);
}
);
function changePersonName() {
person.name = "小浪";
}
// car的逻辑
const car = reactive<{ name: string; price: string }>({
name: "宝马",
price: "40w",
});
function changeCarPrice() {
car.price = "80w";
}
</script>
采用 Vue3 自定义 Hook 的方式,进一步拆分
<template>
<p>{{ person.name }}</p>
<p>{{ car.name }}</p>
<p>{{ animal.name }}</p>
</template>
<script lang="ts" setup>
import { usePerson, useCar, useAnimal } from "./hooks";
const { person, changePersonName } = usePerson();
const { car } = useCar();
</script>
// usePerson.ts
import { reactive, watch } from "vue";
export default function usePerson() {
const person = reactive<{ name: string; sex: string }>({
name: "小明",
sex: "male",
});
watch(
() => [person.name, person.sex],
([nameVal, sexVal]) => {
console.log(`名字被修改了, 修改为 ${nameVal}`);
console.log(`名字被修改了, 修改为 ${sexVal}`);
}
);
function changePersonName() {
person.name = "小浪";
}
return {
person,
changePersonName,
};
}
// useCar.ts
import { reactive } from "vue";
export default function useCar() {
const car = reactive<{ name: string; price: string }>({
name: "宝马",
price: "40w",
});
function changeCarPrice() {
car.price = "80w";
}
return {
car,
changeCarPrice,
};
}
对比完之后,我们会发现,Vue3 可以让我们更好组织代码。person和car的逻辑都被单独放置在一块
仅仅是代码组织的优势吗?不不不,我们再看看模板中的一些变化
<template>
标签中起始便签可以不用<div>
标签,因为Vue3提供了片段的能力,使用Vue-detools中查看,可以看到有fragment
的标记- Watch也不需要罗列多个了,Vue3中支持侦听多个源
- 很自然的使用TypeScript,类型约束更加简单
性能方面
Vue3 主要在这几个方面进行了提升
- 编译阶段。对
diff
算法优化、静态提升等等 - 响应式系统。
Proxy()
替代Object.defineProperty()
监听对象。监听一个对象,不需要再深度遍历,Proxy()
就可以劫持整个对象 - 体积包减少。Compostion API 的写法,可以更好的进行
tree shaking
,减少上下文没有引入的代码,减少打包后的文件体积 - 新增片段特性。Vue 文件的
<template>
标签内,不再需要强制声明一个的<div>
标签,节省额外的节点开销