1. 创建组件
使用 Vue.component
创建组件:
Vue.component('button-click', {
data: function() {
return {
counter: 0
}
},
template: '<button v-on:click="counter++">you click me for {{counter}} times.</button>'
});
通过组件可以自定义一个标签:button-click
每一个组件都是一个可复用的 Vue 实例,同样可以添加 data、template、computed 和 methods,但组件没有 el
这种根实例才具有的选项!
接着在 HTML 中使用组件,可以在一个通过 new Vue
创建的 Vue 根实例中,把这个组件作为自定义元素来使用:
<div id="components-demo">
<button-counter></button-counter>
</div>
let vm = new Vue({
el: "#root"
})
注意:
data 是一个函数,因为每次使用组件都需要分配新的 data !
2. 组件的组织
通常一个应用会以一棵嵌套的组件树的形式来组织:
![](https://cn.vuejs.org/images/components.png)
为了能在模板中使用,组件必须先注册,Vue 才能识别。可以是全局注册或局部注册,通过 Vue.component
是全局注册:
Vue.component('component-name', {
data: function() {
// data
},
template: ''
})
使用全局注册的组件可以被任何通过 new Vue
创建的根实例使用。
3. Prop
# props 的使用
父组件可以通过 props
向子组件传递数据。Prop 是在组件上注册的自定义 attribute 属性,当一个值传递给一个 prop attribute 的时候,它就编程了那个组件实例(标签)的 property。如:
Vue.component('paper', {
props: ['title', 'content'],
template: '<h1>{{title}}</h1>'
})
所有 prop 都存放在数组 props
中(同时加了 ''
),一个 prop 被注册后,可以把数据作为属性传递到组件实例(标签):
<paper title="Vue"></paper>
组件也可以和一般标签一样使用 v-bind
、v-for
等模板命令。
注意: prop 命名为 camelCase 命名的变量在 HTML 中属性对应 kebab-case 命名!
# prop 数据类型
可以以对象形式列出 prop,这些 property 的名称和值分别是 prop 各自的名称和类型:
new Vue({
props: {
title: String,
// 必填
author: {
type: String,
required: true
},
// 有默认值
year: {
type: Number,
default: 2020
},
callback: Function,
tags: Array,
isPblished: Boolean
}
})
4. 单个根元素
当组件内不只包含一个标签时,需要将他们放在一个根元素内,如下面使用 div
包裹子标签(使用 ` 可以让字符串换行书写):
Vue.component('paper', {
props: ['title', 'content'],
template: `
<div class="paper">
<h1>{{title}}</h1>
<p>{{content}}</p>
</div>
`
})
let vm = new Vue({
el: "#root"
})
<div id="root">
<paper title="Vue" content="Vue is awesome."></paper>
</div>
如果酶将多个元素放在根元素,则会报错提示:
Component template should contain exactly one root element
5. 监听子组件事件
子组件可以通过 $emit
触发当前实例上的事件,事件可以被父组件检测到。
当我们使用子组件实现了 paper 排版,当需要能够调节字号的功能时,需要与父组件联系。
# 在父组件中添加一个控制字体的变量
let vm = new Vue({
el: "#root",
data: {
// 使用 em 做单位,em 是相对度量单位
paperFontSize: 1
}
})
# 在子组件中添加按钮触发字号放大事件
Vue.component('paper', {
props: ['title', 'content'],
template: `
<div>
<h1>{{title}}</h1>
<p>{{content}}</p>
<button @click="$emit('enlarge-text')">Enlarge text</button>
</div>`
})
上面的代码添加了 button
,点击 button 后,调用内建的 $emit
方法来除法一个名为 enlarge-text
的事件,该事件可以被父组件监测到。
# 父组件处理子组件触发的事件
<div id="root"
v-bind:style="{fontSize: paperFontSize + 'em'}">
<paper
title="Vue"
content="Vue is awesome."
@enlarge-text="paperFontSize += 0.1"
></paper>
</div>
# 使用事件抛出一个值
子组件可以通过 $emit
触发当前实例上的事件,事件可以被父组件检测到,事件也可以抛出一个值,可以使用 $emit
的第二个参数提供这个值:
$emit(event, args){
// event 为抛出的事件名(字符串)
// args 为可选的参数
}
如:
<button @click="$emit('enlarge-text', 0.1)">
Enlarge text
</button>
在父级组件中通过 $event
可以访问这个值:
<paper
...
@enlarge-text="paperFontSize += $event"
></paper>
或者通过函数来访问,这个值作为第一个参数传入方法:
<paper
...
@enlarge-text="onEnlargeText"
></paper>
// 父组件
new Vue({
el: "#root",
methods: {
onEnlargeText: function(amount){
this.paperFontSize += amount;
}
}
})
6. 插槽
当需要向一个自定义组件传递内容时,需要设置插槽:
Vue.component('paper', {
template: `
<div>
<slot></slot>
</div>`
})
slot
可以插入 HTML 代码:
<paper>
<p>this is the content.</p>
</paper>