组件的数据是独立的, 有些功能需要组件通信才能做
常见的组件通信:
- 父传子
- 子传父
- 非父子
**注意: 组件的数据来源:
1. data 自己提供的数据, 可以随便改
2. props 父组件传递过来的数据, 不要改
不要改父组件传递过来的值, 是在遵循一个开发规范 => 单向数据流
单向数据流: 父组件的数据如果修改了, 会自动向下流动, 影响到子组件,触发子组件的更新
一,父传子
// 1. 给子组件, 以添加属性的方式, 传值 ( 以添加html属性的方式, 传值)
// 规范: 添加的属性名全小写
// 2. 在子组件中, 通过props进行接收, 传递的参数列表
// 父传子复杂类型的说明
// 1. 如果传递的是简单数据类型, 修改了, vue会直接报错
// 2. 如果传递的是复杂数据类型, 不要不修改地址, 就不会报错 (虽然不报错, 但是也避免)
// 没有遵循单向数据流
<div id="app">
<h3>我是父组件</h3>
<son :msg="msg" :obj="obj"></son>
</div>
Vue.component('son', {
template: `
<div class="son">
<h3>我是son组件 <button @click="fn">改值</button></h3>
<p>{{ msg }}</p>
<p>{{ obj.name }}</p>
<p>{{ obj.age }}</p>
</div>
`,
props: ['msg', 'obj'],
methods: {
fn () {
// this.msg = '嘿嘿'
this.obj.name = '老花'
}
}
})
const vm = new Vue({
el: '#app',
data: {
msg: 'hello vue',
obj: {
name: '小花',
age: 18
}
}
})
二,子传父
// 1. 在子组件中, 通过触发事件的同时, 传值
// this.$emit(事件名, 参数1, 参数2, .....)
// 2. 在父组件中, 给子组件注册对应的事件
// <!-- 模板在谁的管理范围内, 用的就是谁的变量 -->
<div id="app">
<h3>我是父组件</h3>
<son @sb="fatherFn"></son>
</div>
Vue.component('son', {
template: `
<div class="son">
我是son组件 <button @click="fn">传值给父组件</button>
</div>
`,
data () {
return {
money: '100块'
}
},
methods: {
fn () {
this.$emit('sb', this.money, '小车车')
}
}
})
const vm = new Vue({
el: '#app',
data: {
msg: 'hello vue'
},
methods: {
fatherFn (money, str) {
console.log(1111)
console.log(money, str)
}
}
})
// 子传父:
// 1. 在子组件中, 通过触发事件的同时传值
// this.$emit('事件名', 参数1, ...)
// 2. 在父组件中, 给子组件去注册 对应的 事件
// @事件名 = 'fatherFn'
三,非父子
//非父子通信
// (1) 先创建一个 都能访问到的 事件总线(event bus)
// 实际就是一个空的vue实例
// (2) 在 A 组件中, 触发 bus 的事件, 触发事件的同时传值
// bus.$emit(事件名, 参数1, 参数2, ....)
// (3) 在 B 组件中, 给 bus 注册对应的事件, 接收参数
// bus.$on(事件名, 事件处理函数)
<div id="app">
<jack></jack>
<rose></rose>
</div>
const bus = new Vue()
Vue.component('jack', {
template: `
<div class="jack">
<h3>我是jack</h3>
<button @click="fn">对rose说</button>
<p>{{ info }}</p>
</div>
`,
data () {
return {
msg: 'you jump, i look look',
info: ''
}
},
created () {
bus.$on('rose-reply', (info) => {
this.info = info
})
},
methods: {
fn () {
// console.log('希望给rose传参')
bus.$emit('jack-say', this.msg)
}
}
})
Vue.component('rose', {
template: `
<div class="rose">
<h3>我是rose</h3>
<button @click="fn">rose回答</button>
<p>{{ info }}</p>
</div>
`,
data () {
return {
info: ''
}
},
// bus的事件注册的越早越好, 因为只有注册了事件, 将来才能触发到
created () {
bus.$on('jack-say', (msg) => {
this.info = msg
})
},
methods: {
fn () {
// 触发bus的事件的同时, 传值
bus.$emit('rose-reply', 'get out!! 你个渣男~')
}
}
})
const vm = new Vue({
el: '#app',
data: {
msg: 'hello vue'
}
})
非父子开关灯案例:
//css
<style>
.light {
width: 100px;
height: 100px;
border-radius: 50%;
text-align: center;
line-height: 100px;
margin: 0 auto;
color: #fff;
background-color: rgb(17, 4, 4);
}
/* 灯座 */
.bottom {
width: 150px;
height: 50px;
margin-top: 10px;
line-height: 50px;
text-align: center;
color: #fff;
background-color: #000;
}
.container {
width: 150px;
}
.active {
background-color: #ff0;
color: #000;
}
</style>
//body
<div id="app" class="container">
<div class="light" class="active">我是一盏灯</div>
<div class="bottom">
<button>开灯</button>
<button>关灯</button>
</div>
</div>
案例完成:
<div id="app" class="container">
<light-pao></light-pao>
<light-zuo></light-zuo>
</div>
const bus = new Vue()
// 灯泡组件
Vue.component('light-pao', {
template: `
<div class="light" :class="{ active: isOn }">我是一盏灯</div>
`,
data () {
return {
isOn: false
}
},
created () {
bus.$on('turn', (flag) => {
this.isOn = flag
})
}
})
// 灯座组件
Vue.component('light-zuo', {
template: `
<div class="bottom">
<button @click="turn(true)">开灯</button>
<button @click="turn(false)">关灯</button>
</div>
`,
methods: {
turn (flag) {
// console.log(flag)
bus.$emit('turn', flag)
}
}
})
const vm = new Vue({
el: '#app',
data: {}
})