一、通信方式之props(父传子)
父组件中引入子组件,在子组件标签上绑定属性。
子组件通过 defineProps() 方法进行接收。
<template>
<div class="box">
<h1>props:我是父组件曹操</h1>
<hr />
<Child info="我是曹操" :money="money"></Child>
</div>
</template>
<script setup lang="ts">
//props:可以实现父子组件通信,props数据还是只读的!!!
import Child from "./Child.vue";
import { ref } from "vue";
let money = ref(10000);
</script>
<style scoped>
.box {
width: 100vw;
height: 400px;
background: yellowgreen;
}
</style>
<template>
<div class="son">
<h1>我是子组件:曹植</h1>
<p>{{props.info}}</p>
<p>{{props.money}}</p>
<!--props可以省略前面的名字--->
<p>{{info}}</p>
<p>{{money}}</p>
</div>
</template>
<script setup lang="ts">
//需要使用到defineProps方法去接受父组件传递过来的数据
//defineProps是Vue3提供方法,不需要引入直接使用
let props = defineProps(['info','money']); //数组|对象写法都可以
console.log(props.info,props.money)
</script>
<style scoped>
.son{
width: 400px;
height: 200px;
background: hotpink;
}
</style>
二、通信方式之自定义事件(子传父)
父组件在子组件标签上绑定自定义事件
子组件通过 defineEmits() 方法进行触发父组件绑定的自定义事件
<template>
<div>
<h1>父组件</h1>
<h2>{{ sonData }}</h2>
<!-- 绑定自定义事件xxx:实现子组件给父组件传递数据 -->
<Event2 @getSonData="handle"></Event2>
</div>
</template>
<script setup lang="ts">
import {ref} from "vue"
const sonData=ref('')
//引入子组件
import Event2 from './Event2.vue';
const handle=(data: string)=>{
sonData.value=data
}
</script>
<style scoped>
</style>
<template>
<div class="child">
<p>我是子组件2</p>
<button @click="info">给父组件传值</button>
</div>
</template>
<script setup lang="ts">
//利用defineEmits方法返回函数触发自定义事件
//defineEmits方法不需要引入直接使用
let $emit = defineEmits(['getSonData']);
const info=()=>{
$emit('getSonData','子组件传递的值')
}
</script>
<style scoped>
.child {
width: 400px;
height: 200px;
background: pink;
}
</style>
三、通信方式之全局事件总线(组件间通信)
全局事件总线是用的 mitt 插件,需要插件安装
$ npm install --save mitt
在src目录下创建bus/index.ts
//bus/index.ts
//引入mitt插件:mitt一个方法,方法执行会返回bus对象
import mitt from 'mitt';
const $bus = mitt();
export default $bus;
<template>
<div class="box">
<h1>父组件:全局事件总线$bus</h1>
<hr />
<div class="container">
<Child1></Child1>
<Child2></Child2>
</div>
</div>
</template>
<script setup lang="ts">
//引入子组件
import Child1 from "./Child1.vue";
import Child2 from "./Child2.vue";
</script>
<style scoped>
.box {
width: 100vw;
height: 400px;
background: yellowgreen;
}
.container{
display: flex;
justify-content: space-between;
}
</style>
<template>
<div class="child1">
<h3>我是子组件1</h3>
<h2>{{carName}}</h2>
</div>
</template>
<script setup lang="ts">
import $bus from "../../bus";
//组合式API函数
import { onMounted ,ref} from "vue";
const carName=ref()
//组件挂载完毕的时候,当前组件绑定一个事件,接受将来兄弟组件传递的数据
onMounted(() => {
//第一个参数:即为事件类型 第二个参数:即为事件回调
$bus.on("car", (data) => {
console.log(data.car);
carName.value=data.car
});
});
</script>
<style scoped>
.child1 {
width: 300px;
height: 300px;
background: hotpink;
}
</style>
<template>
<div class="child2">
<h2>我是子组件2</h2>
<button @click="handler">点击我给兄弟送一台法拉利</button>
</div>
</template>
<script setup lang="ts">
//引入$bus对象
import $bus from '../../bus';
//点击按钮回调
const handler = ()=>{
$bus.emit('car',{car:"法拉利"});
}
</script>
<style scoped>
.child2{
width: 300px;
height: 300px;
background: skyblue;
}
</style>
三、通信方式之provide&inject(组件间通信 祖孙通信)
vue3提供provide(提供)与inject(注入),可以实现隔辈组件传递数据
provide('name',data)
两个参数:第一个参数就是提供的数据key
第二个参数:祖先组件提供数据let name = inject('name')
一个参数:即为祖先提供数据的key
<template>
<div class="box">
<h1>祖先组件 Provide与Inject{{car}} </h1>
<hr />
<Child></Child>
</div>
</template>
<script setup lang="ts">
import Child from "./Child.vue";
//vue3提供provide(提供)与inject(注入),可以实现隔辈组件传递数据
import { ref, provide } from "vue";
let car = ref("法拉利");
//祖先组件给后代组件提供数据
//两个参数:第一个参数就是提供的数据key
//第二个参数:祖先组件提供数据
provide("TOKEN", car);
</script>
<style scoped>
.box {
width: 100vw;
height: 600px;
background: skyblue;
}
</style>
<template>
<div class="child">
<h1>我是子组件1</h1>
<Child></Child>
</div>
</template>
<script setup lang="ts">
import Child from './GrandChild.vue';
</script>
<style scoped>
.child{
width: 300px;
height: 400px;
background: yellowgreen;
}
</style>
<template>
<div class="child1">
<h1>孙子组件</h1>
<p>{{car}}</p>
<button @click="updateCar">更新数据</button>
</div>
</template>
<script setup lang="ts">
import {inject} from 'vue';
//注入祖先组件提供数据
//需要参数:即为祖先提供数据的key
let car = inject('TOKEN');
const updateCar = ()=>{
car.value = '自行车';
}
</script>
<style scoped>
.child1 {
width: 200px;
height: 200px;
background: red;
}
</style>
四、组件通信方式之useAttrs (父传子)
useAttrs方法获取组件标签身上属性与事件
<template>
<div>
<h1>父组件:useAttrs</h1>
<el-button type="primary" size="small" :icon="Edit"></el-button>
<!-- 自定义组件 -->
<HintButton type="primary" size="small" :icon="Edit" title="编辑按钮" @click="handler" @xxx="handler"></HintButton>
</div>
</template>
<script setup lang="ts">
//vue3框架提供一个方法useAttrs方法,它可以获取组件身上的属性与事件!!!
//图标组件
import {Edit} from "@element-plus/icons-vue";
import HintButton from "./HintButton.vue";
//按钮点击的回调
const handler = ()=>{
alert(12306);
}
</script>
<style scoped>
</style>
<template>
<h2>自定义子组件</h2>
<div :title="title">
<el-button :="$attrs"></el-button>
</div>
</template>
<script setup lang="ts">
//引入useAttrs方法:获取组件标签身上属性与事件
import {useAttrs} from 'vue';
//此方法执行会返回一个对象
let $attrs = useAttrs();
//万一用props接受title
let props =defineProps(['title']);
//props与useAttrs方法都可以获取父组件传递过来的属性与属性值
//但是props接受了useAttrs方法就获取不到了
console.log($attrs);
</script>
<style scoped>
</style>
五、组件通信方式之ref(获取子组件的属性及方法)、$parent(获取父组件的属性及方法)
父组件:在子组件标签上绑定ref,必须要定义一个与ref绑定同名的属性【let son = ref()】 用来后期获取组件实例【son.value.money】
子组件:要想别人调用自己的方法和属性必须暴露出去【 defineExpose({money,fly}) 】
<template>
<div class="box">
<h1>我是父亲曹操:{{money}}</h1>
<button @click="handler">找我的儿子曹植借10元</button>
<hr>
<Son ref="son"></Son>
<hr>
<Dau></Dau>
</div>
</template>
<script setup lang="ts">
//ref:可以获取真实的DOM节点,可以获取到子组件实例VC
//$parent:可以在子组件内部获取到父组件的实例
//引入子组件
import Son from './Son.vue'
import Dau from './Daughter.vue'
import {ref} from 'vue';
//父组件钱数
let money = ref(100000000);
//获取子组件的实例
let son = ref();
//父组件内部按钮点击回调
const handler = ()=>{
money.value+=10;
//儿子钱数减去10
son.value.money-=10;
son.value.fly();
}
//对外暴露
defineExpose({
money
})
</script>
<style scoped>
.box{
width: 100vw;
height: 500px;
background: skyblue;
}
</style>
<template>
<div class="son">
<h3>我是子组件:曹植{{money}}</h3>
</div>
</template>
<script setup lang="ts">
import {ref} from 'vue';
//儿子钱数
let money = ref(666);
const fly = ()=>{
console.log('我可以飞');
}
//组件内部数据对外关闭的,别人不能访问
//如果想让外部访问需要通过defineExpose方法对外暴露
defineExpose({
money,
fly
})
</script>
<style scoped>
.son {
width: 300px;
height: 200px;
background: cyan;
}
</style>
父组件:要想子组件调用自己的方法和属性也必须进行暴露【 defineExpose({money}) 】
子组件:直接在方法里传参$parent,然后就可以调用父组件的属性和方法
<template>
<div class="dau">
<h1>我是闺女曹杰{{money}}</h1>
<button @click="handler($parent)">点击我爸爸给我10000元</button>
</div>
</template>
<script setup lang="ts">
import {ref} from 'vue';
//闺女钱数
let money = ref(999999);
//闺女按钮点击回调
const handler = ($parent)=>{
money.value+=10000;
$parent.money-=10000;
}
</script>
<style scoped>
.dau{
width: 300px;
height: 300px;
background: hotpink;
}
</style>