组件通信可以分为父子组件通信、非父子组件通信,可以是数据的传递,也可以是方法的传递,先介绍数据的相互传递,再介绍方法的相互传递。
父组件到子组件传递数据:
一、通过props,父组件可以传递动态和静态数据。
//父组件
<template>
<div id="app">
//第一种静态数据 <HelloWorld msg="我是父组件的数据"/>
//第二种动态绑定 <HelloWorld :msg="message"/>
</div>
</template>
<script>
import HelloWorld from './components/HelloWorld.vue'
export default {
name: 'app',
data(){
return{
message: '我来自父组件'
}
},
components: {
HelloWorld
}
}
</script>
//子组件
<template>
<div class="hello">
来自父组件的值:{{msg}}
</div>
</template>
<script>
export default {
name: 'HelloWorld',
props: ['msg']
//或者 props: { msg: String//指定传入的类型 }
//或者 props: { msg: String,default: '默认值' //指定默认值 }
}
</script>
二、provide / inject
provide 和 inject 主要为高阶插件/组件库提供用例。并不推荐直接用于应用程序代码中。并且这对选项需要一起使用,以允许一个祖先组件向其所有子孙后代注入一个依赖,不论组件层次有多深,并在起上下游关系成立的时间里始终生效。
//父组件
<template>
<div>
<child-dom>
</child-dom>
</div>
</template>
<script>
import childDom from "./components/ChildDom.vue";
export default {
data() {
return{
}
},
provide: {
house: '房子',
car: '车子',
money: '¥10000'
},
methods:{
},
components:{childDom},
}
</script>
//子组件
<template>
<div>
</div>
</template>
<script>
export default {
data() {
return{
}
},
inject: {
house: {
default: '没房'
},
car: {
default: '没车'
},
money: {
default: '¥4500'
}
},
created () {
console.log(this.house, this.car, this.money)
},
methods:{
}
}
</script>
子组件传值给父组件
一、通过props的回调
//父组件
<template>
<div id="app">
<HelloWorld :msg="message"/>
</div>
</template>
<script>
import HelloWorld from './components/HelloWorld.vue'
export default {
name: 'app',
data(){
return{
}
},
methods: {
message: (data)=>{
console.log('我是父组件的方法,在子组件中被触发了')
console.log('来自子组件的值是:'+data)
}
},
components: {
HelloWorld
}
}
</script>
//子组件
<template>
<div class="hello" @click="msg('来自子组件的值~~')">
来自父组件的方法,点我执行
</div>
</template>
<script>
export default {
name: 'HelloWorld',
props: ['msg']
}
</script>
二、通过$emit
//父组件
<template>
<div id="app">
<HelloWorld @getData="message"/>
</div>
</template>
<script>
import HelloWorld from './components/HelloWorld.vue'
export default {
name: 'app',
data(){
return{
}
},
methods: {
message: (data)=>{
console.log('来自子组件的值是:'+data)
}
},
components: {
HelloWorld
}
}
</script>
//子组件
<template>
<div class="hello" @click="goFun">
点击传值给父组件
</div>
</template>
<script>
export default {
name: 'HelloWorld',
data(){
return{
s: 1111
}
},
methods: {
goFun(){
this.$emit('getData',this.s)
}
}
}
</script>
三、.sync修饰实现双向绑定
//父组件
<template>
<div id="app">
<HelloWorld :show.sync='valueChild'/>
父组件值:{{valueChild}}
<button @click="changeValue">点击</button>
</div>
</template>
<script>
import HelloWorld from './components/HelloWorld.vue'
export default {
name: 'app',
data(){
return{
valueChild:true
}
},
methods: {
changeValue(){
console.log('父组件的值被修改:'+this.valueChild)
this.valueChild =!this.valueChild
}
},
components: {
HelloWorld
}
}
</script>
//子组件
<template>
<div>
<div>
<p>子组件值:{{show}}</p>
<button @click.stop="closeDiv">修改</button>
</div>
</div>
</template>
<script>
export default {
name: 'HelloWorld',
methods: {
closeDiv() {
this.$emit('update:show', !this.show); //触发 input 事件,并传入新值
}
},
props:['show']
}
</script>
关系型组件跨级传递(根组件、儿子组件、孙子组件)
一、使用 $attrs 和 $listeners
通过 $attrs 将值连续往下传递(和props传递类似),传递过程中可以只选择当前需要的值,组件中可以通过 inheritAttrs:false 保持当前组件的属性纯净度。通过 $listeners 可以在(…子组件)中 this. $emit(“upRocket”,11111)来触发父组件中的事件,从而达到传值给父组件的目的。
//父组件
<template>
<div>
<child-dom
:foo="foo"
:coo="coo"
@upRocket="reciveRocket"
>
</child-dom>
</div>
</template>
<script>
import childDom from "./components/ChildDom.vue";
export default {
data() {
return {
foo:"Hello, world",
coo:"Hello,rui"
}
},
methods:{
reciveRocket(data){
console.log("我是根组件,这是接受的孙子组件的数据"+data)
}
},
components:{childDom},
}
</script>
//子组件
<template>
<div>
<p>foo:{{foo}}</p>
<childDomChild v-bind="$attrs" v-on="$listeners"></childDomChild>
</div>
</template>
<script>
import childDomChild from './childDomChild';
export default {
name:'child-dom',
props:["foo"],
inheritAttrs:false,
components:{childDomChild}
}
</script>
//孙子组件
<template>
<div>
<p>coo:{{coo}}</p>
<button @click="startUpRocket">发送数据到根组件</button> </div>
</template>
<script>
export default {
name:'child-dom',
props:["coo"],
methods: {
startUpRocket() {
this.$emit("upRocket");
}
}
}
</script>
二、$parent $children
其实通过 $ r e f 可以获取到子组件中的一些挂载属性和值, 父组件如果要获取子组件的方法可以通过this.$refs.mychild.funName("…");这种方式,给子组件指定ref名称。同理,通过 $parent $children可直接操作数据和方法。
- this. $parent查找当前组件的父组件。
- this.$children查找当前组件的直接子组件,可以获取到全部直接子组件, 需要注意$children 并不保证顺序,也不是响应式的。可以通过this.$root.$children[0].$children[0].$children[0].msg连续查找
- this.$root查找根组件,并可以配合$children遍历全部组件
//父组件
<template>
<div>
父组件的值:{{msg}}
<child-dom>
</child-dom>
<button @click="change">父组件点击修改</button>
</div>
</template>
<script>
import childDom from "./components/ChildDom.vue";
export default {
data() {
return{
msg: 0
}
},
methods:{
change(){
this.msg = this.$children[0].childMsg
this.$children[0].childMsg = '子组件的值被父组件修改了'
}
},
mounted(){
},
components:{childDom},
}
</script>
//子组件
<template>
<div>
子组件的值:{{childMsg}}
<button @click="decrease()">子组件点击修改</button>
</div>
</template>
<script>
export default {
name:'child-dom',
data() {
return {
childMsg : 111
};
},
methods: {
decrease() {
this.childMsg = this.$parent.msg
this.$parent.msg = "子组件修改了父组件的值"
}
}
}
</script>
非关系组件传值
一、EventBus
适用于小型项目,可以达到任意组件相互通信的效果
//组件a
<template>
<div>
{{fontCount}}
<child-dom>
</child-dom>
</div>
</template>
<script>
//import Vue from 'vue' //export const EventBus = new Vue()
import { EventBus } from "./assets/bus.js";
import childDom from "./components/ChildDom.vue";
export default {
data() {
return{
fontCount: 0
}
},
methods:{
},
mounted(){
EventBus.$on("decreased", ({num}) => {
this.fontCount -= num
});
},
components:{childDom},
}
</script>
//组件b
<template>
<div>
<button @click="decrease()">-</button>
</div>
</template>
<script>
import { EventBus } from "../assets/bus.js";
export default {
name:'child-dom',
data() {
return {
num: 1,
deg:180
};
},
methods: {
decrease() {
EventBus.$emit("decreased", {
num:this.num
});
}
}
}
</script>
二、vuex