最近在使用Vue3中,遇到很多阻碍,最后发现,现在多是组合式API了,学习了一部分,但是还是不太熟悉,很烦
组合式 API (Composition API) 是一系列 API 的集合,使我们可以使用函数而不是声明选项的方式书写 Vue 组件。它是一个概括性的术语,涵盖了以下方面的 API:
- 响应式 API:例如
ref()
和reactive()
,使我们可以直接创建响应式状态、计算属性和侦听器。 - 生命周期钩子:例如
onMounted()
和onUnmounted()
,使我们可以在组件各个生命周期阶段添加逻辑。 - 依赖注入:例如
provide()
和inject()
,使我们可以在使用响应式 API 时,利用 Vue 的依赖注入系统。
<script setup>
import { ref, onMounted } from 'vue'
// 响应式状态
const count = ref(0)
// 更改状态、触发更新的函数
function increment() {
count.value++
}
// 生命周期钩子
onMounted(() => {
console.log(`计数器初始值为 ${count.value}。`)
})
</script>
<template>
<button @click="increment">点击了:{{ count }} 次</button>
</template>
1.setup()
setup()
钩子是在组件中使用组合式 API 的入口,通常只在以下情况下使用:
- 需要在非单文件组件中使用组合式 API 时。
- 需要在基于选项式 API 的组件中集成基于组合式 API 的代码时。
setup()
的基本使用,这是选项式API中使用setup()函数
<script>
import { ref } from 'vue'
export default {
setup() {
const count = ref(0)
// 返回值会暴露给模板和其他的选项式 API 钩子
return {
count
}
},
mounted() {
console.log(this.count) // 0
}
}
</script>
<template>
<button @click="count++">{{ count }}</button>
</template>
我们可以使用响应式 API 来声明响应式的状态,在 setup()
函数中返回的对象会暴露给模板和组件实例,这里的响应式就是引入的{ref}
了,之后会说
setup()
自身并不含对组件实例的访问权,即在 setup()
中访问 this
会是 undefined
。你可以在选项式 API 中访问组合式 API 暴露的值,但反过来则不行,这是因为在Vue生命周期中setup()
的初始化,是在组件加载之前的,是访问不到组件实例的
如图:
- 访问Props
setup
函数的第一个参数是组件的 props
,标准的组件一致,一个 setup
函数的 props
是响应式的,并且会在传入新的 props 时同步更新
请注意如果你解构了 props
对象,解构出的变量将会丢失响应性。因此我们推荐通过 props.xxx
的形式来使用其中的 props。
如果你确实需要解构 props
对象,或者需要将某个 prop 传到一个外部函数中并保持响应性,那么你可以使用 toRefs() 和 toRef() 这两个工具函数:
import { toRefs, toRef } from 'vue'
export default {
setup(props) {
// 将 `props` 转为一个其中全是 ref 的对象,然后解构
const { title } = toRefs(props)
// `title` 是一个追踪着 `props.title` 的 ref
console.log(title.value)
// 或者,将 `props` 的单个属性转为一个 ref
const title = toRef(props, 'title')
}
}
一些实际应用
2.响应式
- 用
ref()
定义响应式变量
Vue 提供了一个 ref()
方法来允许我们创建可以使用任何值类型的响应式 ref:
import { ref } from 'vue'
const count = ref(0)
ref()
将传入参数的值包装为一个带 .value
属性的 ref 对象:
const count = ref(0)
console.log(count) // { value: 0 }
console.log(count.value) // 0
count.value++
console.log(count.value) // 1
ref 对象是可更改的,也就是说你可以为 .value
赋予新的值。它也是响应式的,即所有对 .value
的操作都将被追踪,并且写操作会触发与之相关的副作用。
-
reactive()
返回一个对象的响应式代理 -
响应式转换是“深层”的:它会影响到所有嵌套的属性。一个响应式对象也将深层地解包任何 ref 属性,同时保持响应性。
值得注意的是,当访问到某个响应式数组或
Map
这样的原生集合类型中的 ref 元素时,不会执行 ref 的解包。若要避免深层响应式转换,只想保留对这个对象顶层次访问的响应性,请使用 shallowReactive() 作替代。
返回的对象以及其中嵌套的对象都会通过 ES Proxy 包裹,因此不等于源对象,建议只使用响应式代理,避免使用原始对象。
-
示例
创建一个响应式对象:
const obj = reactive({ count: 0 }) obj.count++
ref 的解包:
const count = ref(1) const obj = reactive({ count }) // ref 会被解包 console.log(obj.count === count.value) // true // 会更新 `obj.count` count.value++ console.log(count.value) // 2 console.log(obj.count) // 2 // 也会更新 `count` ref obj.count++ console.log(obj.count) // 3 console.log(count.value) // 3
注意当访问到某个响应式数组或
Map
这样的原生集合类型中的 ref 元素时,不会执行 ref 的解包:const books = reactive([ref('Vue 3 Guide')]) // 这里需要 .value console.log(books[0].value) const map = reactive(new Map([['count', ref(0)]])) // 这里需要 .value console.log(map.get('count').value)
将一个 ref 赋值给为一个
reactive
属性时,该 ref 会被自动解包:ts
const count = ref(1) const obj = reactive({}) obj.count = count console.log(obj.count) // 1 console.log(obj.count === count.value) // true
之前一直使用的选项式API,刚使用组合式还是有点不适应。很多API不熟悉,今天使用Element Plus时,发现很多实例都是TS,后面还需要补一下ts的