组合式API和选项式API的区别
组合式API
能够对逻辑关注点进行聚合,把逻辑相关的代码写到一起。选项式API
把数据(data
),计算属性(cpmputed
),监听(watch
),方法(methods
)分离,当对其中的逻辑进行新增和修改时,需要跳转去定位代码修改的地方,开发的时候项目代码会来回跳转。
组合式API
有一个入口方法setup
,这样会引入一个问题,页面的代码都集中在一个setup方法中,会导致该方法中存在大量的代码,可以考虑到采用MVC的模式,将业务代码抽离出来单独的js
文件,setup
中只保留交互代码,实现业务和视图的代码分离,以便于项目更好的维护。
入口
上面提到setup
选项式组合式API
的主入口文件,他的执行顺序是在props
解析之后,组件创建之前。
export default {
beforeCreate() {
console.log("beforeCreate 执行");
},
setup() {
console.log("setup 执行");
}
};
// 执行结果 ===> setup 先于beforeCreate执行
// setup 执行
// beforeCreate 执行
复制代码
因为setup
执行的时候,vue
组件还没有被执行,所以在setup
中不能使用this
。
创建响应式变量
ref
vue
中提供了一个ref
函数,可以将基本数据类型转换为ref
响应式对象,ref
对象会带有一个value属性,返回绑定的值。在js
中,基本数据类型是通过值传递的而不是通过引用传递的,所以需要把基本数据类型封装成ref响应式对象来传递。
<template>
<h3>{{ counter }}</h3>
</template>
<script>
import { ref } from "vue";
export default {
setup() {
let counter = ref(100);
return {
counter,
};
},
};
</script>
复制代码
如上面代码所示,绑定counter
值以及返回的ref
对象。ref
也可以传入引用类型对象,vue
会把对象的值转换成一个proxy
对象
reactive
返回一个响应式副本(Proxy
代理对象)
export default {
setup() {
// 定义一个普通对象obj,obj中有两个属性a,b
let obj = { a: 1, b: 2,};
let refObj = reactive(obj);
console.log(refObj);
return { refObj };
}
};
复制代码
reactive
中使用解构赋值的注意事项
在es6
中的解构赋值是非响应式的
// 声明一个obj对象有 a,b两个属性值
let obj = { a: 1, b: 2}
// 对obj对象进行解构赋值
let { a, b } = obj
// 打印a,b
console.log('a======>' + a) // 1
console.log('b======>' + b) // 2
// 对obj对象a,b属性重新赋值
obj.a = 'a'
obj.b = 'b'
// 打印a,b 并没有因为obj对象的属性值发生变化而变化
console.log('a======>' + a) // ===> 1,目标是这里应该输出a
console.log('b======>' + b) // ===> 2 目标是这里应该输出b
// 解:a,b值进行解构赋值之后,不再随着目标对象obj中属性的变化而变化了,
// 因为a,b为基本数据类型,解构赋值是通过赋值操作而不是内存地址的变化的
// template
<h3>{{ a }}</h3> // 1 a值实际已经变更为"a"了,但页面没有发生变化
<h3>{{ b }}</h3> // 2
// js
export default {
setup() {
let obj = { a: 1, b: 2 };
let refObj = reactive(obj);
console.log(refObj);
let { a, b } = refObj;
console.log(a);
console.log(b);
refObj["a"] = "a";
return { a, b };
}
};
复制代码
toRefs
vue中引入了toRefs
方法,顾名思义,就是把obj
对象中的每个值进行遍历,使每个值都变成ref
响应式对象。
// template
<h3>{{ a }}</h3> // a 正确
<h3>{{ b }}</h3> // 2
// js
export default {
setup() {
let obj = { a: 1, b: 2, };
let refObj = reactive(obj);
console.log(refObj); // Proxy {a: 1, b: 2}
let { a, b } = toRefs(refObj); // toRefs是新增的
console.log(a); // ObjectRefImpl {_object: Proxy, _key: "a", __v_isRef: true}
console.log(b); // ObjectRefImpl {_object: Proxy, _key: "b", __v_isRef: true}
refObj["a"] = "a";
return { refObj, a, b };
}
};
复制代码
ref和reactive的异同点
相同点:
是vue3中定义响应式对象的两个函数
不同点:
定义数据类型
ref
可以定义基本数据类型,也可以定义引用数据类型(object
),当因为引用数据类型时,会把传入的目标对象转换成一个proxy代理对象
reactive
只能定义引用数据类型,定义基本数据类型会报出警告
建议ref
定义基本数据类型,reactive
定义引用数据类型
export default {
setup() {
let num1 = ref(1);
let num2 = reactive(2);
let obj1 = ref({ a: 1 });
let obj2 = reactive({ a: 2 }); // warning ===> value cannot be made reactive: 2
console.log(num1); // RefImpl {_rawValue: 1, _shallow: false, __v_isRef: true, _value: 1}
console.log(num2); // 2 会告警waring
console.log(obj1); // RefImpl {_rawValue: {…}, _shallow: false, __v_isRef: true, _value: Proxy}
// 注意:这里的value是Proxy了,而ref传入基本数据类型,value为基本数据类型的值
console.log(obj2); // Proxy {a: 2}
return { num1, num2, obj1, obj2 };
}
};
复制代码
生命周期钩子
选项式API
中的生命周期钩子函数在setup
中都可以使用,只是命名有所区别,当钩子被组件调用时,生命周期中的钩子函数会执行。