首页 > 移动开发 > HTML5 > Vue3中的组件通信方式
Props(父传子)
使用 Props 将数据传递给子组件
父组件:
< template >
< div class= "container" >
< h1 >我是父组件props </ h1 >
< Child msg= "喜欢雪" :money= "money" ></ Child >
</ div >
</ template >
< script setup lang= "ts" >
import { ref } from "vue";
import Child from "./Child.vue";
const money = ref( 100);
</ script >
< style scoped >
.container {
width: 100vw;
height: 400px;
background: skyblue;
}
</ style >
子组件:
< template >
< div class= "son" >
< h1 > </ h1 >
< h2 > </ h2 >
< button @click= "update" >点击我修改props </ button >
</ div >
</ template >
< script setup lang= "ts" >
//采用defineProps方法接受父组件传递过来的props数据
//此函数不需要引入直接使用
//此函数执行返回一个代理对象,接受的是父组件传递过来的数据(模版使用可以省略代理对象)
//props只读的
let props = defineProps([ "msg", "money"]);
</ script >
< style scoped >
.son {
width: 600px;
height: 200px;
background: #ccc;
}
</ style >
Emit(子传父)
子组件1:
< template >
< div >
< h1 >我是子组件:1 </ h1 >
< button @click= "sendCar" >点击我给爸爸送一台法拉利 </ button >
< button @click= "sendHouse" >点击我给爸爸送城堡 </ button >
</ div >
</ template >
< script setup lang= "ts" >
//按钮的回调触发自定义事件回调
const sendCar = () => {
//触发自定义事件
$emit( "car", "法拉利");
};
const sendHouse = () => {
$emit( "house", "成都的城堡");
};
//此方法不需要引入,直接使用
//用于获取$emit方法用于触发自定义事件
//方法内部需要传递一个数组,数组里面元素即为将来触发的自定义事件类型
let $emit = defineEmits([ "car", "house"]);
</ script >
< style scoped ></ style >
子组件2:
< template >
< div >
< h1 @click= "$emit1('click','哈哈哈我变了')" >我是子组件:2 </ h1 >
< h1 >我是子组件:2 </ h1 >
< h1 >我是子组件:2 </ h1 >
< h1 >我是子组件:2 </ h1 >
< h1 >我是子组件:2 </ h1 >
< h1 >我是子组件:2 </ h1 >
</ div >
</ template >
< script setup lang= "ts" >
let $emit1 = defineEmits([ 'click']);
</ script >
< style scoped ></ style >
父组件:
< template >
< div class= "event" >
<!-- 原生DOM事件 -->
< h1 @click= "handler(1, 2, 3, $event)" >
明天休息。真开心啊。
</ h1 >
< hr />
<!-- 自定义事件 -->
< Event1 @car= "handler1" @house= "handler2" ></ Event1 >
< hr >
<!-- @click|dblclick|change在标签|自定义标签上都是原生DOM事件 .native废弃了-->
< Event2 @click= "handler3" ></ Event2 >
</ div >
</ template >
< script setup lang= "ts" >
//引入
import Event1 from "./Event1.vue";
import Event2 from './Event2.vue';
//同名函数
const handler = ( a, b, c, e) => {
console. log( e);
};
const handler1 = ( car) => {
console. log( car);
};
const handler2 = ( house) =>{
console. log( house);
}
const handler3 = ( parmas) =>{
alert( parmas);
}
</ script >
< style scoped >
.event {
width: 100vw;
height: 600px;
background: hotpink;
}
</ style >
Event bus(mitt插件)
由于vue3没有构造函数Vue、也没有this,导致全局事件总线很难完成,但可以使用替代方案mitt.js,原理还是 EventBus。需要安装mitt.js
封装mitt.js
import mitt from 'mitt'
const mitt = mitt()
export default mitt
组件一:
< template >
< div class= "son" >
< h1 @click= "handler" >我是大儿子:孙策 </ h1 >
</ div >
</ template >
< script setup lang= "ts" >
import $bus from '../../bus'
function handler(){
$bus. emit( 'getYX', '玉玺')
}
</ script >
< style scoped >
.son {
width: 400px;
height: 200px;
background: skyblue;
}
</ style >
组件二:
< template >
< div class= "son1" >
< h1 >我是小霸王的弟弟:孙权 </ h1 >
</ div >
</ template >
< script setup lang= "ts" >
import { onMounted} from 'vue';
import $bus from '../../bus'
//组件挂载完毕
onMounted(() =>{
$bus. on( 'getYX',( params) =>{
console. log( params);
})
})
</ script >
< style scoped >
.son1 {
width: 400px;
height: 200px;
background: yellowgreen;
}
</ style >
v-model(多个数据双向绑定)
三种组件,不同方式
组件一:
< template >
< div class= "box" >
< button @click= "updateMoney" >子组件按钮 </ button >
</ div >
</ template >
< script setup lang= "ts" >
const updateMoney = () => {
//触发自定义事件
$emit( "input", props. value + 100);
};
//vue3接受父组件传递过来的props
let props = defineProps([ "value"]);
let $emit = defineEmits([ "input"]);
</ script >
< style scoped >
.box {
width: 400px;
height: 200px;
background: skyblue;
}
</ style >
组件二:
< template >
< div class= "box" >
< button @click= "handler" >子组件按钮(1) </ button >
</ div >
</ template >
< script setup lang= "ts" >
const handler = () =>{
$emit( 'update:modelValue', props. modelValue + 100)
}
//接受父组件传递过来的props
let props = defineProps([ 'modelValue']);
let $emit = defineEmits([ 'update:modelValue'])
</ script >
< style scoped >
.box {
width: 400px;
height: 200px;
background: yellowgreen;
}
</ style >
组件三:
< template >
< div >
< h1 >我是子组件:与父组件的多个数据同步 </ h1 >
< button @click= "handler" >中国 </ button >
< button @click= "handler1" >美国 </ button >
</ div >
</ template >
< script setup lang= "ts" >
//第一个按钮的回调
const handler = () => {
$emit( 'update:car', props. car + '@')
}
const handler1 = () => {
$emit( 'update:house', props. house + '!')
}
//接受父组件传递过来的props
let props = defineProps([ 'car', 'house']);
let $emit = defineEmits([ 'update:car', "update:house"]);
</ script >
< style scoped ></ style >
父组件:
< template >
< div >
< h1 >v-model:在vue3中使用 --- </ h1 >
<!-- 收集表单数据 -->
<!-- <input type="text" placeholder="请你输入账号" v-model="userName"> -->
< hr >
<!-- 子组件 -->
<!-- <Child :value="money" @input="handler"></Child> -->
<!-- 测试v-model在vue3中使用 -->
<!-- 在vue3当中v-model='xxx',相当给子组件传递props[modelValue] 自定义事件[update:modelValue] -->
<!-- <Child1 v-model="money"></Child1> -->
<!-- <Child2 v-model:car="car" v-model:house="house"></Child2> -->
</ div >
</ template >
< script setup lang= "ts" >
import Child from './Child.vue';
import Child1 from './Child1.vue';
import Child2 from './Child2.vue';
//引入组合式API函数ref
import { ref } from 'vue';
//收集账号的响应式数据
const userName = ref( '');
//vue3:v-model也可以实现组件通信,父子组件数据同步!!!
//父亲的钱数
const money = ref( 10000);
const car = ref( '法拉利');
const house = ref( '大别墅');
//子组件自定义事件的回调
// const handler = (val)=>{
// money.value = val;
// }
</ script >
< style scoped ></ style >
Attrs(获取父组件传递过来的属性与属性值 + 事件)
父组件:传送给子组件
< template >
< div >
< h1 >$attrs与$listeners使用 </ h1 >
< hr >
< el-button type= "success" size= "default" @click= "handler" circle >添加 </ el-button >
< hr >
< Buttons type= "warning" size= "large" tip= "添加商品" @click= "handler" ></ Buttons >
</ div >
</ template >
< script setup lang= "ts" >
import Buttons from './Buttons.vue';
const handler = () =>{
alert( 123);
}
</ script >
< style scoped ></ style >
子组件:接收父组件 传递过来的属性与属性值 + 事件
< template >
< div :title= "tip" >
< el-button := "$attrs" > </ el-button >
</ div >
</ template >
< script setup lang= "ts" >
import { useAttrs } from "vue";
//获取父组件传递过来的属性与属性值 + 事件
const $attrs = useAttrs();
let props = defineProps([ 'tip']);
</ script >
< style scoped ></ style >
Provide / Inject(祖先传后代)
可以实现隔辈组件通信,provide:提供数据,inject:后代注入数据
爷爷组件:
< template >
< div >
< h1 >我是爷爷 </ h1 >
< hr />
< Child ></ Child >
</ div >
</ template >
< script setup lang= "ts" >
import Child from "./Child.vue";
import { ref, provide } from "vue";
const car = ref( "蔚来");
//对外提供数据,给后代子组件使用
provide( "car", car);
</ script >
< style scoped ></ style >
儿子组件:
< template >
< div >
< h1 >我是儿子 </ h1 >
< hr >
< GrandChild ></ GrandChild >
</ div >
</ template >
< script setup lang= "ts" >
import GrandChild from "./GrandChild.vue";
</ script >
< style scoped >
</ style >
孙子组件:
<template> <div> <h1 @click="car+='!'">我是孙子{{car}}</h1> </div> </template> <script setup> import { inject } from "vue"; const car = inject("car"); </script> <style scoped></style>
Refs(父访子)
父组件获取子组件的属性或者调用子组件方法
父组件:
<template> <div> <h1>我是父组件:曹操{{money}}</h1> <button @click="handler">点击我找儿子借用200</button> <hr> <Son ref="son"/> <hr> <Dau/> </div> </template> <script setup> import {ref} from 'vue'; import Son from './Son.vue'; import Dau from './Daughter.vue'; //父组件的钱数 const money = ref(100000000); //获取子组件实例 const son = ref(); //vue3:没有$children function handler(){ //自身钱数+200 money.value+=200; son.value.money-=200; } defineExpose({money}) </script> <style scoped></style>
子组件一:
<template> <div> <h1>我是曹植:{{ money }}</h1> </div> </template> <script setup> import { ref } from "vue"; //儿子曹植的钱 const money = ref(200000); defineExpose({money}) </script> <style scoped></style>
子组件二:
<template> <div> <h1>我是曹节:{{ money }}</h1> <button @click="handler($parent)">点击我给爸爸2000</button> </div> </template> <script setup> import { ref } from "vue"; //儿子曹植的钱 const money = ref(4000); //按钮回调 function handler($parent:any) { money.value -= 200; $parent.money+=200; } </script> <style scoped></style>Vuex
main.js
// main.js import { createApp } from "vue" import App from "./App.vue" import store from "./store" createApp(App).use(store).mount("#app")
store/index.js:
// store/index.js import { createStore } from "vuex" export default createStore({ state:{ count: 1 }, getters:{ getCount: state => state.count }, mutations:{ add(state){ state.count++ } } })
使用方式一(直接使用):
<template> <div>{{ $store.state.count }}</div> <button @click="$store.commit('add')">按钮</button> </template> <script setup></script> <style scoped></style>
使用方式二(获取):
<template></template> <script setup> import { useStore, computed } from "vuex" const store = useStore() console.log(store.state.count) // 1 const count = computed(()=>store.state.count) // 数据是响应式的,跟随vuex的数据 console.log(count) // 1 </script>Slot(插槽)
插槽允许父组件向子组件传递任意内容,包括 HTML、组件或函数
父组件:
< template >
< div >
< h1 >作用域插槽 </ h1 >
< TodoList :arr= "todoList" >
<!-- vue2:v-slot|slot-scope -->
< template #= "{ $row, index }" >
<!-- 父组件给子组件提供结构 -->
< pre :style= "{ color: $row.done ? 'green' : 'red' }" > --- </ pre >
</ template >
</ TodoList >
</ div >
</ template >
< script setup lang= "ts" >
//作用域插槽
//概念:数据是由父组件提供,但是子组件不能决定自身的结构与外观!!!
import { ref } from "vue";
import TodoList from './Todo.vue';
//todoList数据
const todoList = ref([
{ id: 1, title: "吃饭", done: true },
{ id: 2, title: "睡觉", done: true },
{ id: 3, title: "打豆豆", done: false },
]);
</ script >
< style scoped ></ style >
子组件:
< template >
< div >
< ul >
< li v-for= "(item, index) in arr" :key= "item.id" >
< slot :$row= "item" :index= "index" ></ slot >
</ li >
</ ul >
</ div >
</ template >
< script setup lang= "ts" >
//接受父组件传递过来的props
defineProps([ "arr"]);
</ script >
< style scoped ></ style >
来自 “ ITPUB博客 ” ,链接:https://blog.itpub.net/69917895/viewspace-2966088/ ,如需转载,请注明出处,否则将追究法律责任。