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中是一种高级特性,它主要用于开发插件或库,或者处理一些特殊的场景。

相关推荐
golitter.7 分钟前
Ajax和axios简单用法
前端·ajax·okhttp
雷特IT27 分钟前
Uncaught TypeError: 0 is not a function的解决方法
前端·javascript
长路 ㅤ   1 小时前
vite学习教程02、vite+vue2配置环境变量
前端·vite·环境变量·跨环境配置
亚里士多没有德7751 小时前
强制删除了windows自带的edge浏览器,重装不了怎么办【已解决】
前端·edge
micro2010141 小时前
Microsoft Edge 离线安装包制作或获取方法和下载地址分享
前端·edge
.生产的驴1 小时前
Electron Vue框架环境搭建 Vue3环境搭建
java·前端·vue.js·spring boot·后端·electron·ecmascript
awonw1 小时前
[前端][easyui]easyui select 默认值
前端·javascript·easyui
老齐谈电商1 小时前
Electron桌面应用打包现有的vue项目
javascript·vue.js·electron
LIURUOYU4213081 小时前
vue.js组建开发
vue.js
九圣残炎1 小时前
【Vue】vue-admin-template项目搭建
前端·vue.js·arcgis