Vue3组件间的9种通信方式(含例子)

一、props (父-->子)

//父组件
<template>
  <div>
    <h1>我是父组件</h1>
    <child :name="name" age = "12"></child>
  </div>
</template>
<script setup lang="ts">
    import child from './child.vue'
    import { ref } from 'vue'
    const name = ref('父亲名字')
</script>
//子组件
<template>
  <div>
    <h1>我是子组件2</h1>
    <p>我收到了父组件的数据:{{ name }}</p>
    <p>{{ props.age }}</p>
  </div>
</template>
<script setup lang="ts">
const props = defineProps(["name", "age"]);
</script>

二、自定义事件(子-->父)

//父组件
<template>
  <div>
    <h1>我是父组件</h1>
    <child @mimi="tingmimi"></child>
    <p>我听到了子组件的秘密 : {{ msg }}</p>
  </div>
</template>

<script setup lang="ts">
import child from './child.vue'
import {  ref } from 'vue'
let msg =ref('还没听到秘密')
const tingmimi = function(message:any){
     msg.value = message
}
</script>
//子组件
<template>
  <div>
    <h1>我是子组件2</h1>
    <button @click="saymimi">点我给父组件说我的秘密</button>
  </div>
</template>
<script setup lang="ts">
let $emit = defineEmits(['mimi'])
const saymimi = function(){
    $emit('mimi', '是邓紫棋的我的秘密啦')
}
</script>

当子组件中的saymimi函数被调用时,会触发父组件中的tingmimi方法,并将参数'是邓紫棋的我的秘密啦'传递给它

defineEmits([‘mimi’])定义了子组件可以触发的一个名为mimi的事件,通过$emits(‘mimi’,'数据')触发mimi事件,将参数:’数据‘传给父组件;父组件使用自定义事件@mimi="tingmimi"来接受子组件传来的’数据‘。

三、mitt全局事件总线(兄弟间)

安装mitt

npm i mitt

在utils文件创建mitt.ts文件

import mitt from 'mitt'
const $bus = mitt()
export default $bus
在两个子组件都引入mitt文件
<template>
  <div>
    <h1>我是子组件1</h1>
    <p>我收到了来自兄弟的信息:{{ message}}</p>
  </div>
</template>
<script setup lang="ts">
    import $bus from '../utils/mitt';
    import {ref} from 'vue'
    let message =  ref('还不知道呢')
    $bus.on('mimi',(msg:any)=>{
      message.value = msg
    })
</script>
<template>
  <div>
    <h1>我是子组件2</h1>
    <button @click="sayborder">点我给兄弟发秘密</button>
  </div>
</template>
<script setup lang="ts">
    import $bus from '../utils/mitt';
    const sayborder = function(){
        $bus.emit('mimi',{mimi:"遗产全都给我了"})
    }
</script>

四、v-model (父子组件数据同步)

相当于给子组件绑定props,同时绑定了自定义事件

需要添加update:前缀:defineEmits(['update:money'])

<template>
  <div>
    <h1>我是父组件</h1>
    <p>我的财产:{{ money1 }}</p>
    <child v-model:money = money1></child>
  </div>
</template>
<script setup lang="ts">
import {ref} from 'vue'
import child from './child.vue';
let money1 = ref(122000)
</script>
<template>
  <div>
    <h1>我是子组件</h1>
    <input type="text" v-model="value.money">
    <p>父亲的钱{{ money }}</p>
    <button @click="sayborder()">点我偷掉父亲的钱</button>
  </div>
</template>
<script setup lang="ts">
const value = defineProps(['money'])
const $emit = defineEmits(['update:money'])
const sayborder =function(){
  $emit('update:money',value.money-200)
}
</script>

五、useAttrs(父-->子)

<template>
  <div>
    <h1>我是父组件</h1>
    <child :money = money></child>
  </div>
</template>
<script setup lang="ts">
import {ref} from 'vue'
import child from './child.vue';
const money = ref(122000)
</script>
<template>
  <div>
    <h1>我是子组件</h1>
    <p>收到了父亲的财产{{ money }}</p>
  </div>
</template>
<script setup lang="ts">
import { useAttrs} from 'vue';
let $arrts = useAttrs()
let {money} = $arrts
</script>

六、ref与$parent(父-->子、子-->父)

当父组件渲染时,子组件可能还没有完成加载和渲染。因此,在父组件中直接获取子组件的数据时,子组件可能还没有准备好数据,导致获取到的是旧的数据或者undefined。例如刚开始money显示的是undefined。想要拿到组件数据前提是改组件将数据暴露出去了。

