组合式 API

为什么需要它

能够将与同一个逻辑关注点相关的代码配置在一起(解决选项式api的痛点)

基础

image.png

  1. // src/components/UserRepositories.vue
  2. export default {
  3. components: { RepositoriesFilters, RepositoriesSortBy, RepositoriesList },
  4. props: {
  5. user: { type: String }
  6. },
  7. setup(props) {
  8. console.log(props) // { user: '' }
  9. return {} // 这里返回的任何内容都可以用于组件的其余部分
  10. }
  11. // 组件的“其余部分”
  12. }

声明响应式变量

基本类型+数组

在 Vue 3.0 中,我们可以通过一个新的 ref 函数使任何响应式变量在任何地方起作用,如下所示:

  1. import { ref } from 'vue'
  2. const counter = ref(0)
  3. console.log(counter) // { value: 0 }
  4. console.log(counter.value) // 0
  5. counter.value++
  6. console.log(counter.value) // 1

其实本质就是将值传递转换成引用传递(拿到指针)

引用类型

reactive:返回对象的响应式副本

  1. const obj = reactive({ count: 0 })

生命周期的变化

image.png

这些函数接受一个回调函数,当钩子被组件调用时将会被执行:

  1. // MyBook.vue
  2. export default {
  3. setup() {
  4. // mounted
  5. onMounted(() => {
  6. console.log('Component is mounted!')
  7. })
  8. }
  9. }

状态逻辑复用

常用的hooks状态逻辑封装

根据组合api,我们可以抽离公用的状态逻辑,不再使用mixin

  1. function useMouse() {
  2. const x = ref(0)
  3. const y = ref(0)
  4. const update = e => {
  5. x.value = e.pageX
  6. y.value = e.pageY
  7. }
  8. onMounted(() => {
  9. window.addEventListener('mousemove', update)
  10. })
  11. onUnmounted(() => {
  12. window.removeEventListener('mousemove', update)
  13. })
  14. return { x, y }
  15. }
  16. // 在组件中使用该函数
  17. const Component = {
  18. setup() {
  19. const { x, y } = useMouse()
  20. // 与其它函数配合使用
  21. const { z } = useOtherLogic()
  22. return { x, y, z }
  23. },
  24. template: `<div>{{ x }} {{ y }} {{ z }}</div>`
  25. }

image.png

内置组件

Teleport

背景

Vue 鼓励我们通过将 UI 和相关行为封装到组件中来构建 UI。我们可以将它们嵌套在另一个内部,以构建一个组成应用程序 UI 的树。

然而,有时组件模板的一部分逻辑上属于该组件,而从技术角度来看,最好将模板的这一部分移动到 DOM 中 Vue app 之外的其他位置。

一个常见的场景是创建一个包含全屏模式的组件。在大多数情况下,你希望模态的逻辑存在于组件中,但是模态的定位很快就很难通过 CSS 来解决,或者需要更改组件组合。

Teleport 提供了一种干净的方法,允许我们控制在 DOM 中哪个父节点下呈现 HTML,而不必求助于全局状态或将其拆分为两个组件。

  1. const app = Vue.createApp({});
  2. app.component('modal-button', {
  3. template: `
  4. <button @click="modalOpen = true">
  5. Open full screen modal! (With teleport!)
  6. </button>
  7. <teleport to="body">
  8. <div v-if="modalOpen" class="modal">
  9. <div>
  10. I'm a teleported modal!
  11. (My parent is "body")
  12. <button @click="modalOpen = false">
  13. Close
  14. </button>
  15. </div>
  16. </div>
  17. </teleport>
  18. `,
  19. data() {
  20. return {
  21. modalOpen: false
  22. }
  23. }
  24. })
  25. app.mount('#app')