在总结Vue组件化编程的数据通信方面,看了网上的很多资料,都是讲父子组件的数据交互也就是参数传递,在组件的通信方面分几种情况,比如父子组件、非父子的兄弟组件、非父子的其他组件等等,这样看来,基于Vue.js的组件通讯非常繁琐。
可是我们在C/S下的组件通信并没有这些麻烦,通常情况下,我们怎样设计组件通信?
在组件上声明事件,可以是截获系统事件的,也可以是自定义事件,在这个事件中,我们就可以对外进行数据通信。
沿着这个思路,就可以解决Vue组件化编程的组件通信,很简单了。
另外,在Windows中的消息队列中,我们也可以通过捕获事件的方式来得到组件的操作和数据,也同样可以实现Vue组件化编程的组件通信。
最简单的,当然是组件中的数据直接对外进行数据绑定,这样也就可以实现组件通信了。
所以总结基于Vue.js的组件通信,比较简单易用的三种方式:通过数据绑定与数据监听、通过组件的自定义函数(事件)、通过事件捕获。
下面针对这三种情况分别举例说明。
用于演示的基本数据结构:
personList:[{name:'小明',score:97},{name:'小丽',score:88},{name:'小英',score:95},
]
假设现在需要计算score的总和,并且总分也要随着这些分数值的变化而变化。
1、通过数据绑定与数据监听
首先,在Vue实例的data中定义用于计算总和的数据项total以及personList,再定义组件放置姓名和分数(input输入框),然后组件的数据项与personList绑定,最后监听personList数据变化就可以得到总和,并且每个input框的分数变化后总分也随之变化。
完整网页代码:
<!DOCTYPE html>
<html><head><meta charset="utf-8"><title>Vue.js的组件化编程:组件通信</title><script src="./js/vue2.js"></script></head><body><div id="app"><h2>人员表</h2><my-person v-for="(p,index) in personList" :key="index" :my-person="personList[index]"></my-person><p>总分:{{ total }}</p></div><script type="text/javascript">Vue.component("myPerson",{props:['myPerson'],template:`<div>姓名:{{ myPerson.name }}分数:<input type="number" v-model="myPerson.score"/></div>`,});var vm=new Vue({el:"#app",data:{total:0,personList:[{name:'小明',score:97},{name:'小丽',score:88},{name:'小英',score:95},]},methods:{ScoreChange(){this.total = this.personList.reduce((prev, curr) => {return parseInt(prev) + parseInt(curr.score)}, 0)}},watch:{personList:{handler:'ScoreChange',deep:true,//深度监听immediate:true,//有初始值}}});</script></body>
</html>
显示输出:
2、通过组件的自定义函数(事件)
直接叙述就是在组件的响应事件中调用其他组件的数据或者方法,不用区分父子关系。
完整的代码示例:
<!DOCTYPE html>
<html><head><meta charset="utf-8"><title>Vue.js的组件化编程:组件通信</title><script src="./js/vue2.js"></script></head><body><div id="app"><h2>人员表</h2><my-person :my-name="'小明'" :my-score="'99'" ref="S1"></my-person><my-person :my-name="'小丽'" :my-score="'87'" ref="S2"></my-person><p>总分:{{total}}</p></div><script type="text/javascript">Vue.component("myPerson",{props:['myName','myScore'],data(){return {person:{name:"",score:0}}},mounted() {this.person.name=this.myName;this.person.score=this.myScore;},template:`<div>姓名:{{ person.name }}分数:<input type="number" v-model="person.score" @input="dataChange()"/></div>`,methods:{dataChange(){this.$parent.total=parseInt(this.$parent.$refs.S1.person.score) + parseInt(this.$parent.$refs.S2.person.score);}}});var vm=new Vue({el:"#app",data:{total:0}});</script></body>
</html>
输出结果:
说明:
⑴ 数据绑定可以在created或者mounted中进行;
⑵ 绑定的时候不能少写this,否则会提示找不到数据项;
⑶ 关键在事件中的处理,即this.$parent.$refs包含了组件数据,所以在放置组件的时候要写ref属性值(不能重复)。
3、通过事件捕获
直接叙述就是声明另外一Vue实例进行事件挂载与事件捕获,就是组件的事件在Vue实例上进行注册,在另外组件上需要处理的时候就捕获这个事件即可。
完整的代码示例:
<!DOCTYPE html>
<html><head><meta charset="utf-8"><title>Vue.js的组件化编程:组件通信</title><script src="./js/vue2.js"></script></head><body><div id="app"><h2>人员表</h2><my-person :my-name="'小明'" :my-score="'99'" ref="S1"></my-person><my-person :my-name="'小丽'" :my-score="'87'" ref="S2"></my-person><my-total></my-total></div><script type="text/javascript">eventBus=new Vue();Vue.component("myPerson",{props:['myName','myScore'],data(){return {person:{name:"",score:0}}},mounted() {this.person.name=this.myName;this.person.score=this.myScore; },template:`<div>姓名:{{ person.name }}分数:<input type="number" v-model="person.score" @input="myDataChange()"/></div>`,methods:{myDataChange(){eventBus.$emit('DataChange',this.person); }}});Vue.component("myTotal",{data(){return {total:0,personList:[]}},mounted() {eventBus.$on('DataChange',(p)=>{this.total=0;if( !this.personList.find(obj=>obj.name==p.name) ){this.personList.push(p);}this.personList.forEach(element => {this.total+=parseInt(element.score);}); })},template:`<div>总数:{{ total }}</div>`});var vm=new Vue({el:"#app"});</script></body>
</html>
结果输出:
说明:
⑴ 需要声明另外一个Vue实例,名称可以根据自己需要设定;
⑵ 组件的数据绑定可以在created或者mounted中进行;
⑶ 组件的事件触发eventBus.$emit('DataChange',this.person),DataChange可以被其他组件进行捕获处理;
⑷ 其他组件捕获事件
eventBus.$on('DataChange',(p)=>{//p是传递过来的参数//......
})
原来Vue组件的数据通信这么简单!