[TOC]
一、引入
相互的组件之间一定会进行数据交互,那一定就会用到组件之间的通讯
。
- 父子之间的通讯———————->a、a.1父给子,property直接传递 。a.2子给父,父先给子偷偷传递一个函数,然后子再调用该函数进行参数传递。==或== a.3父给子绑定自定义函数
b、使用全局总线
c、订阅消息
- 同级兄弟之间的通讯—————–>a、全局总线 b、订阅消息
- 亲戚关系比较复制——————–> 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
|
import Vue from 'vue'
import App from './App.vue'
Vue.config.productionTip = false
new Vue({ el:'#app', render: h => h(App), beforeCreate() { Vue.prototype.$bus = this }, })
<script> export default { name:'School', data() { return { name:'尚硅谷', address:'北京', } }, mounted() { this.$bus.$on('hello',(data)=>{ console.log('我是School组件,收到了数据',data) }) }, beforeDestroy() { this.$bus.$off('hello') }, } </script>
<script> export default { name:'Student', data() { return { name:'张三', sex:'男', } }, mounted() { }, 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; } const d=new Demo() console.log(demo.prototype) console.log(p.__proto__) console.log(demo.prototype==p.__proto__) </script>
|
4. 使用订阅信息推送。
订阅消息与全局总线的原理相近,这里不展开叙说,只说明简要的使用方法
安装pubsub:npm i pubsub-js
引入: import pubsub from 'pubsub-js'
接收数据:A组件想接收数据,则在A组件中订阅消息,订阅的回调留在A组件自身。
1 2 3 4 5 6 7
| methods(){ demo(data){......} } ...... mounted() { this.pid = pubsub.subscribe('xxx',this.demo) }
|
提供数据:pubsub.publish('xxx',数据)
最好在beforeDestroy钩子中,用PubSub.unsubscribe(pid)
去取消订阅。