共计 3398 个字符,预计需要花费 9 分钟才能阅读完成。
组件 (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 组件化也会有一定的了解了。