我们提供安全,免费的手游软件下载!

安卓手机游戏下载_安卓手机软件下载_安卓手机应用免费下载-先锋下载

当前位置: 主页 > 软件教程 > 软件教程

vue3 快速入门系列 —— 组件通信

来源:网络 更新时间:2024-04-18 04:32:12

vue3 快速入门系列 - 组件通信

组件通信在开发中非常重要,通信就是你给我一点东西,我给你一点东西。

本篇将分析 vue3 中组件间的通信方式。

Tip :下文提到的绝大多数通信方式在 vue2 中都有,但是在写法上有一些差异。

准备环境

在 vue3 基础 上进行。

新建三个组件:爷爷、父亲、孩子A、孩子B,在主页 Home.vue 中加载组件 Gradfather.vue


















浏览器呈现:

# 爷爷
——————————————————
# 父亲
——————————————————
# 孩子A
——————————————————
# 孩子B

下文将再此基础上演示组件间的通信。

props

需求 :实现父给子一件新衣服,子给父一个吻,都用 props 实现。

请看代码:









页面呈现:

# 父亲

来自孩子A: kiss
————————————————————
# 孩子A

来自父亲:新衣服

子给父传数据借助了方法。

通常我们可能会用自定义事件来向父组件传递数据,但是在 react 中,子组件给父组件传递数据就是用 props 传递方法的这种方式进行的。

Tip :祖父给孙子传递就不要用 props。否则按照这个思路,无论什么情况都可以用这个方法。

自定义事件

请看示例:





父组件通过 @send-gift="getGift" 给孩子绑定自定义事件,子组件通过 defineEmits 声明可以触发的事件,最后通过 emit('send-gift', 'kiss2') 触发事件,并将参数传过去。





浏览器呈现:

# 爷爷
——————————————————
# 父亲

来自孩子A: kiss2
——————————————————
# 孩子A

来自父亲:新衣服2

Tip :我们推荐你始终使用 kebab-case 的事件名 —— vue2 官网 - 事件名

mitt

在 vue2 中我们学过 中央事件总线

Vue 3中,中央事件总线(Vue 2中的emit/on机制)已被废除。Vue 3更加推崇使用组合 API、provide/inject以及props/emits来进行组件之间的通信。这样的做法使得组件通信更加明确和可追踪,并且更容易维护和理解。而像mitt这样的第三方库可以作为替代方案,用于实现更灵活的事件管理。

mitt 可以实现 任意组件 之间的通信。

pubsub(例如 pubsub-js 库)、$bus(例如 vue2 中的中央事件总线)、mitt 都是前端中常见的用于实现事件总线(Event Bus)或事件订阅-发布(Publish-Subscribe)模式的解决方案。这三者都是一个套路。也就是:

  • 接收数据:提前绑定(订阅数据)
  • 提供数据:适时触发(发布消息)

mitt 用法很简单,直接看 mitt 仓库 。首先下载包:

PS hello_vue3>  npm install --save mitt

added 1 package, and audited 72 packages in 2s

10 packages are looking for funding
  run `npm fund` for details

1 moderate severity vulnerability

To address all issues, run:
  npm audit fix

Run `npm audit` for details.
"mitt": "^3.0.1"

创建 emitt 并在 main.ts 将其引入项目:

// src\utils\emitter.ts
import mitt from 'mitt'

const emitter = mitt()

export default emitter
// 引入
import emitter from './utils/emitter'

需求 :现在我们让 ChildA 给 ChildB 送礼物。

请看实现:

ChildA 中触发事件:emitter.emit





ChildB 中绑定事件:emitter.on





在 ChildA 中点击按钮,B就能收到礼物。完成任意组件的通信。

Tip : 建议组件卸载时解绑事件。就像这样:

import {onUnmounted} from 'vue'

onUnmounted(() => {
    // 移除该类型的所有事件处理程序
    emitter.off('send-toy')
})

其他写法有:

// 监听
// foo { a: 'b' }
emitter.on('foo', e => console.log('foo', e) )
// 触发
emitter.emit('foo', { a: 'b' })
// 监听所有事件。比如 foo2 就会触发
// foo2 {a: 'b'}
emitter.on('*', (type, e) => console.log(type, e) )
emitter.emit('foo2', { a: 'b' })
// 清除所有事件
emitter.all.clear()
// 注册和解绑事件
function onFoo() {}
emitter.on('foo', onFoo)   // listen
emitter.off('foo', onFoo)  // unlisten

v-model

vue2 中 v-model 用于简化父子之间的通信

你可能不会经常直接在自定义组件中编写 v-model,但是许多 UI 组件库 的底层确实会使用 v-model 来简化父子组件之间的通信和数据流动。这种设计可以使得使用这些组件时更加方便和直观。

