组件 (Component) 是 Vue.js 最强大的功能之一。组件可以扩展 HTML 元素,封装可重用的代码。
组件的创建和注册
我们可以使用 Vue.component(tagName, options)
注册一个全局组件。
<!--全局注册-->
<template>
<div id="app">
<my-component></my-component>
</div>
</template>
<script>
// 全局注册组件
Vue.component('my-component', {
template: '<div>我的组件</div>'
})
// 创建根实例
new Vue({
el: '#app'
})
</script>
<!--渲染后的HTML-->
<div id="app">
<div>我的组件</div>
</div>
我们还可以通过某个 Vue
实例/组件的实例选项 components
注册仅在其作用域中可用的组件,即局部组件。
<!--局部注册-->
<template>
<div id="app">
<my-component></my-component>
</div>
</template>
<script>
var Child = {
template: '<div>我的组件</div>'
}
new Vue({
el: '#app',
components: {
// 局部注册组件,<my-component> 将只在父组件模板中可用
'my-component': Child
}
})
</script>
<!--渲染后的HTML-->
<div id="app">
<div>我的组件</div>
</div>
使用prop
组件实例的作用域是孤立的。父组件的数据需要通过 prop 才能下发到子组件中。
<!--静态prop-->
<template>
<child message="哈喽"></child>
</template>
<script>
Vue.component('child', {
// 声明 props
props: ['message'],
// 就像 data 一样,prop 也可以在模板中使用
// 同样也可以在 vm 实例中通过 this.message 来使用
template: '<span>{{ message }}</span>'
})
</script>
如果想要传递一个变量到子组件中去,即传给子组件的值会跟随父组件中该变量的值的变化而变化,我们可以用 v-bind
来动态地将 prop
绑定到父组件的数据。
<!--动态prop-->
<template>
<div id="dynamic-prop">
<input v-model="parentMsg">
<br>
<child v-bind:my-message="parentMsg"></child>
</div>
</template>
<script>
new Vue({
el: '#dynamic-prop',
data: {
parentMsg: '父组件发过来的消息'
}
})
</script>
我们还可以为组件的 prop
指定验证规则。如果传入的数据不符合要求,Vue
会发出警告。这对于开发给他人使用的组件非常有用。
<!--prop验证-->
<script>
Vue.component('example', {
props: {
// 基础类型检测 (`null` 指允许任何类型)
propA: Number,
// 可能是多种类型
propB: [String, Number],
// 必传且是字符串
propC: {
type: String,
required: true
},
// 数值且有默认值
propD: {
type: Number,
default: 100
},
// 数组/对象的默认值应当由一个工厂函数返回
propE: {
type: Object,
default: function () {
return { message: 'hello' }
}
},
// 自定义验证函数
propF: {
validator: function (value) {
return value > 10
}
}
}
})
</script>
自定义事件进行组件通讯
现在我们父组件可以使用 prop
传递数据给子组件。但子组件怎么跟父组件进行通信呢?这里我们可以通过自定义事件来实现。
具体点说就是使用 $on(eventName)
监听事件,使用 $emit(eventName, optionalPayload)
触发事件。
<template>
<div id="message-event">
<p v-for="msg in messages">{{ msg }}</p>
<button-message v-on:message="handleMessage"></button-message>
</div>
</template>
<script>
Vue.component('button-message', {
template: `<div>
<input type="text" v-model="message" />
<button v-on:click="handleSendMessage">发送消息</button>
</div>`,
data: function () {
return {
message: '哈喽'
}
},
methods: {
handleSendMessage: function () {
this.$emit('message', { message: this.message })
}
}
})
new Vue({
el: '#message-event',
data: {
messages: []
},
methods: {
handleMessage: function (payload) {
this.messages.push(payload.message)
}
}
})
</script>
使用插槽分发内容
为了让组件可以自由组合,我们需要一种方式来混合父组件的内容与子组件自己的模板。这个过程被称为内容分发。我们可以使用特殊的 <slot>
元素作为原始内容的插槽,从而实现内容分发。
如果子组件模板包含一个 <slot>
插口,那么父组件的内容将会被渲染到插槽中。
<!--子组件模板-->
<templalte>
<div>
<h2>子组件的标题</h2>
<slot>
只有在没有要分发的内容时才会显示。
</slot>
</div>
</templalte>
<!--父组件模板-->
<template>
<div>
<h1>父组件的标题</h1>
<my-component>
<p>这是将会分发到子组件的一些初始内容</p>
</my-component>
</div>
</template>
<!--渲染后的HTML-->
<div>
<h1>父组件的标题</h1>
<div>
<h2>子组件的标题</h2>
<p>这是将会分发到子组件的一些初始内容</p>
</div>
</div>
当需要有多个插槽时,我们可以在<slot>
元素上用一个特殊的特性 name
来进一步配置如何分发内容。多个插槽配置不同的名字,这时具名插槽将匹配内容片段中有对应 slot
特性 name
的元素。
<!--layout 子组件模板-->
<template>
<div class="container">
<header>
<slot name="header"></slot>
</header>
<main>
<slot></slot>
</main>
<footer>
<slot name="footer"></slot>
</footer>
</div>
</template>
<!--父组件模板-->
<template>
<layout>
<h1 slot="header">头部标题</h1>
<p>主体内容的一个段落。</p>
<p slot="footer">尾部版权信息</p>
</layout>
</template>
<!--渲染后的HTML-->
<div class="container">
<header>
<h1>头部标题</h1>
</header>
<main>
<p>主体内容的一个段落。</p>
</main>
<footer>
<p>尾部版权信息</p>
</footer>
</div>
总结
本节主要知识点是vue.js
中组件的创建和注册,父组件使用prop
向子组件传递数据并进行数据验证,使用自定义事件进行组件间的通讯,使用插槽来使组件可以自由组合。vue.js
组件是vue
框架中最强大的功能,学完后相信你对web组件化也会有一定的了解了。