v2 用的是结合选项式API
1、结合选项式API
用组件的选项 (data
、computed
、methods
、watch
) 组织逻辑在大多数情况下都有效。然而,当我们的组件变得更大时,逻辑关注点的列表也会增长。这可能会导致组件难以阅读和理解,尤其是对于那些一开始就没有编写这些组件的人来说。
一个大型组件的示例,其中逻辑关注点是按颜色分组。
这种碎片化使得理解和维护复杂组件变得困难。选项的分离掩盖了潜在的逻辑问题。此外,在处理单个逻辑关注点时,我们必须不断地“跳转”相关代码的选项块。
如果我们能够将与同一个逻辑关注点相关的代码配置在一起会更好。而这正是组合式 API 使我们能够做到的
如: data 和 methods 写在一起
2、Composition API 的入口 setup()
新的 setup
组件选项在创建组件之前执行,一旦 props
被解析,并充当合成 API 的入口点。
setup
选项应该是一个接受 props
和 context
的函数,我们将在稍后讨论。此外,我们从 setup
返回的所有内容都将暴露给组件的其余部分 (计算属性、方法、生命周期钩子等等) 以及组件的模板。就是说以上东西都是 setup 返回。
上面的警告是说, setup 发生在 生命周期 beaforeCreate() 之前,实例还没有被创建, 所以选项中也没有 this。
使用的方法:
个人理解这样写,data 和 methods 写在一块,维护起来比较方便
// src/components/UserRepositories.vue `setup` function import { fetchUserRepositories } from '@/api/repositories' // 在我们的组件内 setup (props) { let repositories = [] const getUserRepositories = async () => { repositories = await fetchUserRepositories(props.user) } return { repositories, getUserRepositories // 返回的函数与方法的行为相同 } }
但是,上面的写法中 data repositories 并不是响应式的
在 Vue 3.0 中,我们可以通过一个新的 ref
函数使任何响应式变量在任何地方起作用
ref
接受参数并返回它包装在具有 value
property 的对象中,然后可以使用该 property 访问或更改响应式变量的值:
import { ref } from 'vue' const counter = ref(0) console.log(counter) // { value: 0 } console.log(counter.value) // 0 counter.value++ console.log(counter.value) // 1
在任何值周围都有一个包装器对象,这样我们就可以在整个应用程序中安全地传递它,而不必担心在某个地方失去它的响应性。
// src/components/UserRepositories.vue `setup` function import { fetchUserRepositories } from '@/api/repositories' import { ref } from 'vue' // in our component setup (props) { const repositories = ref([]) const getUserRepositories = async () => { repositories.value = await fetchUserRepositories(props.user) } return { repositories, getUserRepositories } }
完成!现在,每当我们调用 getUserRepositories
时,repositories
都将发生变化,视图将更新以反映更改。
我们的组件现在应该如下所示:(v2 用的是结合选项式API向 V3组合式API 迁移)
下面 setup(props) 可以接收到 外部的 props(父组件传过来的值),使用方式如下 props.user
// src/components/UserRepositories.vue import { fetchUserRepositories } from '@/api/repositories' import { ref } from 'vue' export default { components: { RepositoriesFilters, RepositoriesSortBy, RepositoriesList }, props: { user: { type: String, required: true } }, setup (props) { const repositories = ref([]) const getUserRepositories = async () => { repositories.value = await fetchUserRepositories(props.user) } return { repositories, getUserRepositories } }, data () { return { filters: { ... }, // 3 searchQuery: '' // 2 } }, computed: { filteredRepositories () { ... }, // 3 repositoriesMatchingSearchQuery () { ... }, // 2 }, watch: { user: 'getUserRepositories' // 1 }, methods: { updateFilters () { ... }, // 3 }, mounted () { this.getUserRepositories() // 1 } }
我们已经将第一个逻辑关注点中的几个部分移到了 setup
方法中,它们彼此非常接近。剩下的就是在 mounted
钩子中调用 getUserRepositories
,并设置一个监听器,以便在 user
prop 发生变化时执行此操作。
我们将从生命周期钩子开始。
#生命周期钩子注册内部 setup
为了使组合式 API 的特性与选项式 API 相比更加完整,我们还需要一种在 setup
中注册生命周期钩子的方法。这要归功于从 Vue 导出的几个新函数。组合式 API 上的生命周期钩子与选项式 API 的名称相同,但前缀为 on
:即 mounted
看起来像 onMounted
。
这些函数接受在组件调用钩子时将执行的回调。
让我们将其添加到 setup
函数中:
// src/components/UserRepositories.vue `setup` function import { fetchUserRepositories } from '@/api/repositories' import { ref, onMounted } from 'vue' // in our component setup (props) { const repositories = ref([]) const getUserRepositories = async () => { repositories.value = await fetchUserRepositories(props.user) } onMounted(getUserRepositories) // on `mounted` call `getUserRepositories` return { repositories, getUserRepositories } }
现在我们需要对 user
prop 所做的更改做出反应。为此,我们将使用独立的 watch
函数。
watch
响应式更改
就像我们如何使用 watch
选项在组件内的 user
property 上设置侦听器一样,我们也可以使用从 Vue 导入的 watch
函数执行相同的操作。它接受 3 个参数:
- 一个响应式引用或我们想要侦听的 getter 函数
- 一个回调
- 可选的配置选项
下面让我们快速了解一下它是如何工作的
import { ref, watch } from 'vue' const counter = ref(0) watch(counter, (newValue, oldValue) => { console.log('The new counter value is: ' + counter.value) })