组件通信
1.为什么要进行组件通信
组件可以说是具有独立功能的整体,但是当我们要将这些组件拼接在一起的时候,这些组件相互之间要建立联系,这个联系我们就称之为通信
2.组件通信的方式有一下几种
1.父子组件通信
使用props来实现
2.子父组件通信
自定义事件
3.非父子组件通信
ref链
bus事件总线
4.多组件状态共享(多个组件共用同一个数据) 大知识点(vuex) 这边只讲前3个
vuex
知识点: app实例的手动挂载
new Vue({
el:'#app'
}).$mount('#app')
父子组件通信
案例:
<body>
<div id='app'>
<father></father>
</div>
<template id='father'>
<div>
<p>这是Father组件</p>
<hr>
<son :qwer = "money"></son>
<!-- 子组件做数据绑定 绑定父组件里面的数据 -->
</div>
</template>
<template id='son'>
<div>
<p>这是son组件</p>
<p>父亲给了我{{qwer}}元</p>
<!-- 子组件可以全局调用这个数据 -->
</div>
</template>
<script>
// props
// 1.在父组件的模板中将数据用单项数据绑定的形式,绑定在子组件上
// 2.在子组件的配置项中可以使用一个props配置项来接收这个数据,接收时,props的取值可以是一个数组
// 3.在子组件模板中,接收到的属性可以像全局一样使用
// 这里全局注册Father这个组件
Vue.component('Father', {
template: '#father',
data() {
return {
money: 2000
}
}
})
// 这里全局注册Son这个组件
Vue.component('Son', {
template: '#son',
props: ['qwer'] //子组件用props来接收这个数据
})
new Vue({
el: '#app'
})
</script>
</body>
产生的问题:
问题一:props接收的money和子组件上绑定的自定义属性money是不是同一个?
不是, 绑定自定义属性名字可以自定义(个人一般会写成一样的)
注意:自定义命名不能有大写字母 用-a来表示
问题二:为什么data要定义一个函数
1.组件是一个独立的个体,那么他应该拥有自己的数据,这个数据应该是一个独立的数据
2.也就是说这个数据应该有独立的作用域(需要一个独立的使用范围,这个范围就是这个组件内)
3.函数提供了独立的作用域
问题三:为什么data要有返回值?返回值还是一个对象
因为Vue是通过observe来观察data选项的,所以必须要有返回值
因为Vue要通过es5的Object.defineProperty属性对对象进行getter和setter设置
子父组件通信
<body>
<div id="app">
<Father></Father>
</div>
<template id='father'>
<div>
<h3>这里是father组件</h3>
<p>儿子给了我{{money}}元钱</p>
<Son @give='getHongbao'></Son>
<!-- 这里是第一步! 绑定一个自定义事件在子组件身上 -->
</div>
</template>
<template id='son'>
<div>
<button @click = 'giveFather'>give</button>
<h3>这里是son组件</h3>
</div>
</template>
<script>
Vue.component('Father', {
template: '#father',
data() {
return {
money: 0
}
},
methods: {
getHongbao(val) {
console.log(1)
this.money = val
}
}
})
Vue.component('Son', {
template: '#son',
data() {
return {
hongbao: 500 //要把这个数据发给父组件 , 首先要在父组件中定义一个数据用来接收这个数据
}
},
methods: {
giveFather() {
//如何进行父组件给子组件的自定义事件触发?
// 这里是第二步骤!!!
this.$emit('give', this.hongbao)
}
}
})
new Vue({
el: '#app',
})
</script>
<!-- 自定义事件
1.自定义的 通过 $on 定义 $emit用来触发
2.通过绑定在组件身上定义 $emit用来触发 -->
<!-- 总结:
1.在父组件的模板中,通过事件绑定的形式,绑定一个自定义事件在子组件身上
2.在子组件中 (子组件的配置项methods中)写一个事件处理函数,在事件处理函数中触发父组件绑定的自定义事件
3.将子组件定义的事件处理函数 绑定在子组件的按钮身上(点击触发 实现步骤2) -->
</body>
非父子组件通信(ref链)
<body>
<div id="app">
<Father></Father>
</div>
<template id="father">
<div>
<h3>这里是father</h3>
<button @click = 'look'>点击查看father的this</button>
<p>father的n: {{ n }}</p>
<hr>
<Son ref = 'son'></Son>
<hr>
<Girl ref = 'girl' :n = 'n'></Girl>
<!-- 通过ref绑定组件后,我们发现在他们共同父组件的$refs里面可以找到子组件 -->
</div>
</template>
<template id="son">
<div>
<h3>这里是son组件</h3>
</div>
</template>
<template id="girl">
<div>
<h3>这里是girl组件</h3>
<button @click = 'out'> 输出girl的this </button>
</div>
</template>
<script>
Vue.component('Father', {
template: '#father',
data() {
return {
n: 0
}
},
methods: {
look() {
this.n = this.$refs.son.money
}
}
})
Vue.component('Son', {
template: '#son',
data() {
return {
money: 1000
}
}
})
Vue.component('Girl', {
template: '#girl',
data() {
return {
num: 0
}
},
methods: {
out() {
console.log(this)
console.log(this.$attrs.n)
}
}
})
new Vue({
el: '#app'
})
</script>
<!-- 总结:ref链可以实现非父子组件的通信,但是如果层级太多就比较繁琐了 -->
</body>
非父子组件通信(bus事件总线)
<div id='app'>
<Bro></Bro>
<Sma></Sma>
</div>
<template id="big">
<div>
<h3>这里是哥哥组件</h3>
<button @click = 'hick'>揍</button>
</div>
</template>
<template id="sma">
<div>
<h3>这里是弟弟组件</h3>
<p v-show = 'flag'>呜呜呜呜呜呜wuwuwuu</p>
</div>
</template>
<script>
var bus = new Vue()
Vue.component('Bro', {
template: '#big',
methods: {
hick() {
bus.$emit('aa');
}
}
})
Vue.component('Sma', {
template: '#sma',
data() {
return {
flag: false
}
},
mounted() {
var _this = this
//当前组件挂载结束,也就是我们在页面当中看到真实的dom
//mounted这个钩子函数的触发条件是组件创建时会自动触发
bus.$on('aa', function() {
_this.flag = true
})
}
})
new Vue({
el: '#app'
})
</script>
<!-- 总结:
1.在其中一个组件的挂载钩子函数上做事件的声明
2.在另一个组件中,通过 bus.$emit('事件名称')来触发自定义事件 -->
非常规手段(不推荐使用)
子父通信
<body>
<div id='app'>
<Father></Father>
</div>
<template id='father'>
<div>
<h3>这里是father组件</h3>
<p>这里是父组件的n:{{n}}</p>
<Son :add = 'add'></Son>
</div>
</template>
<template id='son'>
<div>
<h3>这里是son组件</h3>
<button @click = 'add(2000)'>give</button>
</div>
</template>
<script>
//我们要进行子父组件通信
//理解:使用自定义事件实现
Vue.component('Father', {
template: '#father',
data() {
return {
n: 0
}
},
methods: {
add(val) {
this.n = val
}
}
})
Vue.component('Son', {
template: '#son',
data() {
return {
money: 1000
}
},
props: ['add']
})
new Vue({
el: '#app'
})
</script>
</body>
动态组件
1.什么是动态组件
可以改变的组件
2.使用
通过Vue提供了一个component+is属性使用
3.动态组件指定就是component这个组件
<div id="app">
<button @click = "change"> 切换 </button>
<!-- <keep-alive include="">
<component :is = "type"></component>
</keep-alive> -->
<component :is = "type"></component>
</div>
</body>
<script>
/*
业务: 点击一个按钮进行两个组件的切换
*/
Vue.component('Aa',{
template: '<div> Aa </div>'
})
Vue.component('Bb',{
template: '<div> Bb </div>'
})
new Vue({
data: {
type: 'Aa'
},
methods: {
change () {
this.type = (this.type === 'Aa'?'Bb':'Aa')
}
}
}).$mount('#app')
</script>