举例来说,当你使用一个 UI 组件库提供的输入框组件时,通常可以通过 v-model 来实现父组件与该输入框组件之间的双向绑定,让你可以直接在父组件中操作输入框的值,而不需要手动监听事件或者通过 props 和 emit 进行通信。这种方式大大简化了组件的使用方式和数据流动。

v-model 作用在 input 上可以实现双向绑定,作用在组件上,也能实现父子组件之间的通信( vue2 v-model 、 数字输入框组件 )

v-model 实际上是 语法糖 ,对于 input,等于绑定了 :value 和 @input。就像这样:

// vue2
 
等于

vue3 中 v-model 类似,v-model 对应的是 modelValue 的 prop 和 update:modelValue 的事件。比如我想封装一个 MyInput 组件。



等价


需求 :组件A使用 MyInput,通过 v-model 实现父子之间的通信。

首先不用语法糖,实现如下:





Tip update:modelValue 就是事件名,只是包含一个冒号。




浏览器呈现:

# 组件A

val: p

i am MyInput:

// 这是 input 元素
p

编辑 input 内容时, val 对应的值也会同步,于是实现了父子之间的通信。

这三种方式在这里完全可以替换,于是我们知道 v-model 确实就是个语法糖。

// 方式1

// 方式2:模板自动对 ref 进行解包

// 方式3

重命名 modelValue

目前属性名和方法名中默认是 modelValue,就像: ,希望重命名。

下面这个例子通过 v-model 同时传2个值,并修改默认值。请看示例:








$attrs

祖孙数据互传 可以使用 $attrs 实现。

Tip :$attrs 详细请看: vue2 $attrs

父组件给子组件传递三个属性,子组件通过 props 接收一个,剩余2个属性就会到 $attrs:









接着用 $attrs 实现祖父给孙子传递数据。核心代码如下:









浏览器呈现:

# 父亲

$attrs { "name": "peng", "age": 18, "tel": "131xxx" }
————————————————————————————————————————————————————————
# 组件A

$attrs: { "tel": "131xxx" }

来自祖父的name: peng

来自祖父的age: 18

孙子给祖父传数据,利用 props 的方法,这里祖父提供一个修改电话的方法,孙子调用该方法即可。核心代码如下:









在孙子中点击按钮,祖父的 tel 就会改变。

Tip :孙子给祖父传递数据也可以用自定义事件的升级版本 $listener。

$refs 和 $parent

Tip : 在Vue.js 2.x中,$refs是一个特殊的属性,用于访问组件或DOM元素的引用。当在模板中使用ref属性给元素或组件命名时,Vue.js会自动生成一个$refs对象,其中包含了对这些元素或组件的引用。

需求 :父给子一个玩具,子给父一个吻。

父组件通过 ref 给子组件一个玩具。请看代码:









当在模板中使用ref属性给元素或组件命名时,Vue.js会自动生成一个$refs对象。可以通过 $refs 给孩子礼物。请看示例:





Tip :模板通点击可以将 $refs 传入js中,模板中直接通过 $refs 为空(或许是 $refs 是后生成的,并且没有响应式)。

疑惑 :如何在vue3的组合式api的js里直接取得 $refs?

孩子给父亲礼物,可以使用 $parent,最终代码如下:









Tip :ref($refs)、$parent 直接操作父组件或子组件的数据,不太好。但某些情况下或许有用。

provide 和 inject

上面我们使用 $arrts 实现了祖孙数据互传。有个缺点就是会打扰到中间人:父亲 —— 在父组件中需要写 v-bind=$attrs

而 provide/inject 不打扰中间人,实现祖孙数据互传。请看示例:

祖父通过 provide 提供属性或方法给后代:





父组件通过 inject 能收到祖父提供出来的数据:





孙子通过 inject 接收祖父提供的属性和方法:





浏览器呈现:

# 爷爷
——————————————————————
# 父亲

address 长沙
——————————————————————
# 组件A

address: 长沙

// 按钮
change 祖父 tel

长沙 来自祖父。点击按钮,长沙变成 北京 ,实现孙子到祖父的通信。

升级一下上述示例:祖父提供对象,并将地址和修改地址的方法合并一起传出。请看示例:













插槽

vue2 中就存在这个概念,详细请看官网: vue3 插槽

具名插槽和默认插槽用于 父传子 ,作用域插槽用于 子传父

默认插槽

子组件通过 slot 定义插槽。

比较简单,直接看例子:







如果没传,则显示“默认值”

Tip :父组件使用子组件,比如子组件有标题和内容,标题通过父组件 props 传递,内容可以是图片、视频,列表等等,就可以在父组件中使用插槽。

具名插槽

默认插槽其实就是具名插槽的一种。因为默认插槽也有名字(即 default )。





通过 name 属性给插槽定义名字,父组件通过 v-slot 应用对应的插槽。

现在用 v-slot,只能用于组件或