在开发Vuejs组件的项目中,经常需要解决的一个问题就是如何处理父组件、子组件之间的数据传递和消息传递,简而言之就是父子组件之间的通信问题。
Vuejs官方有个非常形象的父、子组件的通信示意图,并且也是其推荐的处理方案,图示如下
图1组件意味着协同工作,通常父子组件会是这样的关系:组件 A 在它的模版中使用了组件 B 。它们之间必然需要相互通信:父组件要给子组件传递数据,子组件需要将它内部发生的事情告知给父组件。然而,在一个良好定义的接口中尽可能将父子组件解耦是很重要的。这保证了每个组件可以在相对隔离的环境中书写和理解,也大幅提高了组件的可维护性和可重用性。
作者对于这种通信机制的使用如上解释,父组件是不能直接操作子组件内部的数据的,这样子不利于状态的统一维护,我们可以理解为国家的几级行政制度,我们当然不推荐国家zx直接插手老家村子里的支部书记的任命。
抛开Vuejs这个特殊的环境,让我们来重新思考组件通信的问题。这个所谓的父子组件通信从本质上来说其实就是2个DOM之间的通信,也就是把DOM1的数据或者状态通过某种方式传递给DOM2,那也就不外乎2种方式:一种是直接通话;一种是让人带话。如下列图所示
通信的2种方式而对于Vuejs而言,王老师不知道他要通知哪位同学,在他的眼里看到是一个大的教室,只知道小明就在教室里面,小明对于他而言是一个黑箱(当然Vuejs希望他能对待黑箱一样对待小明,实际上是可以通过$refs来获取到所有的子元素的)。为了,避免王老师每次都直接进教室找到小明,然后再告诉小明要写作业,我们可以在教室门口放个铃铛,他们约定好:王老师要小明写作业时去敲一下铃铛,小明作业写完了敲2下铃铛,这样他们甚至不需要见面仅凭这个简单地铃铛来传递信息了。如下图:
铃铛通信图因此,当父组件想要更改子组件的状态或者数据时,可以通过修改子组件对外暴露的属性值的方式,子组件内部将这些属性值用于内部视图的渲染、状态切换等行为。上面提到了小明敲2下铃铛告诉王老师他的作业写完了。那么问题来了,因为小明写作业这个任务是不确定时间的,王老师不知道什么时间小明能写完作业。别担心,Vuejs组件的自定义事件刚好可以完美解决这个问题。
事件流图通过王老师让小明写作业这个简单的生活场景,各位有没有更好地理解Vuejs中父子组件的通信方法呢?
下面用一个常见的UI组件(alert)为例,来进一步演示父子组件通信的实际运用。
我们先看看组件在页面的实际引入代码
<div class="status-wrapper">
<hna-alert v-bind:type="type" v-bind:visible="visible" v-bind:text="text"></hna-alert>
</div>
我们在父组件上面希望可以控制子组件的:展示与隐藏、展示类型、展示文本,因此在构建组件时将这些值暴露在组件外部供父组件进行设置和更改,而在组件内部,这些值用来动态渲染组件的表现,代码如下
props : {
//alert的类型
type : {
type : String,
default : 'loading'
},
//是否展示文本
hasText : {
type : Boolean,
default : true
},
//文本默认为空格进行站位
text : {
type : String,
default : ' '
},
//显示还是隐藏
visible : {
type : Boolean,
default : false
}
},
data : function () {
return {
types : {
loading : 'loading',
success : 'success',
fail : 'fail',
warning : 'warning'
}
}
},
computed : {
status : function () {
var _this = this;
return {
loading : _this.type == _this.types.loading,
success : _this.type == _this.types.success,
fail : _this.type == _this.types.fail,
warning : _this.type == _this.types.warning
};
}
},
template : '<transition name="slide-fade">\
<div class="hna-alert" v-show="visible">\
<div class="alert-main">\
<i class="ico-alert" v-bind:class="{loading : status.loading,success : status.success,fail : status.fail,warning : status.warning}"></i>\
<p class="alert-tip">{{text}}</p>\
</div>\
</div>\
</transition> '
子组件的模板上使用type、text这些来控制图标、文本的展示,同时visible来控制子组件的状态(展示、隐藏)。这个示例中没有演示子组件通知父组件自己的一些状态或数据变化,但是大家可以到Hna-UI查看hna-password的源码,是用到子组件通过自定义事件通知父组件数据的方法的。
浅陋之谈,欢迎批评、斧正,不胜感激。
网友评论