首页 > 编程笔记 > JavaScript笔记
阅读:45
Vue provide与inject实现组件通信(附带实例)
在 Vue 中,现有祖组件 App、子组件 Child 和孙组件 Grandson,假如将祖组件 App 中的一些数据传递给孙组件 Grandson,要怎么实现呢?
这就产生了跨层级的祖孙传递模式,其实祖孙之间的传递并不受限制,可以跨越任意多层,只需先在祖组件中利用 provide() 方法进行数据内容的提供,然后在需要接收的孙组件中利用 inject() 函数注入数据即可。
下面通过代码来验证,依次编写祖组件、子组件和孙组件代码。
1) 创建祖组件 App.vue 文件。在 App 组件中引入 provide()、ref() 方法,分别定义 ref 响应式数据 count、非响应式数据 msg 和函数 increase,并在模板中进行渲染、显示。
App.vue 文件代码如下:
2) 创建子组件 Child.vue 文件。子组件 Child 比较简单,只需引入并使用孙子组件 Grandson 即可。
components/Child.vue 文件代码如下:
3) 创建孙组件 Grandson.vue 文件。在引入 inject 函数后,利用它注入祖组件提供的数据,并尝试在模板中进行渲染。此时会发现 msg 的内容不能成功显示,并且控制台中还会出现“Property "msg" was accessed during render but is not defined on instance”的警告提示。这是因为非响应式数据无法被添加到实例对象上,所以孙组件无法实现渲染。而 ref 响应式数据和函数可以被添加到实例对象上,在孙组件中进行相应的使用。
components/Grandson.vue 文件代码如下:
这就产生了跨层级的祖孙传递模式,其实祖孙之间的传递并不受限制,可以跨越任意多层,只需先在祖组件中利用 provide() 方法进行数据内容的提供,然后在需要接收的孙组件中利用 inject() 函数注入数据即可。
下面通过代码来验证,依次编写祖组件、子组件和孙组件代码。
1) 创建祖组件 App.vue 文件。在 App 组件中引入 provide()、ref() 方法,分别定义 ref 响应式数据 count、非响应式数据 msg 和函数 increase,并在模板中进行渲染、显示。
App.vue 文件代码如下:
<script setup> import { provide, ref } from 'vue'; import Child from './components/Child.vue'; const count = ref(0); provide('count', count); // count 是 ref 响应式数据 provide('msg', '你好,尚硅谷!'); // msg 是非响应式数据 const increase = () => { count.value++; }; provide('increase', increase); // increase 是函数 </script> <template> <Child /> <p>msg:{{ msg }}</p> <p>count:{{ count }}</p> <p>state.count:{{ state.count }}</p> </template>值得一提的是,为了后面代码的实现,这里还引入了子组件 Child。
2) 创建子组件 Child.vue 文件。子组件 Child 比较简单,只需引入并使用孙子组件 Grandson 即可。
components/Child.vue 文件代码如下:
<template> <div> <h1>Child</h1> <Grandson /> </div> </template> <script setup> import Grandson from './Grandson.vue'; </script>
3) 创建孙组件 Grandson.vue 文件。在引入 inject 函数后,利用它注入祖组件提供的数据,并尝试在模板中进行渲染。此时会发现 msg 的内容不能成功显示,并且控制台中还会出现“Property "msg" was accessed during render but is not defined on instance”的警告提示。这是因为非响应式数据无法被添加到实例对象上,所以孙组件无法实现渲染。而 ref 响应式数据和函数可以被添加到实例对象上,在孙组件中进行相应的使用。
components/Grandson.vue 文件代码如下:
<template> <h2>Grandson</h2> <!-- 因为非响应式数据无法添加到实例对象上,所以孙组件无法实现渲染 --> <!-- Property "msg" was accessed during render but is not defined on instance --> <p>msg:{{ msg }}</p> <!-- 响应式数据可以进行正常的渲染 --> <p>count:{{ count }}</p> <button @click="increaseCount">increaseCount</button> <button @click="increase">increase</button> </template> <script setup> import { inject } from 'vue'; const msg = inject('msg'); // 非响应式数据 const count = inject('count'); // 响应式数据 const increase = inject('increase'); // 函数 const increaseCount = () => { count.value++; // 可以实现响应式修改与渲染 }; </script>在孙组件中可以动态显示注入的响应式数据 count,也可以更新 count 数据,并且孙组件和祖组件都会同步更新。另外,我们也可以调用注入的函数 increase() 来更新祖组件的数据。