自学前端开发 - VUE 框架 (四) 组合式 API
admin
2024-01-21 12:30:03
0

@[TOC](自学前端开发 - VUE 框架 (四) 组合式 API)
vue2 中使用的是选项式API,到 vue3 中引入了组合式API。选项式API易于学习和使用,写代码的位置已经约定好了,但是代码组织性差,相似的逻辑代码不便于复用,逻辑复杂代码多了不好阅读。而组合式API在功能逻辑复杂繁多情况下,各个功能逻辑代码组织再一起,便于阅读和维护,缺点是需要有良好的代码组织能力和拆分逻辑能力。

在学习阶段,可以选择选项式API来写一些简单的程序。虽然 vue 对两种风格都支持,但是在一些 UI 框架或学习其他人写好的程序时,还是需要对两种风格都有些了解。另外虽然 vue 可以两种风格混用,但是在阅读、成员访问等方面会出现混乱,所以不推荐混用。

基础用法

组合式API使用时也是基于应用实例,因此需要先创建一个应用实例。和选项式API不同的是,选项式API在创建应用实例时,传入的是若干选项组成的对象,而组合式API传入的,主要是 setup 函数对象。所有选项式API中各选项功能都写在 setup 函数中。

{{ num }}

setup 函数将返回一个对象,页面渲染需要的数据、方法、响应式状态需要放在此对象中。

在 setup 函数中手动暴露大量的状态和方法非常繁琐。当使用单文件组件(SFC)时,可以使用

需要注意的是,仅当 ref 是模板渲染上下文的顶层属性时才适用自动“解包”。如果 ref 是文本插值(即一个 {{ }} 符号)计算的最终值,它也将被解包。

const object = { foo: ref(1) }

{{ object.foo + 1 }}
{ foo + 1 }}
-->
{ object.foo.value }} -->
{{ object.foo }}

相对于普通的 JavaScript 变量,我们不得不用相对繁琐的 .value 来获取 ref 的值。这是一个受限于 JavaScript 语言限制的缺点。然而,通过编译时转换,我们可以让编译器帮我们省去使用 .value 的麻烦。响应式语法糖是一个编译时的宏命令:它不是一个真实的、在运行时会调用的方法。而是用作 Vue 编译器的标记,表明最终的变量需要是一个响应式变量。


需要注意的是,响应式语法糖仍处于实验性阶段,有可能出现改动或其他问题。

一般对于普通数据类型,使用 ref(),而对于数组和对象数据类型,则使用 reactive() 来声明(因为 reactive 声明不需要使用 .value)

computed

和选项式API中的 computed 选项类似,组合式API中可以使用 computed 函数创建计算属性。且也能够使用声明 get() 方法和 set() 方法的形式,创建可写的计算属性。

const count = ref(1)
const plusOne = computed(() => count.value + 1)console.log(plusOne.value) // 2plusOne.value++ // 错误
const count = ref(1)
const plusOne = computed({get: () => count.value + 1,set: (val) => {count.value = val - 1}
})plusOne.value = 1
console.log(count.value) // 0

方法

和选项式API中,方法必须写在 methods 选项中不同,组合式API可以在 setup() 函数内部的任意地方定义方法,且无需特殊标注。只要在返回对象中将需要外部使用的方法暴露出来即可。

生命周期钩子

组合式API的生命周期钩子不再是选项了,而是使用一些 api 函数。

onCreated

实际上,组合式API没有 onCreated 这个钩子函数。因为 beforeCreated 和 created 这连个选项式的生命周期钩子在组合式API可以直接写在 setup() 函数中并执行,效果是一样的。

onMounted

onMounted 钩子函数相当于 mounted 钩子选项。


onUpdated

等同于选项式API中的 updated


onUnmounted

等同于选项式API中的 unmounted。和选项式API中几乎不会用到不同,组合式API可能会用在一些需要显式手动释放资源的情况中,例如异步侦听器不会绑定到当前组件,所以需要手动停止。

侦听器

组合式API的侦听器类似于选项式API的侦听器,但还是有区别的。主要在侦听的数据源类型

基本使用

watch 的第一个参数可以是不同形式的“数据源”:它可以是一个 ref (包括计算属性)、一个响应式对象、一个 getter 函数、或多个数据源组成的数组:

const x = ref(0)
const y = ref(0)// 单个 ref
watch(x, (newX,oldX) => {console.log(`x is ${newX}`)
})// getter 函数
watch(() => x.value + y.value,(sum, oldSum) => {console.log(`sum of x + y is: ${sum}`)}
)// 多个来源组成的数组
watch([x, () => y.value], ([newX, newY]) => {console.log(`x is ${newX} and y is ${newY}`)
})

多个数据源

当侦听多个来源时,回调函数接受两个数组,分别对应来源数组中的新值和旧值:

watch([fooRef, barRef], ([foo, bar], [prevFoo, prevBar]) => {/* ... */
})

对于响应式对象

目前,对于 reactive() 声明的响应式对象,侦听器不能正确的获取 oldValue,且侦听器是深度侦听,deep 选项失效。

对于 reactive() 声明的响应式对象的属性,不能直接侦听

const obj = reactive({ count: 0 })// 错误,因为 watch() 得到的参数 obj.count 是一个 number
watch(obj.count, (count) => {console.log(`count is: ${count}`)
})

而正确的方法是需要用一个返回该属性的 getter 函数:

// 提供一个 getter 函数
watch(() => obj.count,(count) => {console.log(`count is: ${count}`)}
)

此种使用 getter 函数的侦听器是浅层侦听器,如果需要将这种侦听器转换为深层侦听器,则需要显式地加上 deep 选项:

