Hi~,我是 一碗周,一个在舒适区垂死挣扎的前端,如果写的文章有幸可以得到你的青睐,万分有幸~
写在前面
我们在写Vue2的时候,编写组件的方式是使用Options API,这种方式的特点就是在对应的属性编写对应的功能模块,例如在data
中定义数据、methods
定义方法等;这种方法的弊端就是同一功能的代码逻辑被拆分到各个属性中,影响代码的阅读。
Vue3中提供的Composition API可以帮助我们优雅的组织我们的代码,让相关功能的代码更加有序的组织在一起,可以参考『做了一夜动画,就为让大家更好的理解Vue3的Composition Api』,采用动画的方式讲解了Composition API。
接下来我们就来介绍一个如何采用Composition API的方式编写代码。
注:本篇文章全部基于<script setup>
的方式介绍与编写,这样写的好处就是在<script setup>
中定义的内容可以在模板中直接使用。
响应式数据
在Vue3中创建响应式的数据主要是通过reactive
和ref
这两个API实现的,现在我们就来依次学习一下这两个以及相关的API。
reactive
reactive
API用于创建响应式的对象或者数组,实际上该方法的内部就是基于ES6的Proxy
实现的。
如下代码展示了reactive
API的用法:
<template>
<h3>信息展示组件</h3>
<div style="margin: 24px 0">
<span>姓名:</span>
<span>{{ data.name }}</span>
<br />
<span>年龄:</span>
<span>{{ data.age }}</span>
</div>
<button @click="data.name = '一碗周'">修改姓名</button>
<br />
<button @click="data.age = '20'">修改年龄</button>
</template>
<script setup>
// 使用 <script setup> 所有的 API 需要单独引入,除 Vue3.2 自动引入的几个API外。
import { reactive } from 'vue'
// 创建响应式对象
const data = reactive({
name: '一碗粥',
age: '18',
})
</script>
运行结果如下:
Vue中还提供了一个isReactive
,该API用于检测是否为reactive
创建的响应式代理。
Ref API
我们使用reactive
只能对Object或者Array类型的数据进行劫持,如果我们想要对普通数据类型的数据进行劫持,可以使用ref
API,例如如下代码:
<template>
<h3>信息展示组件</h3>
<div style="margin: 24px 0">
<span>姓名:</span>
<!-- 在模板中,Vue 会自动帮助我们为 ref 进行解包,所以不需要使用 ref.value 的形式 -->
<span>{{ name }}</span>
<br />
<span>年龄:</span>
<span>{{ age }}</span>
</div>
<button @click="handleEditName">修改姓名</button>
<br />
<button @click="handleEditAge">修改年龄</button>
</template>
<script setup>
// 导入 ref
import { ref } from 'vue'
// 创建响应式对象
const name = ref('一碗粥')
const age = ref('18')
const handleEditName = () => {
// 通过 ref 创造的响应式对象,我们需要通过 ref.value 的方式访问
name.value = '一碗周'
}
const handleEditAge = () => {
age.value = '20'
}
</script>
代码运行结果与上面相同。
readonly
有时我们希望我们传递给其他组件数据时,往往希望其他组件使用我们传递的内容,但是不允许它们修改,这个时候就可以使用readonly
API,该API可以创建一个不可修改的对象。
我们看下面这段代码:
import { ref, readonly } from 'vue'
// 创建响应式对象
const name = ref('一碗粥')
const age = ref('18')
const readonlyName = readonly(name)
const handleEditName = () => {
// 通过 ref 创造的响应式对象,我们需要通过 ref.value 的方式访问
name.value = '一碗周'
}
const handleEditAge = () => {
age.value = '20'
}
我们修改name
时,readonlyName
的值也会跟着进行改变,但是直接修改readonlyName
并不会生效。
toRefs和toRef
toRefs
和toRef
用于将reactive
创建的响应式代码解构成响应式的数据;如果直接使用ES6的语法进行解构,解构出的数据并不是响应式的。
例如下面这段代码:
import { toRefs, reactive } from 'vue'
const user = reactive({ name: '一碗粥', age: '18' })
// user 下的属性通过 toRefs 与解构后的数据建立了链接,任何一个修改都会引起另一个的变化
const { name, age } = toRefs(user)
const handleEditName = () => {
name.value = '一碗周'
}
const handleEditAge = () => {
age.value = '20'
}
如果想解构单个数据可以使用toRef
,示例代码如下:
const name = toRef(user, 'name')
const age = toRef(user, 'age')
计算属性
在Composition API中定义计算属性是通过computed
方法实现,它可以接受两种参数,一个是getter
函数,另一个是包含get
和set
函数的对象;computed
返回一个ref
对象。
如下代码展示接收getter
函数时,计算属性的用法:
import { ref, computed } from 'vue'
const name = ref('一碗周')
const age = ref('18')
// 定义计算属性
const user = computed(() => {
return `姓名:${name.value}\n年龄:${age.value}`
})
上面的代码中当name
或者age
发生变化时,user
也会进行变化。
computed
方法接受对象参数时,最常见的场景就是组件实现v-model
的功能,示例代码如下所示:
<template>
<input type="text" v-model="myName" />
</template>
<script setup>
// 引入需要的方法
import { defineProps, defineEmits, computed } from 'vue'
// 定义 props
const props = defineProps({
name: String,
})
// v-model 规定写法 update:name name->需要v-model的名称
const emit = defineEmits(['update:name'])
// 定义计算属性
const myName = computed({
get() {
return props.name
},
set(val) {
emit('update:name', val)
},
})
</script>
上面的代码展示了如何在computed
方法传递对象参数。
监听器
Vue3的composition API中提供了两个用于监听数据变化的API,分别是watchEffect
(Vue3.2中新增了watchPostEffect
和watchSyncEffect
API,这两个都是watchEffect
的别名,附带指定选项而已)和watch
,这两者的区别如下:
watchEffect
用于自动收集响应式数据的依赖;watch
需要手动指定监听的数据源;
生命周期
Vue3的composition API没有生命周期钩子选项,但是提供了onBeforeMount
、onMounted
等函数来注册声明周期钩子,提供的声明周期函数如下表所示:
选项式 API | Hook inside setup |
触发时机 |
---|---|---|
beforeMount |
onBeforeMount |
组件挂载之前触发 |
mounted |
onMounted |
组件挂载后触发 |
beforeUpdate |
onBeforeUpdate |
组件更新之前触发 |
updated |
onUpdated |
组件更新后触发 |
beforeUnmount |
onBeforeUnmount |
组件卸载之前触发 |
unmounted |
onUnmounted |
组件卸载后触发 |
如下代码展示了部分API的用法:
import { onMounted, onUpdated, onUnmounted } from 'vue'
onMounted(() => {
console.log('onMounted')
})
onUpdated(() => {
console.log('onUpdated')
})
onUnmounted(() => {
console.log('onUnmounted')
})
模板ref($refs的代替品)
由于Vue3的composition API无法使用this
,所以说this.$refs
并不可以用,那我们怎么获取到组件或者元素呢?其实非常简单,我们需要定义个ref
对象,名称与模板中ref
属性的名称一致即可。
示例代码如下:
<template>
<h3 ref="nameRef">一碗周</h3>
</template>
<script setup>
import { ref, onMounted } from 'vue'
const nameRef = ref(null)
onMounted(() => {
console.log(nameRef.value) // <h3>一碗周</h3>
})
</script>
写在最后
写习惯了composition API后,确实比Options API好用。本篇文章就介绍的一些简单的用法,复杂用法以及细节其实在Vue文档中写的非常详细,本篇文章主要是入门composition API