1.父组件传递数据给子组件
父组件数据如何传递给子组件呢?可以通过props属性来实现
父组件向子组件传值成功
总结一下:
子组件在props中创建一个属性,用以接收父组件传过来的值
父组件中注册子组件
在子组件标签中添加子组件props中创建的属性
把需要传给子组件的值赋给该属性
2.子组件传递数据给父组件
实例一
那么,如果子组件想要改变数据呢?这在vue中是不允许的,因为vue只允许单向数据传递,这时候我们可以通过触发事件来通知父组件改变数据,从而达到改变子组件数据的目的.
子组件:
<template>
<div @click="up"></div>
</template>
methods: {
up() {
this.$emit('upup','hehe'); //主动触发upup方法,'hehe'为向父组件传递的数据
}
}
父组件:
<div>
<child @upup="change" :msg="msg"></child> //监听子组件触发的upup事件,然后调用change方法
</div>
methods: {
change(msg) {
this.msg = msg;
}
}
实例二
子组件发出消息:
<template>
<div>
<h2>child子组件部分</h2>
<p>{{message}}</p>
<button v-on:click="sendMsgToParent">向父组件传值</button>
</div>
</template>
<script>
export default{
props:["message"],
methods:{
sendMsgToParent:function(){
this.$emit("listenToChildEvent","this message is from child");
}
}
}
</script>
父组件接收消息:
<template>
<div id="app">
<child v-bind:message="parentMsg" v-on:listenToChildEvent="showMsgFromChild"></child>
</div>
</template>
<script>
import child from './Child';
export default{
name:'app',
data(){
return {
parentMsg:"hello,child"
}
},
methods:{
showMsgFromChild:function (data) {
console.log(data);
}
}
}
</script>
子组件向父组件传值成功
总结一下:
子组件中需要以某种方式例如点击事件的方法来触发一个自定义事件
将需要传的值作为$emit的第二个参数,该值将作为实参传给响应自定义事件的方法
在父组件中注册子组件并在子组件标签上绑定对自定义事件的监听
3.非父子组件通信
如果2个组件不是父子组件那么如何通信呢?这时可以通过eventHub来实现通信.
所谓eventHub就是创建一个事件中心,相当于中转站,可以用它来传递事件和接收事件.
组件一触发:
<div @click="eve"></div>
methods: {
eve() {
Hub.$emit('change','hehe'); //Hub触发事件
}
}
组件2接收:
<div></div>
created() {
Hub.$on('change', () => { //Hub接收事件
this.msg = 'hehe';
});
}
或者创建一个新实例
var bus = new Vue()
// 触发组件 A 中的事件
bus.$emit('id-selected', 1)
// 在组件 B 创建的钩子中监听事件
bus.$on('id-selected', function (id) {
// ...
})
再或者打个比方:假设 bb 组件里面有个按钮,点击按钮,把 123 传递给 aa 组件
// 根组件(this.$root)
new Vue({
el: '#app',
router,
render: h => h(App),
data: {
// 空的实例放到根组件下,所有的子组件都能调用
Bus: new Vue()
}
})
bb 组件内调用事件触发↓
<button @click="submit">提交<button>
methods: {
submit() {
// 事件名字自定义,用不同的名字区别事件
this.$root.Bus.$emit('eventName', 123)
}
}
aa 组件内调用事件接收↓
// 当前实例创建完成就监听这个事件
created(){
this.$root.Bus.$on('eventName', value => {
this.print(value)
})
},
methods: {
print(value) {
console.log(value)
}
},
// 在组件销毁时别忘了解除事件绑定
beforeDestroy() {
this.$root.Bus.$off('eventName')
},
组件通信实例
首先我们要实现的效果是
上下分别是 foo组件和 bar 组件,它们之间是非父子关系,分别点击各自的 button ,另一个组件的 count 对应增加。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>非父子组件通信</title>
<script src="https://unpkg.com/vue@2.1.8/dist/vue.js"></script>
</head>
<body>
<div id='app'>
<foo></foo>
<hr>
<bar></bar>
</div>
</body>
</html>
// 注册一个空的 Vue 实例,作为 ‘中转站’
var eventBus = new Vue({})
// foo 组件
var foo = {
template: '<div><p>the count of foo is {{fooCount}}</p>' +
'<button @click="addBar">add bar\'s count</button></div>',
data: function() {
return {
fooCount: 0
}
},
methods: {
addBar: function() {
// 触发事件
eventBus.$emit('addBar')
}
},
mounted: function() {
eventBus.$on('addFoo', function(num) {
this.fooCount +=num
}.bind(this))
// 这里必须将 this 绑定在组件实例上。如果不使用 bind , 也可以使用箭头函数。
}
}
// bar 组件
var bar = {
template: '<div><p>the count of bar is {{barCount}}</p>' +
'<button @click="addFoo">add foo\'s count</button></div>',
data: function() {
return {
barCount: 0
}
},
methods: {
addFoo: function() {
// 触发事件,同时传递一个参数
eventBus.$emit('addFoo', 2)
}
},
// 在 组件创建的钩子函数中 监听事件
mounted: function() {
eventBus.$on('addBar', function() {
this.barCount++
}.bind(this))
}
}
var vm = new Vue({
el: '#app',
components: {
foo,
bar
}
})
以上就实现了一个简易的 非父子组件之间的通信方式。通过 event bus ,在一个组件创建时的钩子函数中监听 某个事件,而在需要与其进行通信的组件中触发这个函数,同时交换数据。
当然,event bus 只适于某些不复杂的场景,在需要频繁进行组件通信的情况下,还是应该尽量使用 Vuex ,不仅使用上更加简单,同时数据流的流向也会相对清晰。