1.1 绪论
组件化和虚拟DOM是vue的俩大特性。组件系统是Vue中非常重要的一个特性,通过组件的封装,我们可以实现代码的复用以及功能的解耦。组件可以扩展HTML元素,封装可重用的代码。在较高层面上,组件是自定义的元素,Vue.js的编译器为它添加特殊功能。本文将以实际具体的业务组件为例,进行相关的学习总结。
1.2 组件的定义
1.3 组件的注册
1.3.1 全局注册
全局注册,当我们注册全局组件后,我们可以在任何Vue根实例的模板中使用它,全局注册组件的语法如下:
Vue.component('my-component-name', {
// ... 选项 ...
})
全局注册组件也存在一个问题,假如我们项目中的组件都进行了全局注册,webpack打包工具会将这些注册了的组件都进行打包,即使在项目中不再使用的组件也仍旧会被打包,这就会造成代码的冗余。
1.3.2 局部注册
通过普通JavaScript对象的方式来定义组件:
var ComponentA = { /* ... */ }
var ComponentB = { /* ... */ }
var ComponentC = { /* ... */ }
然后在 components 选项中定义你想要使用的组件:
new Vue({
el: '#app',
components: {
'component-a': ComponentA,
'component-b': ComponentB
}
})
1.4 vue组件三要素
- props参数:
数据父组件传入子组件父对子传参,就需要用到 props:
// 通常情况下,通用组件的的应用场景比较复杂,对 props 传递的参数应该添加一些验证规则,常用格式如下:
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
}
}
}
- slot定制插槽:
slot-是可替代插槽,可以用其他节点替换,实现定制模态窗口内容的功能 - event自定义事件
2.1 组件封装
接下来以实际业务为例,说明在实际开发中如何在使用vue-cli脚手架工具创建的项目中从零开始封装一些通用的组件,以封装一个ModalBox组件为例:
2.1.1 组件总体说明
带有标题、可自定制主体内容、按钮文本和行为的模态窗口:

- 属性参数
| 参数 | 说明 | 类型 | 默认值 | 备注 |
|---|---|---|---|---|
| title | 窗口标题 | String | '' | 如果为空,则标题栏不显示(不占高度) |
| labelConfirm | 确定按钮标签 | String | '确定' | |
| labelCancel | 取消按钮标签 | String | '取消' | |
| showConfirmButton | 显示确认按钮 | Boolean | true | |
| showCancelButton | 显示取消按钮 | Boolean | true | |
| showCloseButton | 显示关闭按钮 | Boolean | true | |
| enableBgCancelEvent | 背景支持点击关闭事件 | Boolean | true | |
| showMask | 显示蒙层 | Boolean | true | |
| onConfirm | 确认按钮回调 | Function | 匿名空函数 | |
| onCancel | 取消按钮回调 | Function | 匿名空函数 | |
| onRef | 获取实例对象 | Object | 当前弹窗的实例对象 |
- API方法
| 事件名称 | 说明 | 返回参数 |
|---|---|---|
| showModal | 先获取对象实例,通过实例调用该方法 | - |
2.1.2 项目的创建
vue-cli4.x初始化一个空的工程:

// ModalBox.vue
<!-- component-name & component description -->
<template>
<div class="modalbox">
<div v-if="active">
<div v-if="showMask" class="modalbox-cover" @click="onBgCancel"></div>
<div class="contain-wrapper">
<div class="main-context" :style="bodyBgColor">
<div class="content-wrapper">
<span v-show="title" class="title">{{title}}</span>
<div class="content">{{'主题内容区域'}}</div>
</div>
<div v-show="showConfirmButton || showCancelButton" class="button-dock">
<div v-if="showConfirmButton" @click="onCancel" class="btn-cancel btn-normal">{{labelCancel}}</div>
<div v-show="showConfirmButton && showCancelButton" class="split-line"></div>
<div
v-show="showCancelButton" @click="onConfirm" class="btn-confirm btn-normal">{{labelConfirm}}</div>
</div>
</div>
<div v-show="showCloseButton" class="btn-close">
<div @click="onCancel">
<img src="https://img.baidu.com/img/close.png" class="img" />
</div>
</div>
</div>
</div>
</div>
</template>
<script>
export default {
name: "ModalBox",
components: {},
props:{},
data() {
return {};
},
mounted() {},
methods: {}
};
</script>
<style lang='less' scoped>
.modalbox {
.modalbox-cover {
position: fixed;
top: 0;
left: 0;
right: 0;
bottom: 0;
z-index: 300;
width: 100%;
height: 100%;
background: rgba(0, 0, 0, 0.65);
}
.contain-wrapper {
position: fixed;
z-index: 200;
left: 50%;
top: 50%;
transform: translate(-50%, -50%);
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
z-index: 301;
.main-context {
width: 540px;
background: rgba(255, 255, 255, 1);
border-radius: 24px;
overflow: hidden;
.content-wrapper {
display: flex;
flex-direction: column;
align-items: center;
justify-content: start;
.title {
padding-top: 48px;
font-size: 32px;
font-weight: 500;
color: rgba(51, 51, 51, 1);
line-height: 44px;
}
.content {
width: 100%;
font-size: 32px;
color: rgba(102, 102, 102, 1);
}
}
.button-dock {
display: flex;
height: 104px;
border-top: 2px rgba(247, 247, 247, 1) solid;
.btn-normal {
display: flex;
box-sizing: border-box;
flex: 1;
font-size: 32px;
font-weight: 400;
line-height: 40px;
justify-content: center;
align-items: center;
}
.btn-cancel {
color: rgba(111, 111, 111, 1);
}
.btn-confirm {
color: rgba(255, 88, 96, 1);
}
.split-line {
width: 2px;
height: 100%;
background-color: rgba(247, 247, 247, 1);
}
}
}
.btn-close {
width: 90px;
height: 90px;
margin-top: 48px;
.catchForm {
width: inherit;
height: inherit;
}
.img {
width: 100%;
height: 100%;
}
}
}
}
</style>