Vue3的12种组件通信方式(附代码)

(vue官网:查看
(vue位于Github的地址:查看

这篇文章的目的是让大家知道有这些方法可以用,所以不会深挖,接下来讲解的每种通信方式我都会附带一个简单的demo。
觉得有帮助的话别忘了收藏

开始

Vue3的12种组件通信方式(下面是讲解顺序)

  • Props
  • emits
  • model
  • slot
  • provide / inject
  • bus
  • getCurrentInstance
  • expose / ref
  • Non-Props
  • Vuex
  • Pinia
  • mitt.js

Props / emits

/父组件
<template>
  <b-Vue :msg="props父传子的消息" @changeMsg="changeMessage" />
</template>

<script setup>
import bVue from './components/b.vue' 

function changeMessage(data) {
    //data:'emits子传父的消息'
}
</script>
/子组件b.vue
<template>
  <div>
   <div @click="handleClick"> {{ msg }} <div> //msg: 'props父传子的消息'
  </div>
</template>
<script setup>

const props = defineProps({
  msg: {
    type: String,
    default: ''
  }
})
// 注册一个自定义事件名,向上传递时告诉父组件要触发的事件。
const emit = defineEmits(['changeMsg'])

function handleClick() {
  emit('changeMsg', 'emits子传父的消息')
}
</script>

v-model / emits

  • v-model 是 一个语法糖,通过Vue3的文档可以发现,这个指令的用法发生了一定的变化。在之前,xxxx.sync与之是很相似的,如今.sync指令已经被废除了,而是统一使用v-model这个指令。

  • v-model在组件身上使用

    • 相当有给子组件传递props[modelValue] = 10000

    • 相当于给子组件绑定自定义事件update:modelValue

  • 下面是使用v-model 与emits的通信示例 ( Vue官网中对于v-model的描述 )

/父组件
// Parent.vue
<template>
  <b-Vue v-model:msg1="message1" v-model:msg2="message2" />
</template>

<script setup>
import { ref } from 'vue'
import bVue from './components/b.vue'

const message1 = ref('父传子1')

const message2 = ref('父传子2')
</script>
// 子组件
<template>
  <div><button @click="send1">修改msg1</button> {{msg1}}</div>

  <div><button @click="send2">修改msg2</button> {{msg2}}</div>
</template>

<script setup>
import { ref } from 'vue'

// 接收参   // 接收父组件使用 v-model 传进来的‘单’个值,必须用 modelValue 这个名字来接收
const props = defineProps({
  msg1: String,
  msg2: String
})
必须用 update:参数||modelValue  这个格式来通知父组件修改值
const emit = defineEmits(['update:send1', 'update:send2'])

function send1() {
  emit('update:msg1', 'GOA1')
}

function send2() {
  emit('update:msg2', 'GOA2')
}

</script>

slot插槽

  • 插槽可以理解为传一段 HTML 片段给子组件。子组件将 元素作为承载分发内容的出口。
  • 插槽的基础用法非常简单,只需在 子组件 中使用 标签,就会将父组件传进来的 HTML 内容渲染出来。
  • 下面是slot进行通信的示例 (Vue官网关于slot的说明)
/父组件
 <template>
  <!-- v-slot="{scope}" 获取子组件传上来的数据 -->
  <!-- :list="list" 把list传给子组件 -->
  <b-Vue v-slot="{scope}" :list="list">
    <div>
      <div> {{ scope.id}}</div>
      <div>{{ scope.text}}</div>
      <hr>
    </div>
  </b-Vue>
</template>

<script setup>
import { ref } from 'vue'
import bVue from './components/b.vue'

const list = ref([
  { id: '1', text: '1'},
  { id: '2', text: '1'},
  { id: '3', text: '1'},
])
</script>
/子组件
<template>
  <div>
    <!--:scope="item" 返回每一项 -->
    <slot v-for="item in list" :scope="item" />
  </div>
</template>

<script setup>
const props = defineProps({
  list: {
    type: Array,
    default: () => []
  }
})
</script>

provide / inject

  • 遇到父孙之间传值, props 和 emit 的方式会显得比较笨拙。这时就可以用 provide 和 inject 了。
  • provide 是在父组件里使用的,可以往下传值。
  • inject 是在子(后代)组件里使用的,可以网上取值。
  • 无论组件层次结构有多深,父组件都可以作为其所有子组件的依赖提供者。
  • 下面是provide / inject进行实践的示例(Vue官网对provide / inject的描述)
/<template>
  <b-Vue></b-Vue>
</template>

<script setup>
import { ref, provide, readonly } from 'vue'
import bVue from './components/b.vue'

const name = ref('provide+readonly传的字')
const msg = ref('provide传的字')

// 使用readonly可以让子组件无法直接修改,需要调用provide往下传的方法来修改
provide('name', readonly(name))

provide('msg', msg)

provide('changeName', (value) => {
  name.value = value
})
</script>
/<template>
  <div>
    <div>msg: {{ msg }}</div>
    <div>name: {{name}}</div>
    <button @click="handleClick">修改</button>
  </div>
</template>

<script setup>
import { inject } from 'vue'

const name = inject('name', '默认值')  //provide传的字
const msg = inject('msg')
const changeName = inject('changeName')

function handleClick() {
 // 正确的方式
  changeName('虎躯一震')
  // 因为 msg 没被 readonly 过,所以可以直接修改值
  msg.value = '世界'
}
</script>

useAttrs

  • vue3框架提供了一个方法useAttrs方法,可以获取到组件身上的属性和事件,换个说法,useAttrs的功能于props的功能很类似,都是父组件传递数据给子组件。
  • 如果使用了props和useAttrs同时接收数据,props的优先级比useAttrs高
  • 下面为使用attrs进行通信的实践
/<template>
  <b-Vue type="primary"  title="名字" ></b-Vue>
</template>
 
<script setup lang="ts"> 
import bVue from './b.vue';
const handleEvent = () => {}
const handle = () => {}
</script>
 /<template>
  <div>
    子组件:{{ attrs.title }}
  </div>
</template>
 
<script setup lang="ts">
// 引入useAttrs方法:获取组件(attrsSon)身上的属性和事件
import { useAttrs } from 'vue';
// 此方法会返回一个对象
let attrs = useAttrs()
console.log('attrs',attrs); //组件身上的属性和事件  
</script>

eventBus

  • 如果你刚开始使用Vue3,很可能会发现,原本用得得心应手的eventBus突然不灵了,因为Vue3不再提供$on与emit函数,Vue实例不再实现事件接口。Vue 官方推荐使用 mitt 或 tiny-emitter。,或者自己手撸一个事件类
  • 这个vue实现eventBus的效果其实多种,我就不舞刀弄枪了,这里推荐一篇写的蛮好的博客(下面链接)
  • Vue 3 中如何优雅的使用eventBus(事件总线)

getcurrentinstance

  • getcurrentinstance 是 vue 提供的一个方法,支持访问内部组件实例。
  • getCurrentInstance 只暴露给高阶使用场景,典型的比如在库中。
  • 强烈反对在应用的代码中使用 getCurrentInstance。请不要把它当作在组合式 API 中获取 this 的替代方案来使用。
  • getCurrentInstance 只能在 setup 或生命周期钩子中调用。
  • 只有在 development,即开发环境下才能获取到当前组件的实例,换句话说就是这个方法只是在开发环境下用于调试使用的;(适合在开发组件库的情况下使用,不适合日常业务开发中使用 )
  • 有兴趣的话可以去钻研一下,我这里就简单介绍下
import {  getCurrentInstance } from 'vue'
let num= null;
num = getCurrentInstance 

console.log(num)  //开发环境下可以获取到组件实例


expose / ref

  • 子组件可以通过 expose 暴露自身的方法和数据。

  • 父组件通过 ref 获取到子组件并调用其方法或访问数据。

  • 使用ref可以直接得到子组件的定义值,但要注意:在父组件要使用getCurrentInstance得到this,在子组件使用defineExpose暴露变量。

/父拿到子的数据
<template>
  <div>{{ msg }}</div>
  <button @click="callChildFn">调用子组件的方法</button>
  <b-Vue ref="com" />
</template>

<script setup>
import { ref, onMounted } from 'vue'
import bVue from './components/b.vue'

const com = ref(null) 

const msg = ref('')

onMounted(() => {
  // 在加载完成后,将子组件的 message 赋值给 msg
  msg.value = com.value.message
})

function callChildFn() {
  // 调用子组件的 changeMessage 方法
  com.value.changeMessage('父改变参')

  // 重新将 子组件的message 赋值给 msg
  msg.value = com.value.message
}
</script>
/<template>
  <div>{{ message }}</div>
</template>

<script setup>
import { ref } from 'vue'

const message = ref('我是子的参')

function changeMessage(data) {
  message.value = data
}

使用 defineExpose 向外暴露指定的数据和方法
defineExpose({
  message,
  changeMessage
})

</script>

Non-Props

  • Non-Props 就是 非 Prop 的 Attribute。(Vue官网中的描述

  • 意思是在子组件中,没使用 prop 或 emits 定义的 attribute,可以通过 $attrs 来访问。常见的有 class 、style 和 id。

/<template>
  <b-Vue msg="传子的数据" name="父亲" />
</template>

<script setup>
import { ref } from 'vue'
import bVue from './components/b.vue'
</script>
<template>
  <div :message="$attrs.msg">只绑定指定值</div>
  <div v-bind="$attrs">全绑定</div>
</template>
/有兴趣可以上手一下 

Vuex

  • Vuex和Pinia是Vue3中的状态管理工具,使用这两个工具可以轻松实现组件通信,由于这两个工具功能比较强大,这里就不做展示了,具体可以查阅文档 (改天有空补上)

休息一下先 等会儿写

在这里插入图片描述

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

SqCheese

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值