组件(Component)是Vue.js 最强大的功能之一。组件可以扩展HTML 元素,封装可重用的代码。
在较高层面上,组件是自定义元素,Vue.js 的编译器为它添加特殊功能。在有些情况下,组件也可以是原声HTML 元素的形式,以 is 特性扩展。
使用组件
#注册
<!-- 注册全局组件 -->
Vue.component(tagName,options)
Vue.component('my-component',{
//选项
})
确保在初始化根实例之前注册组件
<div id="example">
<my-component></my-component>
</div>
<script>
// 注册
Vue.component('my-component',{
template: '<div>A custom component!</div>'
})
//创建根实例
new Vue({
el:example
})
</script>
<!-- 渲染为 -->
<div id="example">
<div>A custom component!</div>
</div>
#局部注册
不必在全局注册每个组件。
通过使用组件实例选择项注册,可以使组件仅在另一个实例/组件的作用域中可用:
<script>
// 注册
var Child={
template: '<div>A custom component!</div>'
}
//创建根实例
new Vue({
el:example,
components:{
'my-component':Child
}
})
</script>
#DOM 模板解析说明
当使用DOM 作为模板是(例如,将el 选项挂载到一个已存在的元素上),将会受到HTML 的一些限制。尤其像
-
,
-
,,限制了能被它包裹的元素。
-
,,限制了能被它包裹的元素。
<!-- 自定义中使用受限元素时会导致一些问题 -->
<table>
<my-row>...</my-row>
</table>
<!-- 变通方案是使用特殊的 is 属性 -->
<table>
<tr is="my-row">...</tr>
</table>
#data必须是函数
通过Vue 构造函数传入的各种选项大多数都应该在组件利用。data 是一个例外,它必须时函数。
<script>
// Vue 会停止,data 必须是一个函数
Vue.component('my-component',{
template: '<span>{{message}}</span>',
data:{
message: 'hello'
}
})
data:function(){
// 技术上data 的确是一个函数,因此Vue 不会警告
// 但返回给每个组件的实例却引用了同一个data 对象
return data
}
data:function(){
//为每个组件返回全新的data 对象,每个counter 都有自己内部状态
return {
counter:1
}
}
</script>
#构成组件
组件意味着协同工作,通常父子组件关系:
组件A 在它的模板中使用了组件B,父组件要给子组件传递数据,子组件需要将内部发生的事情告知给父组件。
然而,在一个良好定义的接口中尽可能将父子组件解耦时很重要的。这保证了每个组件可以在相对隔离的环境中书写和理解,也大幅提高了组件的可维护性和可重用性。
注:耦合时指两个或两个以上的体系或运动形式间通过相互作用而彼此影响以至联合起来的现象。
解耦就是将两种运动分离开来处理问题,常用解耦方法时忽略或简化对所有研究问题影响小的一种运动,只分析主要运动。
父组件通过props 向下传递数据给子组件
子组件通过events 给父组件发送信息
Prop
使用Prop 传递数据
组件的作用域是孤立的。
意味着不能(也不应该)在子组件的模板内直接引用父组件的数据。要让子组件使用父组件的数据,需要通过子组件的props 选项。
<child message="hello"></child>
Vue.component('child',{
props:['message'],
template:'<span>{{message}}</span>'
})
动态Prop
v-bind 动态地绑定父组件的数据到子模板的props
<input v-model="parentMsg">
<br>
<!-- 两种写法 -->
<child v-bind:my-message="parentMsg"></child>
<child :my-message="parentMsg"></child>
//
Vue.component('child',{
props:['myMessage'],
template:'<span>{{myMessage}}</span>'
})
字面量语法vs动态语法
传递一个实际的number,需要使用v-bind
<!-- 错误使用,被当作字符串 -->
<comp some-prop="1"></comp>
<!-- 必须使用v:bind -->
<comp v-bind:some-prop="1"></comp>
单向数据流
prop 是单向绑定:当父组件的属性变化时,将传到给子组件,但是不会反过来。
自定义事件
父组件使用props 传递数据给子组件,子组件使用v-on 与父组件通信
使用v-on 绑定自定义事件
on(eventName)监听事件
emit(eventName) 触发事件
注:不能用$on 侦听子组件抛出事件,而必须在模板里直接用v-on 绑定
<p>{{total}}</p>
<button-counter v-on:increment="incrementTotal"></button-counter>
<button-counter v-on:increment="incrementTotal"></button-counter>
//
Vue.component('button-counter',{
template:'<button v-on:click="incrementCount">{{counter}}</button>',
data:function(){
return {
counter: 0
}
},
methods:{
incrementCount:function(){
this.counter +=1
this.$emit('increment') //触发事件
}
}
})
new Vue({
el:'#counter-event-example',
data:{
total:0
},
methods:{
incrementTotal:function(){
this.total +=1
}
}
})