看完这篇文章,你将了解:
- 为什么要使用组件?
- 全局注册和局部注册组件
- 父组件如何给子组件传递数据?
- 子组件如何给父组件传递数据?
- 非父子组件如何通信?
- 什么是单向数据流?单向数据流的两种应用常景
为什么要使用组件?
组件 (Component) 是 Vue.js 最强大的功能之一。组件可以扩展 HTML 元素,封装可重用的代码。在较高层面上,组件是自定义元素,Vue.js 的编译器为它添加特殊功能。在有些情况下,组件也可以表现为用 is 特性进行了扩展的原生 HTML 元素。所有的 Vue 组件同时也都是 Vue 的实例,所以可接受相同的选项对象 (除了一些根级特有的选项) 并提供相同的生命周期钩子。
全局注册和局部注册组件
组件两要素: 组件名和模板
全局注册
Vue.component('component', { template: '<div>我是一个全局组件</div>' })
局部注册
var app = new Vue({ el: '#app', components: { 'component': { template: '<div>我是一个局部注册组件</div>' } } })
- 全局注册: Vue.component(组件名, 模板)
- 局部注册: components: {组件名: 模板}
父组件如何给子组件传递数据?
在组件的属性上实现
- 子组件设置属性
xx=父组件信息
- 子组件的 props 变量接收 xx
props 译为属性,组件中的 props 变量定义的就是组件作为 html 标签的属性数组
之所以用属性传递数据,是因为从 html 角度上讲,子组件属性是子组件暴露给父组件的数据接口
<div id='app'>
<com xx='msg'></com>
</div>
var app = new Vue({
el: 'app',
data: {
msg: '来自父组件的信息'
},
components: {
'com': {
template: '<div>{{xx}}</div>',
props: ['xx']
}
}
})
理论上,也可以通过以下方式拿到父组件数据
this.$parent.父亲数据
this.$root.父亲数据 (若 root 是父亲)
子组件如何给父组件传递数据?
自定义事件实现
有三个关键部分:
- 子组件绑定自定义事件(这是一个桥梁,搭完后两段施工)
<com @事件名 = 方法名></com>
- 子组件端触发
事件名
methods:
...
this.$emit(事件名, this.message)
...
- 父组件端注册
方法名
methods:
...
方法名: function(value) {}
...
这样,子组件的数据 this.message 就成为了父组件方法参数中的 value
demo
理论上,也可以通过以下方式拿到子组件数据
<com ref='a'>, 然后 this.$ref.a.子组件数据
非父子组件如何通信?
借助公共父组件通信(类似于 eventHub 模块)
- 父组件搭建事件中心
bus: new Vue()
- 发送者访问父亲的 bus,发送事件
this.$root.bus.$emit(xx, 数据)
- 接受者访问父亲的 bus,注册事件
this.$root.bus.$on(xx, 动作)
单向数据流
- 解释:也就是父组件数据变化时会传递给子组件,但是反过来不行。比如通过
props
传递数据就是单向。 - 目的:是尽可能将父子组件解耦,避免子组件无意间修改了父组件的状态
- 应用场景:业务中经常遇到两种需要改变(使用) prop 的情况
- 一种是父组件传递初始值进来,子组件将它作为初始值保存起来,在自己的作用域下可以随意使用和修改。这种情况可以在组件 data 内再声明一个数据,引用父组件数据
Vue.component('my-component', {
props: ['msg'],
template: '<div>{{count}}</div>',
data: function() {
return {
count: this.msg
}
}
})
- 另一种是 props 作为需要被转变的原始值传入。这种情况用计算属性就可以了
Vue.component('width-component', {
props: ['width'],
template: '<div :style="style"></div>'
computed: {
style: function() {
return {
width: this.width + 'px',
background: 'red',
height: '30px'
}
}
}
})
<div id='app'>
<input type="text" v-model="width">
<width-component :width="width"></width-component>
</div>
暂无评论