let a = {b: {c: 1}}watch(() => a.b, (newValue, oldValue) => {// 因为侦听器是浅层侦听// 无法获取 c 的状态改变
})
watch(() => state.someObject,(newValue, oldValue) => {// 注意:`newValue` 此处和 `oldValue` 是相等的// *除非* state.someObject 被整个替换了},{ deep: true }
)

即时回调

同选项式API,侦听器是懒执行的。在组合式API中,可以显式调用侦听函数来立即执行。

const url = ref('https://...')
const data = ref(null)async function fetchData() {const response = await fetch(url.value)data.value = await response.json()
}// 立即获取
fetchData()
// ...再侦听 url 变化
watch(url, fetchData)

也可以用 watchEffect 函数 来简化上面的代码。watchEffect() 会立即执行一遍回调函数,如果这时函数产生了副作用,Vue 会自动追踪副作用的依赖关系,自动分析出响应源。上面的例子可以重写为:

watchEffect(async () => {const response = await fetch(url.value)data.value = await response.json()
})

回调的触发时机

同选项式API,侦听器会在DOM更新前调用,也可以添加选项使得侦听器在DOM更新后调用

watch(source, callback, {flush: 'post'
})watchEffect(callback, {flush: 'post'
})

后置刷新的 watchEffect() 有个更方便的别名 watchPostEffect()

import { watchPostEffect } from 'vue'watchPostEffect(() => {/* 在 Vue 更新后执行 */
})

停止侦听器

一般侦听器以同步方式创建,如果使用异步回调方式创建,那么它不会绑定到当前组件上,必须手动停止它,以防内存泄漏。


要手动停止一个侦听器,需要调用 watch 或 watchEffect 返回的函数:

const unwatch = watchEffect(() => {})// ...当该侦听器不再需要时
unwatch()

注意,需要异步创建侦听器的情况很少,尽可能选择同步创建。如果需要等待一些异步数据,可以使用条件式的侦听逻辑:

// 需要异步请求得到的数据
const data = ref(null)watchEffect(() => {if (data.value) {// 数据加载后执行某些操作...}
})

相关内容

热门资讯

如何给自己喜欢的人写同学录 如何给自己喜欢的人写同学录就写快毕业了~~~很怀念我们大家之间的友情~~希望友情天长地久~~别的可以...
我和女朋友异地恋,马上就要情人... 我和女朋友异地恋,马上就要情人节了想给她一个惊喜,不知道送什么好,求各位大神给个好主意,在线等我觉得...
口腔修复学的名词解释一个:垂直... 口腔修复学的名词解释一个:垂直距离 (确切些)垂直距离:为天然牙列成正中牙合时,鼻底到颏底的距离,也...
掬水月在手,弄花香满衣。云在青... 掬水月在手,弄花香满衣。云在青天水在瓶是什么意思?前两句是《春山夜月》中的诗句,写的是夜的静,月的美...
古代有哪些少数民族和游牧民族屈... 古代有哪些少数民族和游牧民族屈从与汉族?也就是汉族的附属民族,难道没有嘛?西南地区的少数民族,
求海贼王新片头曲 DREAMI... 求海贼王新片头曲 DREAMIN' ON-Da-iCE,真的好好听啊。这首歌是特别好听的,然后但每个...
女朋友家要的彩礼很多,我没有那... 女朋友家要的彩礼很多,我没有那么多钱给她怎么办?我个人觉得如果女朋友家要的彩礼钱很多,但是你又没有那...
复活者盖茨和逢魔时王谁厉害 复活者盖茨和逢魔时王谁厉害肯定是逢魔时王厉害了,证据:在大结局里,逢魔时王一拳打爆e总,一脚踢死0号...
作文点评语句大全简短? 作文点评语句大全简短?1重点突出,中心明确,立意鲜明。内容详略得当,主次分明,情节波折性较强,于平常...
“苦尽甘来又一春,甜归苦涉终千... “苦尽甘来又一春,甜归苦涉终千秋”是什么意思?所有苦难总有尽头的,然后随之而来的就是甘甜,如同恰逢春...
原创 从... 这两天所谓的“零元购”成为热议话题居高不下,广大网友都在关注相关事件的进展。从土豆到桃子再到零食,这...
数字网络语 191 什么意思?... 数字网络语 191 什么意思?在线等快~191是小苹果的意思
Gackt整容过吗 Gackt整容过吗整过的,公开的秘密,圈子密友都知道。你们也知道他笑时不太敢太用力,也是因为这个原因...
什么样的叫特殊人群? 什么样的叫特殊人群?怎么分叫特殊人群?和大众生活不太一样的比如甲鸟或者又鸟。
梦想和远方的佳句 梦想和远方的佳句1,岁月不饶人,你若不留意,它就会偷走你的初心、耐性、意志,最终也将使你遗忘当初的梦...
搞怪女厨分集简介 搞怪女厨分集简介 这一部剧讲了男女主被家里强制联婚。女一号不肯和男主完婚就拌成丑女人,潜进男主家中做...
求音乐:咱当兵的人简谱 刘斌 求音乐:咱当兵的人简谱 刘斌 如下:
黔东南最原始的村落,进寨还要喝... 黔东南最原始的村落,进寨还要喝“拦门酒”,为什么要这么做?为什么要这么做?这是一种当地的习俗吧,因为...
半小时和一个半小时 用英语怎么... 半小时和一个半小时 用英语怎么说?half an hour是半小时 还是 一个半小时 ?半小时:ha...
38岁林依晨结婚七年未怀孕被嘲... 38岁林依晨结婚七年未怀孕被嘲:生不出孩子,是女人的原罪吗?不是的,我觉得应该正确看待这个问题,也不...