像平时前端开发中,我们经常使用elementUI
,iviewUI
,移动端vant
,mint
等等。那么他们的封装是如何实现的呢。
整体用到的vue
的相关知识为:
prop
官方:Prop 是你可以在组件上注册的一些自定义 attribute。当一个值传递给一个 prop attribute 的时候,它就变成了那个组件实例的一个 property。
通俗:父组件引用子组件并给子组件增加一个属性,并可以传递数据
插槽
官方:Vue 实现了一套内容分发的 API,将 slot
元素作为承载分发内容的出口。
通俗:给一个组件传递一些内容
$emit
官方:监听当前实例上的自定义事件。事件可以由 vm.$emit
触发。回调函数会接收所有传入事件触发函数的额外参数。
通俗:子组件可以使用 $emit 触发父组件的自定义事件,传递数据
接下来就用常用的Button组件做例子。
要求及思路:
$emit
将能够使用到的事件传递出去外部Vue使用:(简写)
import {
Button } from '@/components/Button/index'
<div>
<p class="explain_title">按钮类型</p>
<Button type="normal">普通按钮</Button>
<Button type="default">默认按钮</Button>
<Button type="error">警告按钮</Button>
<Button type="success">主要按钮</Button>
<Button type="warning">警告按钮</Button>
</div>
<div>
<p class="explain_title">朴素按钮</p>
<Button plain type="normal">普通按钮</Button>
<Button plain type="default">默认按钮</Button>
<Button plain type="error">警告按钮</Button>
<Button plain type="success">主要按钮</Button>
<Button plain type="warning">警告按钮</Button>
</div>
<div>
<p class="explain_title">圆角按钮</p>
<Button circle plain type="normal">普通按钮</Button>
<Button circle plain type="default">默认按钮</Button>
<Button circle type="error">警告按钮</Button>
<Button circle type="success">主要按钮</Button>
<Button circle plain type="warning">警告按钮</Button>
</div>
Button.vue放封装的主体,建议再建一个js文件,export输出出去,因为以后可能同类封装的组件不止一个,如element对于Button还有一个button-group的组件
<template>
<button
@click="handleClick"
:class="[
// 此步为重要的步骤,主要是控制class来控制显示不同的按钮样式
type ? 'ice-button--' + type : '',
'button_init',
{
'is-plain': plain,
'is-circle': circle
}
]"
>
//使用插槽
<span v-if="$slots.default"><slot></slot></span>
</button>
</template>
<script>
export default {
name: 'Button',
// 使用prop自定义属性
props: {
// type来定义button的类型
type: {
type: String,
default: "normal",
},
// 是否为背景白色,边框和字体同颜色的简朴按钮
plain: Boolean,
// 是否为圆角按钮(在这里我是做了圆角处理不是完全圆)
circle: Boolean,
},
computed: {
},
methods: {
handleClick(evt) {
this.$emit("click", evt);
},
},
};
</script>
这里我简单写了几个三类样式
/* base */
.button_init {
display: inline-block;
margin: 10px;
width: 90px;
height: 45px;
font-size: 12px;
position: relative;
}
.button_init:active::after {
content: "";
position: absolute;
top: 0px;
left: 0px;
width: 100%;
height: 100%;
background: rgba(0, 0, 0, 5%);
}
/* 普通按钮 */
.ice-button--normal {
background: #474747;
border: 1px solid #474747;
color: #ffffff;
}
.ice-button--normal.is-plain {
background: #fff;
border: 1px solid #474747;
color: #474747;
}
.ice-button--normal.is-plain.is-circle {
background: #fff;
border: 1px solid #474747;
color: #474747;
border-radius: 10px;
}
.ice-button--normal.is-circle {
background: #474747;
border: 1px solid #474747;
color: #ffffff;
border-radius: 10px;
}
/* 默认按钮 */
.ice-button--default {
background: #1989fa;
border: 1px solid #1989fa;
color: #ffffff;
}
.ice-button--default.is-plain {
background: #fff;
border: 1px solid #1989fa;
color: #1989fa;
}
.ice-button--default.is-plain.is-circle {
background: #fff;
border: 1px solid #1989fa;
color: #1989fa;
border-radius: 10px;
}
.ice-button--default.is-circle {
background: #1989fa;
border: 1px solid #1989fa;
color: #ffffff;
border-radius: 10px;
}
/* 警告按钮 */
.ice-button--error {
background: #eb2f06;
border: 1px solid #eb2f06;
color: #ffffff;
}
.ice-button--error.is-plain {
background: #fff;
border: 1px solid #eb2f06;
color: #eb2f06;
}
.ice-button--error.is-plain.is-circle {
background: #fff;
border: 1px solid #eb2f06;
color: #eb2f06;
border-radius: 10px;
}
.ice-button--error.is-circle {
background: #eb2f06;
border: 1px solid #eb2f06;
color: #ffffff;
border-radius: 10px;
}
/* 主要按钮 */
.ice-button--success {
background: #2ecc71;
border: 1px solid #2ecc71;
color: #ffffff;
}
.ice-button--success.is-plain {
background: #fff;
border: 1px solid #2ecc71;
color: #2ecc71;
}
.ice-button--success.is-plain.is-circle {
background: #fff;
border: 1px solid #2ecc71;
color: #2ecc71;
border-radius: 10px;
}
.ice-button--success.is-circle {
background: #2ecc71;
border: 1px solid #2ecc71;
color: #ffffff;
border-radius: 10px;
}
/* 警告按钮 */
.ice-button--warning {
background: #f39c12;
border: 1px solid #f39c12;
color: #ffffff;
}
.ice-button--warning.is-plain {
background: #fff;
border: 1px solid #f39c12;
color: #f39c12;
}
.ice-button--warning.is-plain.is-circle {
background: #fff;
border: 1px solid #f39c12;
color: #f39c12;
border-radius: 10px;
}
.ice-button--warning.is-circle {
background: #f39c12;
border: 1px solid #f39c12;
color: #ffffff;
border-radius: 10px;
}
import Button from './Button.vue'
export{
Button
}
根据这个思路,还可以给封装的Button组件加上icon。比如element封装的Button
然后像其他的组件都可以使用此思路进行细致的封装,这里我只是简单的封装了下,具体也可以去找element或者其他库的源码去看看,学习一下。