ref:父-->子

<template>
  <div>
    <h1>我是父组件</h1>
    <child ref="mychildref"></child>
    <p>原来的生活费是{{ money }}</p>
    <button @click ="addmoney">点我给儿子涨生活费</button>
  </div>
</template>
<script setup lang="ts">
import {ref} from 'vue'
import child from './child.vue';
const mychildref = ref()
const money = ref()
const addmoney=function(){
  money.value = mychildref.value.money
  mychildref.value.money  += 200
}
</script>
<template>
  <div>
    <h1>我是子组件</h1>
    <p>我今年{{ age }}岁</p>
    <p>我的生活费{{ money }}</p>
  </div>
</template>
<script setup lang="ts">
import { ref } from 'vue';
const age = ref(12)
const money = ref(200)
defineExpose({
  age,
  money
}
</script>

$parent:子-->父

<template>
  <div>
    <h1>我是父组件</h1>
    <p>我的财产:{{ money }}</p>
    <child ></child>
  </div>
</template>
<script setup lang="ts">
import {ref} from 'vue'
import child from './child.vue';
const money = ref(122000)
defineExpose({
  money
})
</script>
<template>
  <div>
    <h1>我是子组件</h1>
    <p>父亲原来的钱{{ money1 }}</p>
    <button @click="sayborder($parent)">点我偷掉父亲100块</button>
  </div>
</template>
<script setup lang="ts">
import { ref } from 'vue';
const money1 = ref()
const sayborder =function($parent:any){
  money1.value = $parent.money
  $parent.money-=100
}
</script>

七、provide与inject(爷-->孙)

使用provide和inject方法实现爷爷组件和孙子组件通信时,孙子组件修改接收到的数据会影响爷爷组件的数据,这是因为provide和inject是基于Vue的响应式系统实现的。

当爷爷组件通过provide将数据传递给后代组件时,这些数据会被Vue的响应式系统进行跟踪。当孙子组件通过inject接收到这些数据时,它们实际上是响应式的,即它们与爷爷组件中的数据建立了引用关系。

因此,当孙子组件修改接收到的数据时,实际上是直接修改了爷爷组件中的数据,这就导致了爷爷组件的数据也会发生变化。

这种影响是由于provide和inject的特性决定的,它们提供了一种方便的方式来在组件之间共享数据,但也需要注意数据的修改可能会影响到其他组件。

<template>
  <div>
    <h1>我是爷爷组件</h1>
    <p>爷爷给孙子红包{{ money }}</p>
    <child></child>
  </div>
</template>
<script setup lang="ts">
import child from './child.vue';
import { provide,ref } from 'vue';
const money = ref('1000')
provide('hongbao',money)
</script>
<template>
  <div>
    <h1>我是孙子组件</h1>
    <p>我爷爷给我红包{{ money }}</p>
    <button @click="sayborder">点我看看剩多少钱</button>
  </div>
</template>
<script setup lang="ts">
import { inject,ref } from 'vue';
let money = ref(inject('hongbao') as number)
const sayborder = function(){
  money.value= 500
}
</script>

八、pinia

安装pinia  :npm i pinia

//main.ts
import { createApp } from 'vue';
import App from './App.vue';
import { createPinia } from 'pinia';
const pinia = createPinia()
const app = createApp(App)
app.use(pinia)
app.mount('#app')
//选项式
import {defineStore} from 'pinia'
let useInfoStore = defineStore('info',{
    state:()=>{
        return {
            money:1000
        }
    },
    actions:{
        handle(){
            this.money +=100
        }
    },
    getter:{}
})
export default useInfoStore
//组合式
import {defineStore} from 'pinia'
import {ref} from 'vue'
let useCountStore = defineStore('Count',()=>{
    let count = ref(100)
    let countAdd = function(){
        count.value +=100
    }
    return { count,countAdd}
})
export default useCountStore

组件中使用

<template>
  <div>
    <p>我在pinia的财产:{{ money }}</p>
    <button @click="add">点我money加100</button>
  </div>
</template>
<script setup lang="ts">
import useInfoStore from '../store/user'
const info = useInfoStore()
const money = info.money
const add = function(){
  info.handle()
}
</script>

九、slot插槽

默认插槽

<template>
  <div>
    <h1>我是父组件</h1>
    <hr>
    <child >
      <div><h1>我是solt传的</h1></div>
    </child>
  </div>
</template>
<script setup lang="ts">
import child from './child.vue';
</script>
<template>
  <div>
    <h1>我是子组件</h1>
    <slot></slot>
    <button >点我num加10</button>
  </div>
</template>
<script setup lang="ts">
</script>

具名插槽

<template>
  <div>
    <h1>我是父组件</h1>
    <hr>
    <child >
      <template v-slot:abc>
        <div>
          <h1>我是名字‘abc’solt传的</h1>
        </div>
      </template>
      <template #bbb>//v-slot:可以简写成#
        <div>
          <h1>我是名字‘bbb’solt传的</h1>
        </div>
      </template>
    </child>
  </div>
</template>
<script setup lang="ts">
import child from './child.vue';
</script>
<template>
  <div>
    <h1>我是子组件</h1>
    <slot name="abc"></slot>
    <button >点我num加10</button>
    <slot name="bbb"></slot>
  </div>
</template>
<script setup lang="ts">
</script>

作用域插槽

在父组件中可以访问子组件中的数据。作用域插槽通过v-slot指令和slot-scope属性来实现。

<template>
  <div>
    <h1>我是父组件</h1>
    <hr>
    <child :arr =arr>
      <template v-slot="{$son,$index}">
        <div>
          <h1>我是solt传的</h1>
          <p>儿子叫{{ $son.name }}--{{ $index }}</p>
          <p>儿子{{ $son.id }}岁</p>
        </div>
      </template>
    </child>
  </div>
</template>
<script setup lang="ts">
import child from './child.vue';
const arr = [{id:1,name:'a'},{id:2,name:'b'},{id:3,name:'c'}]
</script>
<template>
  <div>
    <h1>我是子组件</h1>
    <ul>
      <li v-for="(item,index) in arr " :key="index">
        /*需要使用$符命名*/
        <slot :$son="item" :$index="index"></slot>
      </li>
    </ul>
  </div>
</template>
<script setup lang="ts">
defineProps(['arr'])
</script>
  • 12
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
抱歉,我之前给出的回答有误。在Vue 3中,常见的组件通信方式有以下几: 1. Props/Attributes(属性):父组件通过props向子组件传递数据。子组件通过props接收数据并进行相应的处理和渲染。 ```vue // Parent.vue <template> <Child :message="parentMessage" /> </template> <script> import Child from './Child.vue'; export default { data() { return { parentMessage: 'Hello from parent component', }; }, components: { Child, }, }; </script> // Child.vue <template> <div>{{ message }}</div> </template> <script> export default { props: ['message'], }; </script> ``` 2. Emit(事件):子组件通过$emit方法触发自定义事件,并传递数据给父组件进行处理。 ```vue // Child.vue <template> <button @click="sendMessage">Send Message</button> </template> <script> export default { methods: { sendMessage() { this.$emit('message-sent', 'Hello from child component'); }, }, }; </script> // Parent.vue <template> <Child @message-sent="handleMessage" /> </template> <script> import Child from './Child.vue'; export default { methods: { handleMessage(message) { console.log(message); // Output: Hello from child component }, }, components: { Child, }, }; </script> ``` 3. Provide/Inject(依赖注入):父组件通过provide提供数据,子组件通过inject接收数据。 ```vue // Parent.vue <template> <div> <child-component></child-component> </div> </template> <script> import ChildComponent from './ChildComponent.vue'; export default { provide: { message: 'Hello from parent component', }, components: { ChildComponent, }, }; </script> // ChildComponent.vue <template> <div> <grand-child-component></grand-child-component> </div> </template> <script> import GrandChildComponent from './GrandChildComponent.vue'; export default { components: { GrandChildComponent, }, }; </script> // GrandChildComponent.vue <template> <div>{{ message }}</div> </template> <script> export default { inject: ['message'], }; </script> ``` 4. Vuex(状态管理):使用Vuex进行全局状态管理,各个组件通过store来共享数据。 ```vue // store.js import { createStore } from 'vuex'; const store = createStore({ state() { return { message: 'Hello from Vuex store', }; }, }); export default store; // Child.vue <template> <div>{{ message }}</div> </template> <script> import { useStore } from 'vuex'; export default { computed: { message() { const store = useStore(); return store.state.message; }, }, }; </script> // Parent.vue <template> <Child /> </template> <script> import Child from './Child.vue'; export default { components: { Child, }, }; </script> ``` 这些是Vue 3中常见的四组件通信方式。我之前给出的10方式是错误的,请忽略之前的回答。对于其他的通信方式Vue 3并没有提供特定的机制,但可以根据具体的需求使用其他方式实现组件的通信,例如事件总线、自定义事件、全局事件等。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值