返回

Vue3 Composition API 中 Provide/Inject 和模版 Ref 的妙用

前端

引言

Vue3 Composition API 引入了强大的新功能,如 Provide 和 Inject,为构建更灵活、可重用的组件提供了丰富的选择。此外,模版 Ref 也得到显著增强,进一步简化了对 DOM 元素的访问。在这篇文章中,我们将深入探究这些功能在实际项目中的应用,从基本用法到进阶技巧。

<#section>Provide 和 Inject:数据的跨层级共享</#section>

基本使用

提供者组件使用 Provide 声明要在后代组件中共享的数据,而消费者组件使用 Inject 接收这些数据。这提供了一种非侵入式的方式,无需使用 props 或事件传递数据。

// 提供者组件
export default {
  provide() {
    return {
      message: 'Hello, world!'
    }
  }
}

// 消费者组件
export default {
  inject: ['message'],
  setup() {
    console.log(this.message) // 输出:Hello, world!
  }
}

子组件修改父组件传递过来的数据

有时,子组件需要修改父组件提供的 reactive 数据。Composition API 允许这样做,只需使用 provide() 返回一个 ref,并在子组件中使用 inject() 接收它。

// 提供者组件
export default {
  provide() {
    const message = ref('Hello, world!')
    return {
      message
    }
  }
}

// 消费者组件
export default {
  inject: ['message'],
  setup() {
    this.message.value = 'Goodbye, world!' // 修改父组件提供的 ref
  }
}

禁止子组件修改父组件传递过来的数据

在某些情况下,需要防止子组件修改父组件提供的 reactive 数据。Composition API 中,可以在 Provide 声明中使用函数来实现:

// 提供者组件
export default {
  provide() {
    return {
      message: {
        value: 'Hello, world!',
        readonly: true
      }
    }
  }
}

// 消费者组件
export default {
  inject: ['message'],
  setup() {
    try {
      this.message.value = 'Goodbye, world!' // 引发错误
    } catch (e) {
      console.log(e.message) // 输出:Cannot set readonly property 'value' of object
    }
  }
}

<#section>模版 Ref:简化 DOM 访问</#section>

基本使用

模版 Ref 允许直接访问 DOM 元素,无需使用 ref 属性或 $refs 对象。只需要在元素上添加一个 ref 即可,Vue 会自动将当前 DOM 元素分配给 ref。

<template>
  <div ref="myDiv"></div>
</template>

<script>
  export default {
    setup() {
      const myDivRef = ref(null) // 访问 DOM 元素:myDivRef.value
    }
  }
</script>

动态获取 ref

模版 Ref 还支持动态获取 ref。通过将 ref 与一个计算属性或方法绑定,可以根据需要延迟或有条件地获取 DOM 元素。

<template>
  <div :ref="() => { if (condition) { return 'myDiv' } else { return null } }"></div>
</template>

<#section>进阶技巧</#section>

Composition API 中的 Dependency Injection

Composition API 允许使用依赖注入,通过注入库或服务来简化代码组织和可测试性。

import { createApp } from 'vue'
import MyService from './my-service.js'

const app = createApp({
  provide: {
    myService: new MyService()
  }
})

模版 Ref 的高级用法

模版 Ref 不仅仅用于访问 DOM 元素。它们还可以用于响应事件、创建自定义指令和实现类似 Vuex 的状态管理。

<template>
  <div ref="myDiv" @click="handleClick"></div>
</template>

<script>
  export default {
    setup() {
      const myDivRef = ref(null)
      const handleClick = () => {
        console.log(myDivRef.value) // 输出:点击的 DOM 元素
      }
    }
  }
</script>