共计 3049 个字符,预计需要花费 8 分钟才能阅读完成。
前言: 在前端我的项目中牵扯的最多的莫过于组件之间的传值了,除了最最罕用的 props 和 emit,其实在 Vue 中还额定提供了另外几种办法。明天分享一种组件之间通信的办法。
一. 场景再现
- 先别着急思考题目这个 api 的含意。在这里我先入手写一个比拟常见的场景。
所对应的组件外部代码比较简单,这里我就不展现了,逻辑上就是 这三个组件层层援用。所对应的页面成果如下:
- 如上图,这是一个在我的项目中很常见的一个场景,三层嵌套的组件。(其实还有深层次的嵌套,目前咱们拿 三层嵌套 举例足矣)
- ok,你当初的需要是:在 爷爷组件 内须要提供一个字符串数据 “韩振方” 去提供给 儿子组件 应用。
- 聪慧的你必定想到了 props,废话不多说,咱们间接上手。
二. 传递 Props
- “我认为多浅近呢,这不就是数据 父传子 的场景吗?我间接传递 props 去实现这个需要。”
- 于是我会在
GrandFather.vue
写下这样一段代码 - 接下来就该去
Father.vue
组件去接管这个数据了。于是咱们在Father.vue
组件定义了props
去接管这个值。咱们看一眼页面
没什么问题,爸爸组件 曾经收到了。然而别忘了咱们工作还没实现呢,咱们的需要是给 儿子组件 应用,
- 于是咱们又连忙接着往下传递。
- 所以当初咱们的
Children.vue
组件的样子就变成这个样子。页面成果如下:
最终咱们的 儿子组件 也的确拿到了。
- 写到这里你发现了一些不太对劲的中央吗?🤔
- 其实咱们的 爸爸组件 是齐全不须要晓得这些属性的,它仅仅只是充当了一个 传话筒 。如果这个组件单纯是这一个应用场景还好,然而一旦咱们想要在第二个中央复用 爸爸组件 的时候,咱们会发现问题就来了。咱们必须给这个 爸爸组件 提供一个叫做
message1
的props
,然而实际上这个message1
并不是一个 爸爸组件 外部本人应用的一个属性。 - 写到这里你发现了,仅仅只多传递了一层,就导致组件的复用性变得很差。这还是仅仅只嵌套了三层的场景,一旦到了第四层,你会发现事件逐步开始变得辣手起来了,如同
props
并不是一个好的抉择了。 - 想到这里你会开始思考,有没有更好的解决办法呢?🤔你别说,还真有,那就是咱们明天的配角,
provide
和inject
。
三. provide 和 inject
- 首先不要死记硬背 api 的名字,作者起名字必定都是有起因的。在很多状况下咱们通过先看这两个单词的意思。
- 单从这两个单词的含意就大略能猜出个大略的意思,一个是 提供 某个值,另一个是去 注册 , 接管 这个值。
- 那么问题就引出来了,咱们怎么正确的应用这两个 api 呢?其实很简略,让咱们回到 爷爷组件,还原他最后的模样。
- 你做的仅仅只须要两步:
或者你会诧异,就这样就行了?我明确通知你,是的,这样就行了。
- 接下来最初一步,去 儿子组件 接管应用就功败垂成了。
咱们看一下页面成果:
- 不仅仅数据胜利拿到了,而且要害的是咱们的 爸爸组件 是干干净净的,丝毫不影响其余中央对它的援用。
- 咱们再回过头解说 provide 的用法。provide 承受两个参数。第一个参数须要是一个举世无双的标识(不容许和组件外部的变量重名),第二个参数就是筹备传递的值。
你也能够这样了解,当初 爷爷组件 拿着一个喇叭在喊🎺:“谁要‘韩振方 ’,谁要‘ 韩振方’,价格便宜,仅仅须要一个‘message’”。 - 这时候 儿子组件 听到了这个音讯,大喊:“我要我要!!”于是它就连忙 inject 了一个“message”。
留神: 你用于承受的变量名字是轻易起的,不须要你和后面保持一致。
- 而 爸爸组件 丝毫不想要,所以它就压根不须要 inject。
- 并且 inject 还能够容许你有个 兜底 的行为。什么意思? 假如这个 儿子组件 在别的中央也须要复用,然而它的 爷爷组件 或者 它压根就没有爷爷组件,那么第二个参数将作为
suibian
的默认值。 - 咱们测试一下,咱们首先勾销了 爷爷组件 的 provide 行为。
能够看到,页面正确的显示了咱们的 兜底 数据。
三. provide 的进阶用法
- provide 的作用远远不止提供 字符串 类型数据而已,咱们在 爷爷组件 申明一个响应式的数据试试。
- 让咱们看一下 儿子组件 是否能够正确的响应。
能够看到,的确是能够的。
- 当初 儿子组件 长大了,它说我本人也想控制数字的增长,能够吗?爷爷组件 是很宠 孙子 的,于是又提供了一个办法给 孙子 应用。
- 儿子组件 真的能够本人管制吗?孩子真的长大了吗?
咱们测试一下:
能够看到 儿子组件 的确是 长大了 (指胜利 inject 了 爷爷组件 provide 的函数)
- 千万不要转头就忘,第二个参数是咱们的兜底行为。如果爷爷没提供函数,我就本人应用一个没有任何行为的箭头函数。仅此而已。
四. 源码
爷爷组件代码
<script lang="ts" setup>
// 这是爷爷组件
import {ref} from "vue";
import {provide} from "vue";
import Father from "./Father.vue";
const count = ref<number>(0);
function add() {count.value = count.value + 1;}
provide("message", count);
provide("messageAdd", add); // 我把 add 也同时提供给儿子组件
</script>
<template>
<div class="w-full h-[300px] bg-[black]">
<span class="text-white text-[20px]"> 爷爷组件 </span>
<button @click="add">message+1</button>
<Father />
</div>
</template>
父亲组件代码
<script lang="ts" setup>
// 这是父亲组件
import Children from "./Children.vue";
</script>
<template>
<div class="w-[70%] h-[270px] bg-[pink]">
<span class="text-[black] text-[20px]"> 爸爸组件 </span>
<span class="text-[black] text-[15px]"></span>
<Children />
</div>
</template>
儿子组件代码
<script lang="ts" setup>
// 这是儿子组件
import {inject} from "vue";
const suibian = inject("message", "如果爷爷没提供没有的话就用我");
const add = inject("messageAdd", () => {});
</script>
<template>
<div class="w-[70%] h-[230px] bg-[white]">
<span class="text-[black] text-[20px]"> 儿子组件 </span>
<span class="text-[black] text-[10px]">{{suibian}}</span>
<button @click="add"> 长大了,我本人 +1</button>
</div>
</template>
五. 思考题
如果我当初 爷爷组件 和父亲组件 同时提供了一个雷同的关键词的值,儿子组件 最初会应用谁的呢?
GrandFather.vue: => provide("message","爷爷组件提供的");
Father.vue: =>provide("message","父亲组件提供的")
Children.vue:=> inject("message","我应用谁的?")
正文完