Vue组件中的通讯方式

[TOC]

一、引入

相互的组件之间一定会进行数据交互,那一定就会用到组件之间的通讯

  1. 父子之间的通讯———————->a、a.1父给子,property直接传递 。a.2子给父,父先给子偷偷传递一个函数,然后子再调用该函数进行参数传递。==或== a.3父给子绑定自定义函数
    b、使用全局总线
    c、订阅消息
  2. 同级兄弟之间的通讯—————–>a、全局总线 b、订阅消息
  3. 亲戚关系比较复制——————–> a、全局总线 b、订阅消息

二、

1.最简单的方法的方法————–property

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
//使用
//父--to-->子
<student :propertyName="parameterName/functionName"></student>
//子--accept--父
props:["parameterName/functionName"]


//案例
//父组件,使用property传递参数、函数,实现父子之间通讯

<MyFooter :todos="todos" :checkAllTodo="checkAllTodo" :clearAllTodo="clearAllTodo"/>

//子组件,通过接收property,然后收到来自父的参数,并调用函数来传递方法。
<script>
export default {
name:'MyFooter',
props:['todos','checkAllTodo','clearAllTodo'],
computed: {
//总数
total(){
return this.todos.length
},
//已完成数
doneTotal(){
//此处使用reduce方法做条件统计
/* const x = this.todos.reduce((pre,current)=>{
console.log('@',pre,current)
return pre + (current.done ? 1 : 0)
},0) */
//简写
return this.todos.reduce((pre,todo)=> pre + (todo.done ? 1 : 0) ,0)
},
//控制全选框
isAll:{
//全选框是否勾选
get(){
return this.doneTotal === this.total && this.total > 0
},
//isAll被修改时set被调用
set(value){
this.checkAllTodo(value)
}
}
},
methods: {
/* checkAll(e){
this.checkAllTodo(e.target.checked)
} */
//清空所有已完成
clearAll(){
this.clearAllTodo()
}
},
}
</script>

2. 使用自定义事件给子组件的实例对象的绑定事件。

然后在子组件中用 this.$emit("functionName",parameter)进行调用

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
//使用
//父--to-->子
//方法一 直接写
//父
<student @functionName='funName'></student>
//子
this.$emit("fucNa")
//方法二 通过ref
//父
<student ref='student'></student>
this.$ref.student.$on("functionName",parameterName)


//子--accept-->父
this.$emit("functionName")
//使用emit调用即可

3.使用全局总线

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
//1. 在main.js中进行全局总线的挂载安装
//引入Vue
import Vue from 'vue'
//引入App
import App from './App.vue'
//关闭Vue的生产提示
Vue.config.productionTip = false

//创建vm
new Vue({
el:'#app',
render: h => h(App),
beforeCreate() {
Vue.prototype.$bus = this
//安装全局事件总线,尽量早的进行安装
},
})

//2. 在A组件中调用this.$bus.$on()绑定事件
<script>
export default {
name:'School',
data() {
return {
name:'尚硅谷',
address:'北京',
}
},
mounted() {
// console.log('School',this)
//在vc加载完成后就进行绑定
// tip:
// 这里也需要注意this指向的问题,如果想this指向为当前vc,就使用箭头函数/写在methods中的函数(详细看前一篇)
this.$bus.$on('hello',(data)=>{
console.log('我是School组件,收到了数据',data)
})
},
beforeDestroy() {
this.$bus.$off('hello') //
//在beforedestroy是最好进行解绑 ,适当的给它减少压力
},
}
</script>
//3. 在B组件中调用this.$bus.$emit()调用事件
<script>
export default {
name:'Student',
data() {
return {
name:'张三',
sex:'男',
}
},
mounted() {
// console.log('Student',this.x)
},
methods: {
sendStudentName(){
this.$bus.$emit('hello',this.name)
}
},
}
</script>

这里简要说明一下全局总线的工作原理(及其要求):

1. 全局总线的要求: - 全部组件都能访问到 - 可以调用 this.\$on(FunctionName,function) 方法进行事件的绑定、this.\$emit(fuctionName,parameter)方法进行方法的触发

​ 2. 一个重要的内置关系: VueComponent.prototype.proto === Vue.prototype

​ 2.1 为什么要有这个关系:—->让==组件实例对象(vc)==可以访问到 ==Vue原型==上的属性、方法。

这里涉及到了一部分原型链的知识:
简要说明一下: 由构造函数创建的对像(这里为vueComponet创建的vc对象),可以通过 ==_proto_(隐形原型)==访问到构造函数上的==原型==

​ 而构造函数自身可以通过 ==prototype(显示原型)==直接访问自身的==原型对象==

原型链

tip: Q:为什么不把$bus加在vc的原型上?

​ A:每一个vc是由vue构造函数中的extend函数每一次调用生成的,且

​ ——>每次调用vue.extend时,返回的都是一个全新的vuecomponent(即vc的构造函数)

​ —-> 每次的构造函数都不同(详细看18章中的介绍)

​ ↓以下为原型链的知识

​ —原型(prototype)本质上是存在于构造函数上的一个属性,如果每一个vc的构造函数(vueComponent)都不同,那每一个vc都有一个自己的原型(prototype)。

​ final:

​ 如果加在某一个vc的原型上,则无法让每一个vc都能访问到。

​ —->加在vm的原型上,由于vm的构造器只有一个,所以原型也只有一个。

​ 再通过 VueComponent.prototype.proto === Vue.prototype 这个关系,则可以让每一个vc都能成功访问到。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15

//以下为说明原型链中原型属性
<script>

function demo(){
this.a=1;
}
//创建一个demo的实例对象
const d=new Demo()
console.log(demo.prototype) //显示原型属性
console.log(p.__proto__) //隐私原型属性
//两个属性指向的是同一个原型对象,显示和隐式是对属性的修饰,
//------> 不能说“显示原型对象”/“隐式原型对象”,这样子会误以为有两个原型对象
console.log(demo.prototype==p.__proto__) //----> tr
</script>

4. 使用订阅信息推送。

订阅消息与全局总线的原理相近,这里不展开叙说,只说明简要的使用方法

  1. 安装pubsub:npm i pubsub-js

  2. 引入: import pubsub from 'pubsub-js'

  3. 接收数据:A组件想接收数据,则在A组件中订阅消息,订阅的回调留在A组件自身。

    1
    2
    3
    4
    5
    6
    7
    methods(){
    demo(data){......}
    }
    ......
    mounted() {
    this.pid = pubsub.subscribe('xxx',this.demo) //订阅消息
    }
  4. 提供数据:pubsub.publish('xxx',数据)

  5. 最好在beforeDestroy钩子中,用PubSub.unsubscribe(pid)取消订阅。