一、前言
这篇文章主要总结了几种通信方式:
1、方式一:使用props: [ ]和$emit() (适用于单层通信)
2、方式二:$attrs和$listeners(适用于多层)
二、主要内容
1、方式一:使用props: [ ]和$emit()
(1)父组件向子组件通信
a.步骤:①先给父组件添加自定义属性
②子组件用props:[]接收传来的自定义属性
③子组件就可使用接收到的数据
b.代码如下:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Document</title>
<style type="text/css">
*{
margin:0;
padding: 0;
} .parent{
height: 150px;
width: 400px;
background-color: blue;
} .child{
height: 100px;
width: 200px;
background-color: pink;
}
</style>
</head>
<body>
<div id='app'> </div>
<script type="text/javascript" src="node_modules/vue/dist/vue.js"></script>
<script type="text/javascript"> Vue.component('Child',{ data(){
return{ }
}, template:`<div class='child'>
这是孩子组件
<input :value='childData'/> </div>`, props:['childData'] }) var Parent = {
data(){
return{
msg:'这是父组件的数据'
}
}, template:`<div class='parent'>
这是父组件:
<Child :childData='msg'></Child>
</div>
`
} new Vue({
el:"#app",
data(){
return{ }
}, template:`<Parent></Parent>`,
components:{
Parent
}
})
</script>
</body>
</html>
父组件向子组件传递数据.html
c.测试结果:孩子组件接收到了父组件的数据,并且显示在孩子组件的input框里
d.具体实现:
(2)子组件向父组件通信
步骤:①现在父组件中定义自定义事件
②子组件中定义一个原生的事件,调用下面methods中定义的
③在子组件的method()中定义一个事件,用$emit(),来触发父组件的事件,
代码如下:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Document</title>
<style type="text/css">
*{
margin:0;
padding: 0;
} .parent{
height: 150px;
width: 400px;
background-color: blue;
} .child{
height: 100px;
width: 200px;
background-color: pink;
}
</style>
</head>
<body>
<div id='app'> </div>
<script type="text/javascript" src="node_modules/vue/dist/vue.js"></script>
<script type="text/javascript"> Vue.component('Child', {
data(){
return{
childData:'孩子'
}
},
template:`<div class='child'>
这是孩子组件
<input v-model='childData' @input='childerValue(childData)'/> </div>`, methods:{
childerValue:function(val){
this.$emit('childerHander', val)
} } }) var Parent = {
data(){
return {
msg:'' }
}, template:`<div class='parent'> <Child @childerHander='childerHander'></Child>
</div>`, methods:{ childerHander:function(val){
console.log(val) }
}
} new Vue({
el:'#app',
data(){
return{ }
},
template:`<div>
<Parent></Parent> </div>`, components:{
Parent
} })
</script> </body>
</html>
孩子的数据传到父组件中.html
测试:
具体实现:
-------------------------------------------------------------------------------------------------------------------------------------------------------------------
方式二:$attrs和$listeners
第一种方式适合用于单层嵌套的情况,如果组件中有三层嵌套如果用第一种那么需要在每个子组件中定义props:[]接收,这样实现起来比较麻烦,在vue2.4开始提供了$attrs和$listeners来解决这个问题
能够让组件A之间传递消息给组件C
如下所示:
代码如下:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Document</title>
<style type="text/css">
.a{
width: 400px;
height: 400px;
background-color: blue; } .b{
width: 300px;
height: 300px;
background-color: orange; } .c{
width: 200px;
height: 200px;
background-color: pink; }
</style>
</head>
<body>
<div id='app'>
</div>
<script type="text/javascript" src="node_modules/vue/dist/vue.js"></script> <script type="text/javascript">
//定义组件cc Vue.component('C',{
data(){
return{ }
},
template:`<div class='c'>
这是c组件
<div>{{$attrs.messagec}}</div> </div>`
}) Vue.component('B',{
data(){
return{ }
},
template:`<div class='b'>
<C v-bind='$attrs'></C> </div>`
}) //定义组件A
Vue.component('A', {
data(){
return{ }
}, //1.先接收
props:['message'], template:`<div class='a'>
<B v-bind='$attrs'></B> </div>`
}); //定义组件App----A
var App = {
data(){
return{
msg:'我是父组件的内容',
messagec:'helloc'
}
}, template:`<div>
这是一个父组件
<A :messagec='messagec'></A> </div>`
} new Vue({
el:'#app',
data(){
return{ }
}, components:{
App
}, template:'<App />' })
</script>
</body>
</html>
方式二父组件向子组件通信.html
测试:
具体实现:
(2)子组件向父组件传递信息
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Document</title>
<style type="text/css">
.a{
width: 400px;
height: 400px;
background-color: blue; } .b{
width: 300px;
height: 300px;
background-color: orange; } .c{
width: 200px;
height: 200px;
background-color: pink; }
</style>
</head>
<body>
<div id='app'>
</div>
<script type="text/javascript" src="node_modules/vue/dist/vue.js"></script> <script type="text/javascript">
//定义组件cc Vue.component('C',{
data(){
return{ }
},
template:`<div class='c'>
这是c组件
<input @input='cClickHandler' /> </div>`,
methods:{
cClickHandler(){
alert(1)
this.$emit('getCData','这是c的数据')
}
}
}) Vue.component('B',{
data(){
return{ }
},
template:`<div class='b'>
<C v-on='$listeners'></C> </div>`
}) //定义组件A
Vue.component('A', {
data(){
return{ }
},
//1.先接收
props:['message'], template:`<div class='a'>
<B v-on='$listeners'></B> </div>`
}); //定义组件App----A
var App = {
data(){
return{
msg:'我是父组件的内容',
messagec:'helloc'
}
},
template:`<div>
这是一个父组件
<A v-on:getCData='getCData'></A>
</div>`,
methods:{
getCData(val){
console.log(val)
}
}
} new Vue({
el:'#app',
data(){
return{ }
}, components:{
App
}, template:'<App />' })
</script>
</body>
</html>
方式二父组件向子组件传递数据.html
测试如下:
具体实现:
----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
方式三:上面两种方式都是父子组件之间数据的传递,如果两个组件不是父子关系呢?这种情况下可以使用*事件总线的方式,新建一个Vue事件bus对象,然后通过bus.$emit触发事件,bus.$on监听触发的事件
例子如下:
代码如下:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Document</title>
<style type="text/css">
.brotherB{
width: 400px;
height: 400px;
background-color: blue;
} .brotherC{
width: 200px;
height: 200px;
background-color: pink;
}
</style>
</head>
<body> <div id='app'> </div>
<script type="text/javascript" src="node_modules/vue/dist/vue.js"></script>
<script type="text/javascript">
//*事件总线
var bus = new Vue();
//B->C传事件
Vue.component('brotherC', {
data(){
return{
msg:'hello brotherB'
}
}, template:`<div class="brotherC">
我是老大(brotherC)
<input type='text' v-model='msg' @input='passData(msg)'/> </div>`,
methods:{
passData(val) { bus.$emit('globalEvent',val) //去触发
}
}
}); Vue.component('brotherB', {
data(){
return{ brother2Msg:''
}
}, template:`<div class="brotherB">
<p>我是老二(brotherB)</p>
<p>老大传递过来的数据:{{brother2Msg}}</p> </div>`,
//首先给brotherB绑定一个全局的事件
mounted(){ bus.$on('globalEvent', (val)=>{ this.brother2Msg = val;//这里用箭头函数,避免避免this改变 })
} }); var App = {
data(){
return{
msg:'我是父组件的内容'
}
}, template:`<div> <brotherC></brotherC>
<brotherB></brotherB> </div>`
} new Vue({
el:"#app",
data(){
return{ }
}, template:'<App/>',
components:{
App
} }) </script> </body>
</html>
方式三:兄弟之间通信.html
演示效果如下:
具体实现:
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
方式四:父组件中通过provide来提供变量,然后在子组件中通过inject来注入变量,不论子组件有多深,只要调用了inject那么就可以注入provider中自定义的属性,而不只仅仅是从prop中接受到的数据,只要在生命周期内,子组件都可以调用
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Document</title>
</head>
<body>
<div id='app'> </div>
<script type="text/javascript" src="node_modules/vue/dist/vue.js"></script> <script type="text/javascript"> Vue.component('Child', { data(){
return {
msg:''
}
}, template:`<div>
我是孩子{{msg}} </div>`,
//2.注入
inject:['for'], created(){
//3.拿到
this.msg = this.for
}
}) Vue.component('Parent', {
template:`<div>
<p>我是父</p>
<Child /> </div>`
})
var App = {
data(){
return{ }
},
//1。提供
provide:{
for:'[这是父组件的信息]'
}, template:`<div>
<h2>我是入口组件</h2>
<Parent /> </div>`
} new Vue({
el:"#app",
data(){
return { }
}, template:'<App/>',
components:{
App
} })
</script>
</body>
</html>
方式四父组件向子组件通信.html
测试如下:
------------------------------------------------------------------------------------------------------------------------------------------------------------
方式五:$parent $children
代码实现:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Document</title>
<style type="text/css">
.child{
width: 300px;
height: 300px;
background-color: pink;
} .parent{
width: 500px;
height: 500px;
background-color: blue;
}
</style>
</head>
<body>
<div id="app"></div>
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<script type="text/javascript">
Vue.component('Child',{
data(){
return{
mymessage:''
}
},
template:`<div class="child">
<input type="text" v-model="mymessage" @input='changeValue'/> </div>`,
methods:{
changeValue(){
this.$parent.message = this.mymessage
}
}
}) Vue.component("Parent",{
data(){
return{
message:"hello"
}
},
template:`<div class="parent">
<p>我是父组件{{message}}</p> <Child></Child> </div>`, methods:{ }
}) var App={
data(){
return{ }
},
template:`<div>
<h2>我是入口组件</h2>
<Parent />
</div>`
} new Vue({
el:"#app",
data(){
return{ }
}, template:`<App />`,
components:{
App
}
})
</script>
</body>
</html>
子向父传
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Document</title>
<style type="text/css">
*{
margin:0;
padding: 0;
} .parent{
height: 150px;
width: 400px;
background-color: blue;
} .child{
height: 100px;
width: 200px;
background-color: pink;
} </style> </head>
<body>
<div id='app'> </div>
<script type="text/javascript" src="node_modules/vue/dist/vue.js"></script>
<script type="text/javascript"> Vue.component('Child', {
props:{//子组件通过props接收父组件的value props:[]也可以
value:String,
}, data(){
return{
mymessage:this.value //将上面的this.value赋值给mymessage }
}, template:`<div class='child'>
<input type="text" v-model='mymessage' @input='changeValue' /> </div>`, methods:{
changeValue(){//通过$parent将子组件的信息传递给孩子 this.$parent.message = this.mymessage;
console.log(this.$parent)
}
} }) Vue.component('Parent',{
//当点击之后,
template:`<div class='parent'>
<p>我是父亲组件{{message}}</p>
<button @click='changeValue'>test</button>
<Child></Child> </div>`,
methods:{//通过$chidren[0]传递给孩子
changeValue(){
this.$children[0].mymessage = 'hello'
}
},
data(){
return {
message:'hello'
}
}
}) var App = {
data(){
return{ }
},
template:`<div>
<h2>我是入口组件</h2>
<Parent/> </div>`
} new Vue({
el:"#app",
data(){
return{ }
}, template:'<App/>',
components:{
App
} })
</script> </body>
</html>
方式五组件通信.html
测试:
三、总结
1、常用的方式是前三种