1. 组件API按需引入
import { ref, toRef, toRefs, computed, watch, getCurrentInstance, reactive, component, onMounted } from 'vue'
2. setup执行时机与注意点
-
setup
执行时机在beforeCreate
之前 - 在
setup
中是不能使用data
和methods
,因为还没初始化好 - 由于不能再setup函数中使用
data
和methods
,所以Vue为了避免我们错误的使用,它直接将setup
函数中的this
修改成undefined
. -
setup
只能同步,不能异步 -
setup
中定义的数据需要return
后才能被模板使用
// Vue3中可以创建多个根节点
{num.age}
{num1.age}
3.Suspense 组件
-
Suspense
中可以添加多个异步组件 -
Suspense
组件是有两个插槽的。默认的default
是在异步组件加载完成之后显示,还有个插槽fallback
代表异步组件加载中显示
- 子组件
setup
内执行异步需用Suspense
包裹,但是,这个时候想要在页面加载完成功之后处理一些内容的话需要确保在第一个await
语句之前注册生命周期钩子
// ...
async setup () {
onMounted(() => {
//...页面加载完成之后需要做其他操作
})
await $http.getUserInfo().then((res: any) => {
//... 处理数据
})
await $http.getApplicationInfo().then((res: any) => {// ...})
return {
//....
}
}
4. reactive VS ref
一般来说,ref
被用来定义简单的字符串或者数值,而reactive被用来定义对象数组等
ref
定义对象时,value
返回的是proxy
,reactive
定义对象时返回的也是proxy
,而这确实存在一些联系
ref
来定义数据时,会对里面的数据类型进行一层判断,当遇到复杂的引用类型时,还是会使用reactive
来进行处理
那么能否使用reactive
来定义普通类型?答案是不行会出现警告,因此reactive
只能被用来定义对象
let num = reactive(100)
如果非要用reactive
定义基本数据类型的话,我们需要在reactive
中将数据包装一下
let num = reactive({val:100})
但是使用reactive
定义的数据和ref定义的数据打印结果有一些差异
let num = reactive({val:100})
let num1 = ref(10)
console.log(num) // {val:100} // 使用reactive定义的num结果是一个数值类型的100
console.log(num1) // 获得一个对象 // 需要用num1.value去获取数据 // 使用vue3中提供的ref方法定义的num打印时候是一个对象
注意ref
定义的数据需要用.value
获取,但template
模板中不需要直接写入return
出去的值即可
5: toRef与 toRefs的作用
Vue3提供了一个新的API:toRef/toRefs
,它可以将一个响应型对象(reactive object
) 转化为普通对象(plain object
),同时又把该对象中的每一个属性转化成对应的响应式属性(ref
)。说白了就是放弃该对象(Object
)本身的响应式特性(reactivity
),转而给对象里的属性赋予响应式特性(reactivity
)。
toRef
:从一个reactive形式的对象里面,提取出来一个指定的属性,然后变成ref形式的对象,,其接收两个参数,第一个参数为对象 A,第二个参数为对象中的某个属性名 x,以便于保持属性的响应性。
// toRef
const num3 = reactive({
name: 'zs',
age: 18
})
const personNameToRef = toRef(num3, 'name')
console.log('num3ToRef', personNameToRef)
console.log('num3ToRefValue', personNameToRef.value)
打印看效果
其实这个不是和ref
一个意思吗
ref(num3 .name)
-
toRefs
:简单的说,就是批量的toRef
toRef
一次只能变一个属性,toRefs
一次能把所有属性都变了。
// toRefs
const num3 = reactive({
name: 'zs',
age: 18
})
const personNameToRef = toRefs(num3)
console.log('num3ToRefs', personNameToRef)
console.log('num3ToRefsValue', personNameToRef.name)
打印看效果
- 那么
ref
toref
torefs
区别到底是什么呢?
- 参数不同:
ref()
接收一个 js 基本数据类型的参数;toRef()
接收两个参数,第一个为对象,第二个为对象中的某个属性; - 原理不同:
ref()
是对原数据的一个深拷贝,当其值改变时不会影响到原始值; -
toRef()
是对原数据的一个引用,当值改变时会影响到原始值 - 当我们希望对象的多个属性都变成响应式数据,并且要求响应式数据和原始数据相关联,这时候
toRefs()
就派上用场了,它用于批量设置多个响应式数据。 - 那么,到这里又有疑问了,通过上面的学习我们知道使用
reactive()
创建的数据已经具有响应式了,为什么还要再toRefs()
呢?
如果return
时使用 ES6 的扩展运算符那么其内部属性就失去了响应性 ,对响应式对象进行toRefs
后,可以对其进行解构方便 Vue 模版使用,但是不会使其失去响应性。 - 具体可以理解为:为响应式对象的每一个键值对创建了一个ref响应式,即使这个响应式对象被拆分了,并不影响键值对的响应式变化,这就好比给羊圈的每只洋套了根绳子,即使羊圈没了,我们依旧可以通过绳子追踪到某一只羊
如果还是不理解那就让我们上 -- 传送门 --
- 如果转换值为普通对象,那么只会改变对象里的某一个值,并不会引起视图更新
6. defineComponent作用
-
defineComponent
可以给组件的setup
方法准确的参数类型定义. -
defineComponent
可以接受显式的自定义props
接口或从属性验证对象中自动推断 -
defineComponent
可以正确适配无 props、数组props
等形式 - 引入
defineComponent()
以正确推断setup()
组件的参数类型
7. getCurrentInstance函数
setup
的执行时组件对象还没有创建,此时不能使用this来访问setup
里的数据或者操作router和vuex等
我们可以通过 getCurrentInstance
这个函数来返回当前组件的实例对象,也就是当前Vue这个实例对象,从而去操作一些数据与方法,getCurrentInstance
函数里的ctx /proxy
就相当于this
import { getCurrentInstance } from 'vue';
// 获取当前组件实例
const instance = getCurrentInstance();
// 获取当前组件的上下文,下面两种方式都能获取到组件的上下文。
const { ctx } = getCurrentInstance(); // 方式一,这种方式只能在开发环境下使用,生产环境下的ctx将访问不到
const { proxy } = getCurrentInstance(); // 方式二,此方法在开发环境以及生产环境下都能放到组件上下文对象(推荐)
// ctx 中包含了组件中由ref和reactive创建的响应式数据对象,以及以下对象及方法;
proxy.$attrs
proxy.$data
proxy.$el
proxy.$emit
proxy.$forceUpdate
proxy.$nextTick
proxy.$options
proxy.$parent
proxy.$props
proxy.$refs
proxy.$root
proxy.$slots
proxy.$watch