Vue 依赖注入:一种高效的数据共享方法

什么是vue依赖注入?

Vue是一个用于构建用户界面的渐进式框架。
它提供了一种简单而灵活的方式来管理组件之间的数据流,即依赖注入(Dependency Injection,DI)。

依赖注入是一种设计模式,它允许一个组件从另一个组件获取它所依赖的数据或服务,而不需要自己创建或管理它们。这样可以降低组件之间的耦合度,提高代码的可维护性和可测试性。

依赖注入示意图

provide和inject

在Vue中,依赖注入的方式是通过provide和inject两个选项来实现的。
provide选项允许一个祖先组件向下提供数据或服务给它的所有后代组件。 inject选项允许一个后代组件接收来自祖先组件的数据或服务。 这两个选项都可以是一个对象或一个函数,对象的键是提供或接收的数据或服务的名称,值是对应的数据或服务。函数的返回值是一个对象,具有相同的格式。

下面是一个简单的例子,演示了如何使用依赖注入的方式共享数据:

父组件

html 复制代码
<template>
  <div>
    <h1>我是祖先组件</h1>
    <child-component></child-component>
  </div>
</template>
js 复制代码
<script>
import ChildComponent from './ChildComponent.vue'

export default {
  name: 'AncestorComponent',
  components: {
    ChildComponent
  },
  // 提供一个名为message的数据
  provide: {
    message: 'Hello from ancestor'
  }
}
</script>

子组件

html 复制代码
<template>
  <div>
    <h2>我是后代组件</h2>
    <p>{{ message }}</p>
  </div>
</template>
js 复制代码
// 后代组件
<script>
export default {
  name: 'ChildComponent',
  // 接收一个名为message的数据
  inject: ['message']
}
</script>

这样,后代组件就可以直接使用祖先组件提供的数据,而不需要通过props或事件来传递。

需要注意的是,依赖注入的数据是不可响应的,也就是说,如果祖先组件修改了提供的数据,后代组件不会自动更新。 如果需要实现响应性,可以使用一个响应式的对象或者一个返回响应式对象的函数作为provide的值。

实现响应式依赖注入的几种方式

一、提供响应式数据

方法是在提供者组件中使用ref或reactive创建响应式数据,然后通过provide提供给后代组件。后代组件通过inject接收后,就可以响应数据的变化。

提供者:

js 复制代码
<template>
  <div>
    <h1>我是提供者组件</h1>
    <button @click="count++">增加计数</button>
    <child-component></child-component>
  </div>
</template>

<script>
import ChildComponent from './ChildComponent.vue'
import { ref, provide } from 'vue'

export default {
  name: 'ProviderComponent',
  components: {
    ChildComponent
  },
  setup() {
    // 使用ref创建一个响应式的计数器
    const count = ref(0)
    // 提供给后代组件
    provide('count', count)
    return {
      count
    }
  }
}
</script>

接收者:

js 复制代码
<template>
  <div>
    <h2>我是接收者组件</h2>
    <p>计数器的值是:{{ count }}</p>
  </div>
</template>

<script>
import { inject } from 'vue'

export default {
  name: 'ChildComponent',
  setup() {
    // 接收提供者组件提供的响应式对象
    const count = inject('count')
    return {
      count
    }
  }
}
</script>

二、提供修改数据的方法

提供者组件可以提供修改数据的方法函数,接收者组件调用该方法来更改数据,而不是直接修改注入的数据。

提供者:

js 复制代码
<template>
  <div>
    <h1>我是提供者组件</h1>
    <p>消息是:{{ message }}</p>
    <child-component></child-component>
  </div>
</template>

<script>
import ChildComponent from './ChildComponent.vue'
import { ref, provide } from 'vue'

export default {
  name: 'ProviderComponent',
  components: {
    ChildComponent
  },
  setup() {
    // 使用ref创建一个响应式的消息
    const message = ref('Hello')
    // 定义一个更改消息的方法
    function updateMessage() {
      message.value = 'Bye'
    }
    // 提供给后代组件
    provide('message', { message, updateMessage })
    return {
      message
    }
  }
}
</script>

接收者:

js 复制代码
<template>
  <div>
    <h2>我是接收者组件</h2>
    <p>消息是:{{ message }}</p>
    <button @click="updateMessage">更改消息</button>
  </div>
</template>

<script>
import { inject } from 'vue'

export default {
  name: 'ChildComponent',
  setup() {
    // 接收提供者组件提供的响应式对象和方法
    const { message, updateMessage } = inject('message')
    return {
      message,
      updateMessage
    }
  }
}
</script>

三、使用readonly包装

通过readonly包装provide的数据,可以防止接收者组件修改数据,保证数据流的一致性。

提供者:

js 复制代码
<template>
  <div>
    <h1>我是提供者组件</h1>
    <p>姓名是:{{ name }}</p>
    <child-component></child-component>
  </div>
</template>

<script>
import ChildComponent from './ChildComponent.vue'
import { ref, provide, readonly } from 'vue'

export default {
  name: 'ProviderComponent',
  components: {
    ChildComponent
  },
  setup() {
    // 使用ref创建一个响应式的姓名
    const name = ref('Alice')
    // 使用readonly包装提供的值,使其不可修改
    provide('name', readonly(name))
    return {
      name
    }
  }
}
</script>

接收者:

js 复制代码
<template>
  <div>
    <h2>我是接收者组件</h2>
    <p>姓名是:{{ name }}</p>
    <button @click="name = 'Bob'">尝试修改姓名</button>
  </div>
</template>

<script>
import { inject } from 'vue'

export default {
  name: 'ChildComponent',
  setup() {
    // 接收提供者组件提供的只读对象
    const name = inject('name')
    return {
      name
    }
  }
}
</script>

四、使用<script setup>

<script setup>组合式写法下,provide和inject默认就是响应式的,无需额外处理。

总结

依赖注入的方式共享数据在Vue中是一种高级特性,它主要用于开发插件或库,或者处理一些特殊的场景。

相关推荐
m0_7482552638 分钟前
前端安全——敏感信息泄露
前端·安全
鑫~阳2 小时前
html + css 淘宝网实战
前端·css·html
Catherinemin2 小时前
CSS|14 z-index
前端·css
漫天转悠2 小时前
Vue3项目中引入TailwindCSS(图文详情)
vue.js
qq_589568103 小时前
Echarts+vue电商平台数据可视化——后台实现笔记
vue.js·信息可视化·echarts
2401_882727574 小时前
低代码配置式组态软件-BY组态
前端·后端·物联网·低代码·前端框架
NoneCoder4 小时前
CSS系列(36)-- Containment详解
前端·css
anyup_前端梦工厂4 小时前
初始 ShellJS:一个 Node.js 命令行工具集合
前端·javascript·node.js
5hand4 小时前
Element-ui的使用教程 基于HBuilder X
前端·javascript·vue.js·elementui
GDAL4 小时前
vue3入门教程:ref能否完全替代reactive?
前端·javascript·vue.js