持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第11天,点击查看活动详情。
前提
在学习Vue3之前,首先要知道一下Vue3的优点有哪些?
笼统的来说就是:
- Vue3可以更好的支持TypeScript
- 速度加快 打包速度减少了41%
- 内存减少了54%,渲染加快
具体来说:
- 重写了响应式系统、重写了虚拟DOM的实现,性能上得到了提升
- 新推出组合式API(composition API),使维护组件代码变得更简单
- 新增了一些功能,如Teleport、Suspense、片段
- 修改和优化了一些API(生命周期、动画类名),同时移除了一些API(如listeners、filter)
Vue3最重要的新特性就是composition API,也是接下来重点需要学习的。
setup
在vue组件中我们使用Composition API的地方,我们称为setup。setup执行的时机是在beforeCreate生命函数之前执行,因此在这个函数中是不能通过this来获取实例的;同时为了命名的统一,将beforeDestroy改名为beforeUnmount,destroyed改名为unmounted,因此vue3有以下生命周期函数:
- beforeCreate(建议使用setup代替)
- created(建议使用setup代替)
- setup
- beforeMount
- mounted
- beforeUpdate
- updated
- beforeUnmount
- unmounted
写一个简单的方法来进行对比vue2和vue3:
// vue2
<template>
<div class="home">{{ msg }},{{ showMessage() }}</div>
</template>
<script lang="ts">
import { defineComponent } from "vue";
export default defineComponent({
name: "Home",
data() {
return {
msg: "hello world",
};
},
methods: {
showMessage() {
return "大家好";
},
},
});
</script>
// vue3
<template>
<div class="home">{{ msg }},{{ showMessage() }}</div>
</template>
<script lang="ts">
import { defineComponent } from "vue";
export default defineComponent({
name: "Home",
setup() {
let msg = "hello world";
function showMessage() {
return "大家好";
}
return {
msg,
showMessage,
};
},
});
</script>
ref
ref()函数可以将数据转化为响应式数据,一般用来定义一个基本类型的响应式数据。
在使用ref之前需要在页面中进行引用:
import { ref } from "vue";
在setup中使用时:let count = ref(1);,此时如果要改变count变量的值的时候,改变的是count.value
页面完整代码如下:
<template>
<div>
<div>{{ count }}</div>
<button @click="increase()" type="button"></button>
</div>
</template>
<script lang="ts">
import { defineComponent, ref } from "vue";
export default defineComponent({
name: "ref",
setup() {
let count = ref(1);
let increase = () => {
console.log(count);
count.value++;
};
return {
count,
increase,
};
},
});
</script>
<style lang="scss" scoped>
button {
width: 100px;
height: 40px;
}
</style>
打印count:
reactive
reactive()函数的用法与ref()的用法像是,也是将数据变成响应式数据,当数据发生变化的时候模板视图也会自动更新;不同的是ref()用于基本数据类型,而reactvie()用于引用类型的数据,比如对象和数组。 ref其实也能响应式改变引用类型的值,不过不推荐使用;
<template>
<div>
<div class="" v-for="(item, index) in arr" :key="index">
{{ item.title }}:{{ item.value }}
</div>
<button @click="addData()">添加数据</button>
</div>
</template>
<script lang="ts">
import { defineComponent, reactive } from "vue";
export default defineComponent({
name: "reactive",
setup() {
let arr = reactive([ // 需要注意的是,用法和ref有些出入
{
title: "姓名",
value: "张三",
},
{
title: "姓名",
value: "李四",
},
{
title: "姓名",
value: "王五",
},
]);
let addData = () => {
arr.push({
title: "姓名",
value: "刘麻子",
});
};
return {
arr,
addData
};
},
});
</script>
响应式原理
面试中经常会被问,Vue3的响应式原理是什么?这里就顺道记录一下:
Vue3的响应式原理是通过Proxy(代理)对对象的属性值进行读写、添加、删除进行劫持,通过Reflect(反射)动态对被代理对象的属性进行特定的操作;Proxy和Reflect不支持IE浏览器,这也是Vue3不支持IE浏览器的主要原因之一。
Vue2的响应式原理是通过defineProperty对对象已有属性值的读取和修改进行劫持(监视/拦截),通过重写数组、更新数组一系列更新元素的方法来实现元素修改的劫持。
Object.defineProperty 不足在于:
Object.defineProperty只能劫持对象的属性(key值.Object.key()),因此我们需要对每个对象的每个属性进行遍历。Object.defineProperty不能监听数组。是通过重写数据的那7个可以改变数据的方法来对数组进行监听的。Object.defineProperty也不能对 es6 新产生的 Map、Set 这些数据结构做出监听。Object.defineProperty也不能监听新增和删除操作,通过Vue.set()和Vue.delete来实现响应式的。
Vue3用Proxy的优势如下:
- 可以直接监听整个对象而非属性。
- 可以直接监听数组的变化。
- 有13中拦截方法,如
ownKeys、deleteProperty、has等是Object.defineProperty不具备的。 - 返回的是一个新对象,我们可以只操作新的对象达到目的,而
Object.defineProperty只能遍历对象属性直接修改;
未完待续~