前端时间一直在研究Vue3,最近总算把笔记整理完了,在此记录下来,以备查阅。
虽然这篇内容不多,但是私以为看完这篇,对着代码写写,基本上也就入门Vue3了。
Vue3学习笔记:
1. setup生命周期等
在Vue3中,有一个setup函数,是新的组件选项,作为composition API的入口。
1. setup的调用时机:
-
创建组件实例,然后初始化props,接着调用setup函数。从生命周期来看,它是在beforeCreate之前被调用的。所有的组合API函数都在此使用,并且只被执行一次。
-
setup中的this是undefined,不能通过this来访问data/computed/methods/props,包括所有的组合式API中的相关回调函数都不可以
2. setup函数返回的是一个对象,对象中的属性或方法,可以直接使用。
如下代码中,setup返回了两个属性,一个是count变量,一个是updateCount函数,可以直接使用。
<template>
{
{
count}}
<br/>
<button @click="updateCount">更新数据</button>
</template>
<script lang='ts'>
import {
defineComponent, ref} from 'vue';
export default defineComponent ({
name: 'App',
setup(){
// html 模板中不需要.value属性的写法
let count = ref(11);
function updateCount(){
count.value++ ;
}
return {
count, // 返回的count属性可以直接使用
updateCount, // 函数也在此返回
}
}
})
</script>
另外,vue2中的data返回的配置项,也可以用在vue3中,用法与在Vue2中一致。但是并不推荐这样做。
同样的,vue2中定义method的方式,也可以用在vue3中,官方也不推荐这样使用。
methods中可以访问setup提供的属性和方法,但是setup中 无法访问data和methods。
setup不能是一个async函数,因为返回值不再是return对象,而是promise,模板看不到return对象中的属性数据。
3. setup参数:
写法:setup(props,context){} 或 setup(props,{attrs,slots,emit}){}
props: 包含了props配置中声明并传入的所有属性对象
attrs:包含没有在props中声明的所有属性对象,相当于this.$attrs
slots:包含所有传入的插槽对象,相当于this.$slots
emit:用来分发自定义事件函数,相当于this.$emit
2. 异步引入组件
异步引入组件的方法很多,在这里记录下3个:
- defineAsyncComponent异步加载组件
<template>
<AsyncCom />
</template>
import {
defineComponent, defineAsyncComponent} from 'vue';
// Vue3中静态引入组件的方法
const AsyncCom = defineAsyncComponent(()=>import('./AsyncCom.vue'));
export default defineComponent({
components:{
AsyncCom },
setup(){
return {
}
},
});
- setup中返回promise对象
export default defineComponent({
setup(){
return new Promise((resolve, reject)=>{
setTimeout(()=>{
resolve({
msg:'Hello world!'
});
},2000);
})
}
});
- setup和async/await结合使用
前面说过,setup不能是async函数,那是因为返回的是一个promise对象,模板看不到返回对象中的数据结构,所以需要把结果处理成模板可识别的结构,方能使用。
如下代码所示:
export default defineComponent({
// setup(){
// return axios.get('/data/address.json').then(response=>{
// return {
// data: response.data
// }
// });
// }
async setup(){
const result = await axios.get('/data/address.json');
return {
data: result.data
}
}
})
3. 数据代理源码分析
Vue2中数据代理用的是Object.defineProperty方法,Vue3中是通过Proxy和Reflect结合,实现数据代理的。proxy比Object.defineProperty高效,响应也更快。
代码见下:
// 模拟Vue3中的数据代理
let user = {
name: '路飞',
age: 20,
wife:{
name: '小樱',
age: 19,
};
const proxyUser = new Proxy(user,{
get(target,prop){
console.log('get方法调用了!');
return Reflect.get(target,prop);
},
// 修改目标对象的属性值/为目标对象添加新的属性
set(target,prop,value){
return Reflect.set(target,prop, value);
},
// 删除目标对象上的某个属性
deleteProperty(target,prop){
console.log('delete方法被调用了!');
return Reflect.deleteProperty(target, prop);
}
});
proxyUser.name = '路飞';
proxyUser.gender = '男';
delete proxyUser.gender;
proxyUser.wife.name = '小红';
4. ref和reactive的基本使用
Vue3中有两个新的API,ref和reactive都是用来把数据转换成响应式数据,ref用来处理基本数据,reactive用来处理对象(递归深度响应式数据)。
ref也可以传入对象类型的数据,其内部会自动调用reactive,把对象转为响应式数据。
ref:内部会给value添加getter和setter来实现数据劫持,在js/ts中,ref对象的值,需通过.value操作,而在模板中则不需要添加.value。
reactive:内部通过Proxy来实现对象内部所有属性的劫持,并通过Reflect操作对象内部数据。
<template>
<h1>用户1</h1>
<h2>姓名:{
{
user.name }}</h2>
<h2>年龄:{
{
user.age}}</h2>
<h2>性别:{
{
user.gender}}</h2>
<h2>wife: {
{
user.wife}}</h2>
<button @click="updateUser">更改数据</button>
<h2>App父级组件</h2>
<h3>{
{
msg}}</h3>
<button @click="msg+='='">Update</button> // 模板中不用调用msg.value即可操作ref中的数据
</template>
import {
defineComponent,reactive,ref } from 'vue';
export default defineComponent({
name: 'App',
setup(){
const obj: any = {
// 为了在使用obj.gender = "男"的时候不出现这种错误提示
name:"香吉士",
age: 25,
wife:{
age: 22,
gender: 'female',
name: '娜美',
car: ['法拉利','奔驰'],
}
};
const user = reactive(obj);
const msg = ref('How are you,today?');
const updateUser = ()=>{
// 通过当前的代理对象找到该对象中的某个属性,更改该属性中的某个数组的数据
user.wife.age=23;
user.wife.car[1]='玛莎拉蒂';
user.wife.car[2]='奥拓';
// 总结:如果操作代理对象,目标对象中的数据也会随之变化,同时如果想要在操作数据的时候,界面也要跟着重新更新渲染,那么也是操作代理对象
};
return {
user,
msg,
updateUser
}
}
});
5. computed计算属性
Vue3中的计算属性依然依赖于缓存,有getter和setter函数,也有简写形式,但是不用像Vue2中那样写在computed配置项中,而是写在setup中,作为组合式API之一返回,如下所示:
<template>
<div class="demo">
<h1>我是computed演示组件</h1>
用户1FirstName:<input v-model="person1.firstName" /><br />
用户1LastName:<input v-model="person1.lastName" />
全名<h1>{
{
person1.fullName}}</h1>
<hr/>
用户2FirstName:<input v-model="person2.firstName" /><br />
用户2LastName:<input v-model="person2.lastName" />
全名<h1>{
{
person2.fullName}}</h1>
</div>
</template>
<script>
import {
reactive,computed} from 'vue';
export default {
name: 'Demo',
props:['msg','school'],
emits:['hello'],
setup(props, context){
let person1 = reactive({
firstName:'尼古拉斯',
lastName:'赵四',
age: 18,
});
let person2 = reactive({
firstName:'郭达',
lastName:'斯坦森',
age<