maiy's blog

Composition Api 和 Teleport

2021-01-13

Composition Api

Composition Api是为了解决vue组件里逻辑代码过多而出现的,主要是利用setup函数把组件的逻辑功能点封装起来,即逻辑复用。

setup

setup函数在组件创建之前执行,由于setup在创建实例前执行,因此没有this,也不能访问组件声明的属性。参数是propscontext。如果需要在setup里创建响应式的变量,那就需要ref函数把变量封装起来,在setup函数里使用obj.value的形式来访问变量。我们也可以在setup函数里用watch函数对响应式变量进行监听。使用toRefs函数对props的属性进行响应式引用。computed函数也可以在setup函数里创建只读的响应式引用。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
import { fetchUserRepositories } from '@/api/repositories'
import { ref, onMounted, watch, toRefs, computed } from 'vue'

setup(props) {
// 使用toRefs创建对props的user属性的响应式引用
const { user } = toRefs(props)

const repositories = ref([]) // 创建了响应式的变量
const getUserRepositories = async () => {
// 使用respositories.value 来访问响应式变量
repositories.value = await fetchUserRepositories(props.user);
}

onMounted(getUserRepositories) // 在mounted生命周期执行时调用getUserRepositories

watch(user, getUserRepositories) // 每当user更新时都会调用getUserRepositories

const searchQuery = ref('')
// 创建了只读的响应式引用,每当searchQuery或者repositories更新都会重新执行该计算函数
const repositoriesMatchingSearchQuery = computed(() => {
return repositories.value.filter(item => item.name.inclueds(searchQuery.value))
})

return {
repositories,
searchQuery,
getUserRepositories,
repositoriesMatchingSearchQuery
}
}

组合式函数

这样一看像是把所有逻辑都抽出来封装在setup函数,而且会使得setup函数变得很臃肿,所以vue3.0会把上面的例子setup函数里的逻辑提取到一个独立的组合式函数
把逻辑1函数抽象出来

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
// 函数1
import { fetchUserRepositories } from '@/api/repositories'
import { ref, onMounted, watch } from 'vue'
// 钩子函数
export default function useUserRepositories(user) {
const repositories = ref([]) // 创建了响应式的变量
const getUserRepositories = async () => {
// 使用respositories.value 来访问响应式变量
repositories.value = await fetchUserRepositories(props.user);
}
onMounted(getUserRepositories) // 在mounted生命周期执行时调用getUserRepositories
watch(user, getUserRepositories) // 每当user更新时都会调用getUserRepositories

return {
repositories,
getUserRepositories
}
}

把逻辑2函数抽象出来

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
// 函数2
import { ref, computed } from 'vue'

export default function useRepositoryNameSearch(respositories) {
const searchQuery = ref('')
// 创建了只读的响应式引用,每当searchQuery或者repositories更新都会重新执行该计算函数
const repositoriesMatchingSearchQuery = computed(() => {
return repositories.value.filter(item => item.name.inclueds(searchQuery.value))
})

return {
searchQuery,
repositoriesMatchingSearchQuery
}
}

最后在组件中引用,这样子就能把代码逻辑抽象出来,创建个好维护的代码。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
import useUserRepositories from '@/composables/useUserRepositories'
import useRepositoryNameSearch from '@/composables/useRepositoryNameSearch'
import { toRefs } from 'vue'

export default {
props: {
user: { type: String }
},
setup(props) {
// 使用toRefs创建对props的user属性的响应式引用
const { user } = toRefs(props)

// 与React hook类似
const { repositories, getUserRepositories } = useUserRepositories(user)
const {
searchQuery,
repositoriesMatchingSearchQuery
} = useRepositoryNameSearch(repositories)

return {
// 因为我们并不关心未经过滤的仓库
// 我们可以在 `repositories` 名称下暴露过滤后的结果
repositories: repositoriesMatchingSearchQuery,
getUserRepositories,
searchQuery,
}

}
}

Teleport

Teleport是为了解决在组件里也能把内容渲染在父节点以外的问题,常见的使用场景是组件控制弹框,通知信息等全局动画。如下代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
<template>
<div class="hello">
<h1>{{ msg }}</h1>
<teleport to="#purple-box">
<p>{{ content }}</p>
</teleport>
</div>
<template>
<script>
export default {
data() {
return {
msg: 'HelloWorld',
content: 'hello teleport', // teleport 显示在purple-box下,
}
}
}
</script>

片段

以往template只能包含一个元素,现在支持多个

使用支付宝打赏
使用微信打赏

若你觉得我的文章对你有帮助,欢迎点击上方按钮对我打赏

扫描二维码,分享此文章