😄你们过年好!如今已经进入21
世纪20
年代了,20
后的出现对于92
年还没女友的我刺激仍是蛮大的,虽然还差点步入中年,但咱们仍是须要展望将来,期待着一份美好的爱情。这也是个人新年愿望,但愿和我有一样境遇的小伙伴在新的一年都能找到本身理想的另外一半儿👄。css
最近这两年前端技术真的是变幻无穷,让人透不过气来,但总有那些牛X的大佬及时的把新技术总结分享出来供咱们这些小白白吸取,虽然仍是记不太住...😫前端
做为一名前端儿,对广泛在公司写业务是最基本不过的事情了,使用过的轮子无数,但多是岁数大了,记性不是特别好,对使用过的轮子再次用到仍是免不了各类google
、度娘走一波,诶心累😥。好久之前我就很是羡慕这些轮子的制造者,在平常工做中若可以封装组件会更加使本身的技术获得提高,基础更加扎实,说白了,封装组件这个套路那绝对是百利而无一害😘。vue
这篇做为2020
年的起始篇,让咱们从头来封装几个组件,了解封装组件的思路,愿广大前端儿都跨过组件封装这个门槛儿,也是为想进大厂体验高逼格工做氛围的童鞋们作好准备🤪。git
万事开头难,好的开头才会顺利的走好每一步。因此,封装以前咱们须要掌握一些前置知识点:web
vue
sass
ElementUI
git
只需熟悉以上4
点咱们即可以踏上封装组件的旅程ajax
ElementUI
做为一款很是优秀的前端UI库,在平时工做中使用的也是较多的,并且,我以为个人审美再牛X
,也想不出来比人家还要好看的样式体验,不管是样式仍是代码上,我都会向它靠拢。很明显,我就是研究人家的源码来学习-😥-只不过我会尽可能把思路捋出来供哪些没思路的小伙伴儿有些帮助,同时也对我本身组件封装相关知识的巩固。对于有不对的地方望大佬们轻喷,多提意见,毕竟都是圈儿里的,说话要搂着点😭vue-cli
大过年的,碎碎叨叨的也差很少了,接下来,进入主题吧--最经常使用的组件莫过于button
了,就用它来做为新年第一道菜,看看怎么样把它一步步炒成美食的。typescript
前边操做我就略过了哈:数组
vue-cli
起个项目,同时配置sass
用来写css
components
目录用来存放封装的组件views
目录用来展现及使用封装的组件theme
目录存放组件样式及公共样式文件router.js
中咱们就正常配置路由便可,用来展现咱们写过的每一个组件附加:
prettier+eslint
来规范代码的书写,香不香谁用谁知道😋sass
components/button/button.vue
在此文件中来封装button
views/button/button-view.vue
此文件用来使用封装过的button
展现在页面上theme/common
中存放公共的样式,包括字体、公共样式变量、及icon
样式theme/components
中存放各个对应的组件样式theme/index.scss
用来导入全部上面的样式文件,便与组件文件访问router/index.js
中配置对应的页面路由{
path: "/button",
name: "button",
component: Button
},
复制代码
在button.vue
中写如一个原生button
按钮,并引入到button-view.vue
文件中
components/button.vue
<template>
<button>按钮</button>
</template>
<script>
export default {
name: "ZButton"
};
</script>
<style lang="scss" scoped></style>
复制代码
views/button/button-view.vue
<template>
<z-button></z-button>
</template>
<script>
import ZButton from "@/components/button/button";
export default {
name: "ZButtonView",
components: {
ZButton
}
};
</script>
复制代码
到此,页面上会出现写的这个原生按钮。先不急,先来简单看下elemetnui
中的源码结构:
example
文件夹存放的是一些示例代码src
文件夹中存放的是一些指令工具方法packages
文件夹中存放的是全部组件的封装源码packages/theme-chalk/src
中存放的是全部样式相关文件types
文件夹存放的是对于typescript
的声明文件了解其文件结构便可,想看源码的同窗能够自行去深刻琢磨。这里并非要作成多么大的一个ui
组件库,目的是实现一些组件的封装,了解其套路。
并且,ui
库之因此为ui
库,就是由于它们的样式很漂亮,咱们在使用时并不须要写过多的样式去重写,大部分状况下直接使用便可。这就证实了ui
库中的样式文件代码是很重要的,并且有必定的规范。 在封装组件以前咱们先来梳理下样式相关的问题:
theme/common/vars.scss
中先定义公共的样式变量theme/common/font.scss
中定义字体相关样式theme/common/icon.scss
中定义图标相关样式由于样式代码太多了,这里就不贴出来了。我所用的都是elementui
中的样式,只不过本身改动了些,没有人家那样规范。毕竟水平有限,css
也是一门很大的学问,想要玩的精我感受仍是要下一番苦功夫的。
button
组件首先,咱们先来看看人家封装的button
组件具备哪些特性:
type
值显示不一样样式的按钮:default
、primary
、info
、warning
、success
、danger
size
值显示不一样尺寸大小的按钮plain
、round
、circle
、disable
、loading
native-type
属性支持原生功能的按钮:button
、reset
、submit
click
事件,并触发父级组件的click
事件,执行对应的业务逻辑ButtonGroup
按钮组下面,咱们开始逐一实现elementUI
中button
的相关功能。
type
显示不一样样式的按钮每套
ui
库使用时都会有一套本身的前缀,例如elementui
中的el
,我这参照人家来作,前缀定义为z
思路:根据传入不一样的type
来显示不一样的样式的按钮,因此这里要把这个样式作成动态的,在vue
中作成动态的可使用对象、数组的方式,而且这些值须要传递进来,涉及到父子组件传值的一些操做。
实现:
components/button.vue
<template>
<button
class="z-button"
:class="[ // 动态绑定class `z-button-- + ${type}`, // 重点在这里,type是父组件传递过来的 ]"
>
<span> // 该slot插槽用来显示传入的文本内容,以及后面要实现的右侧字体图标
<slot></slot>
</span>
</button>
</template>
<script>
export default {
name: "ZButton",
props: {
type: { // 这里接受父组件传递过来的type属性,用来拼接动态class,生成不一样样式的按钮
type: String,
default: "default"
}
}
};
</script>
<style lang="scss" scoped>
@import "../../theme/components/button.scss"; // 组件样式在这里写的,因为代码过多,就不展现了
</style>
复制代码
其中还包括按钮的
hover
、active
等效果的样式代码
views/button/button-view.vue
<template>
<div class="z-button-container">
<div class="z-button-wrap">
<div class="z-row">
<z-button>不一样样式的按钮</z-button>
<z-button type="primary">主要按钮</z-button>
<z-button type="success">成功按钮</z-button>
<z-button type="info">信息按钮</z-button>
<z-button type="warning">警告按钮</z-button>
<z-button type="danger">危险按钮</z-button>
</div>
</div>
</div>
</template>
<script>
import ZButton from "@/components/button/button";
export default {
name: "ZButtonView",
components: {
ZButton
}
};
</script>
<style lang="scss" scoped>
// 这里的css代码只是为了布局展现美观一些,跟封装组件的样式没啥关系
.z-button-wrap .z-row {
margin-bottom: 20px;
}
.z-button-wrap .z-button + .z-button {
margin-left: 10px;
}
.z-button-wrap .z-button-group + .z-button-group {
margin-left: 10px;
}
.z-button-wrap .z-button-group .z-button {
margin-left: 0;
}
.z-button-wrap .z-button-group {
margin-bottom: 10px;
}
</style>
复制代码
此时,在页面上会看到根据传入的不一样的type
,会展现不一样样式的按钮了
size
值显示不一样尺寸大小的按钮思路:其实和上面定义不一样样式的路子是同样的,只不过此次是根据传入的size
改变尺寸而已。咱们能够把传入的size
做为计算属性来实现绑定不一样的样式,同时能够要求开发人员在使用的时候只能传入medium
、small
、mini
这几个值,若是传入别的值进行报错用来提示开发人员 实现:
components/button.vue
<template>
<button
class="z-button"
:class="[ // 动态绑定class `z-button-- + ${type}`, // 重点在这里,type是父组件传递过来的 buttonSizeClass // 使用计算属性 ]"
>
<span> // 该slot插槽用来显示传入的文本内容,以及后面要实现的右侧字体图标
<slot></slot>
</span>
</button>
</template>
<script>
export default {
name: "ZButton",
props: {
type: { // 这里接受父组件传递过来的type属性,用来拼接动态class,生成不一样样式的按钮
type: String,
default: "default"
},
size: { // 父组件传递过来的值,经过validator校验器来规定传入的值的范围
type: String,
validator: value => {
return ["medium", "small", "mini"].indexOf(value) !== -1;
}
}
},
computed: {
buttonSizeClass() { // 该计算属性用来计算class样式
if (this.size) {
return "z-button--" + this.size;
}
return null;
}
},
};
</script>
<style lang="scss" scoped>
@import "../../theme/components/button.scss"; // 组件样式在这里写的,因为代码过多,就不展现了,按钮尺寸相关样式也已添加在此文件中
</style>
复制代码
views/button/button-view.vue
<template>
<div class="z-button-container">
<div class="z-button-wrap">
<div class="z-row">
<z-button>不一样样式的按钮</z-button>
<z-button type="primary">主要按钮</z-button>
<z-button type="success">成功按钮</z-button>
<z-button type="info">信息按钮</z-button>
<z-button type="warning">警告按钮</z-button>
<z-button type="danger">危险按钮</z-button>
</div>
<div class="z-row">
<z-button>不一样尺寸的按钮</z-button>
<z-button type="primary" size="medium">主要按钮</z-button>
<z-button type="success" size="small">成功按钮</z-button>
<z-button type="info" size="mini">信息按钮</z-button>
</div>
</div>
</div>
</template>
<script>
import ZButton from "@/components/button/button";
export default {
name: "ZButtonView",
components: {
ZButton
}
};
</script>
<style lang="scss" scoped>
// 这里的css代码只是为了布局展现美观一些,跟封装组件的样式没啥关系
.z-button-wrap .z-row {
margin-bottom: 20px;
}
.z-button-wrap .z-button + .z-button {
margin-left: 10px;
}
.z-button-wrap .z-button-group + .z-button-group {
margin-left: 10px;
}
.z-button-wrap .z-button-group .z-button {
margin-left: 0;
}
.z-button-wrap .z-button-group {
margin-bottom: 10px;
}
</style>
复制代码
思路:elementUI
中分为朴素、圆角、圆形按钮,能够根据父组件传入的布尔值来判断该按钮组件加入不一样的样式类来实现。 实现:
components/button.vue
<template>
<button
class="z-button"
:class="[ // 动态绑定class `z-button-- + ${type}`, // 重点在这里,type是父组件传递过来的 buttonSizeClass, // 使用计算属性 { // 以对象的形式为按钮添加不一样形状的样式类 'is-plain': plain, 'is-round': round, 'is-circle': circle } ]"
>
<span> // 该slot插槽用来显示传入的文本内容,以及后面要实现的右侧字体图标
<slot></slot>
</span>
</button>
</template>
<script>
export default {
name: "ZButton",
props: {
type: { // 这里接受父组件传递过来的type属性,用来拼接动态class,生成不一样样式的按钮
type: String,
default: "default"
},
size: { // 父组件传递过来的值,经过validator校验器来规定传入的值的范围
type: String,
validator: value => {
return ["medium", "small", "mini"].indexOf(value) !== -1;
}
},
// 如下三个布尔值来做为样式的标志状态,默认为false,为true则添加对应的样式类
// 样式代码已在button.scss中写好
plain: {
type: Boolean,
default: false
},
round: {
type: Boolean,
default: false
},
circle: {
type: Boolean,
default: false
}
},
computed: {
buttonSizeClass() { // 该计算属性用来计算class样式
if (this.size) {
return "z-button--" + this.size;
}
return null;
}
},
};
</script>
<style lang="scss" scoped>
@import "../../theme/components/button.scss"; // 组件样式在这里写的,因为代码过多,就不展现了,按钮尺寸相关样式也已添加在此文件中
</style>
复制代码
views/button/button-view.vue
<template>
<div class="z-button-container">
<div class="z-button-wrap">
<div class="z-row">
<z-button>不一样样式的按钮</z-button>
<z-button type="primary">主要按钮</z-button>
<z-button type="success">成功按钮</z-button>
<z-button type="info">信息按钮</z-button>
<z-button type="warning">警告按钮</z-button>
<z-button type="danger">危险按钮</z-button>
</div>
<div class="z-row">
<z-button>不一样尺寸的按钮</z-button>
<z-button type="primary" size="medium">主要按钮</z-button>
<z-button type="success" size="small">成功按钮</z-button>
<z-button type="info" size="mini">信息按钮</z-button>
</div>
<div class="z-row">
<z-button>不一样形状的按钮</z-button>
<z-button type="primary" plain>主要按钮</z-button>
<z-button type="success" circle>成功按钮</z-button>
<z-button type="info" round>信息按钮</z-button>
</div>
</div>
</div>
</template>
<script>
import ZButton from "@/components/button/button";
export default {
name: "ZButtonView",
components: {
ZButton
}
};
</script>
<style lang="scss" scoped>
// 这里的css代码只是为了布局展现美观一些,跟封装组件的样式没啥关系
.z-button-wrap .z-row {
margin-bottom: 20px;
}
.z-button-wrap .z-button + .z-button {
margin-left: 10px;
}
.z-button-wrap .z-button-group + .z-button-group {
margin-left: 10px;
}
.z-button-wrap .z-button-group .z-button {
margin-left: 0;
}
.z-button-wrap .z-button-group {
margin-bottom: 10px;
}
</style>
复制代码
icon
支持思路:首先把elementui
中的字体文件拷贝到我们本身的src/assets
目录中,在theme/common/font.scss
中引入字体文件进行使用:
theme/common/font.scss
@font-face {
font-family: "element-icons";
src: url(../assets/element-icons.woff) format("woff"),
url(../assets/element-icons.ttf) format("truetype");
font-weight: normal;
font-style: normal;
}
[class*=" z-icon-"],
[class^="z-icon-"] {
font-family: element-icons !important;
speak: none;
font-style: normal;
font-weight: 400;
font-variant: normal;
text-transform: none;
line-height: 1;
vertical-align: baseline;
display: inline-block;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
}
复制代码
在theme/common/icon.scss
中写入全部icon
相关字体,及样式,这里我就简单写下,只包含了edit
和loading
的icon
图标,其实能够把全部的图标都写在这里面:
theme/common/icon.scss
.z-icon-edit:before {
content: "\e78c";
}
.z-icon-loading:before {
content: "\e6cf";
}
@keyframes rotating { // loading效果旋转动画
0% {
transform: rotateZ(0deg);
}
100% {
transform: rotateZ(360deg);
}
}
.z-icon-loading { // loading效果旋转动画
animation: rotating 2s linear infinite;
}
复制代码
接下来,实现icon
的支持
components/button.vue
<template>
<button
class="z-button"
:class="[ // 动态绑定class `z-button-- + ${type}`, // 重点在这里,type是父组件传递过来的 buttonSizeClass, // 使用计算属性 { // 以对象的形式为按钮添加不一样形状的样式类 'is-plain': plain, 'is-round': round, 'is-circle': circle } ]"
>
<i v-if="icon" :class="icon"></i> // icon显示的位置
<span v-if="$slots.default"> // 这里作个判断,只有插槽内有内容才展现,由于有图标按钮,没文字的那种
<slot></slot> // 该slot插槽用来显示传入的文本内容,以及后面要实现的右侧字体图标
</span>
</button>
</template>
<script>
export default {
name: "ZButton",
props: {
type: { // 这里接受父组件传递过来的type属性,用来拼接动态class,生成不一样样式的按钮
type: String,
default: "default"
},
size: { // 父组件传递过来的值,经过validator校验器来规定传入的值的范围
type: String,
validator: value => {
return ["medium", "small", "mini"].indexOf(value) !== -1;
}
},
// 如下三个布尔值来做为样式的标志状态,默认为false,为true则添加对应的样式类
// 样式代码已在button.scss中写好
plain: {
type: Boolean,
default: false
},
round: {
type: Boolean,
default: false
},
circle: {
type: Boolean,
default: false
},
icon: String // 接受父组件传递过来的icon值
},
computed: {
buttonSizeClass() { // 该计算属性用来计算class样式
if (this.size) {
return "z-button--" + this.size;
}
return null;
}
},
};
</script>
<style lang="scss" scoped>
@import "../../theme/components/button.scss"; // 组件样式在这里写的,因为代码过多,就不展现了,按钮尺寸相关样式也已添加在此文件中
</style>
复制代码
views/button/button-view.vue
<template>
<div class="z-button-container">
<div class="z-button-wrap">
<div class="z-row">
<z-button>不一样样式的按钮</z-button>
<z-button type="primary">主要按钮</z-button>
<z-button type="success">成功按钮</z-button>
<z-button type="info">信息按钮</z-button>
<z-button type="warning">警告按钮</z-button>
<z-button type="danger">危险按钮</z-button>
</div>
<div class="z-row">
<z-button>不一样尺寸的按钮</z-button>
<z-button type="primary" size="medium">主要按钮</z-button>
<z-button type="success" size="small">成功按钮</z-button>
<z-button type="info" size="mini">信息按钮</z-button>
</div>
<div class="z-row">
<z-button>不一样形状的按钮</z-button>
<z-button type="primary" plain>主要按钮</z-button>
<z-button type="success" circle>成功按钮</z-button>
<z-button type="info" round>信息按钮</z-button>
</div>
<div class="z-row">
<z-button plain>默认按钮</z-button>
<z-button type="primary" :loading="loading" plain icon="z-icon-edit">
主要按钮
<i class="z-icon-edit z-icon--right"></i> // 子组件的插槽存放右侧字体图标做用体如今这里
</z-button>
</div>
</div>
</div>
</template>
<script>
import ZButton from "@/components/button/button";
export default {
name: "ZButtonView",
components: {
ZButton
}
};
</script>
<style lang="scss" scoped>
// 这里的css代码只是为了布局展现美观一些,跟封装组件的样式没啥关系
.z-button-wrap .z-row {
margin-bottom: 20px;
}
.z-button-wrap .z-button + .z-button {
margin-left: 10px;
}
.z-button-wrap .z-button-group + .z-button-group {
margin-left: 10px;
}
.z-button-wrap .z-button-group .z-button {
margin-left: 0;
}
.z-button-wrap .z-button-group {
margin-bottom: 10px;
}
</style>
复制代码
loading
及disabled
思路:定义好loading
状态的样式,根据传入的布尔值来决定是不是loading
、disabled
状态。而且由于loading
的时候也是不可点击的,即禁用状态,样式不一样,但功能相似。因此咱们能够把这两个属性写在一块儿。还有一点就是字体图标按钮若是显示loading
状态,那么该字体图标就不要显示了。 实现:
components/button.vue
<template>
<button
:disabled="disable || loading" // 用同一个属性实现禁用状态便可
class="z-button"
:class="[ // 动态绑定class `z-button-- + ${type}`, // 重点在这里,type是父组件传递过来的 buttonSizeClass, // 使用计算属性 { // 以对象的形式为按钮添加不一样形状的样式类 'is-plain': plain, 'is-round': round, 'is-circle': circle } ]"
>
<i v-if="!loading && icon" :class="icon"></i> // 这里加入loading判断条件,loading为false图标才显示
<i v-if="loading" class="z-icon-loading"></i> // loading图标,css其实就是让图标进行循环旋转
<span v-if="$slots.default"> // 这里作个判断,只有插槽内有内容才展现,由于有图标按钮,没文字的那种
<slot></slot> // 该slot插槽用来显示传入的文本内容,以及后面要实现的右侧字体图标
</span>
</button>
</template>
<script>
export default {
name: "ZButton",
props: {
type: { // 这里接受父组件传递过来的type属性,用来拼接动态class,生成不一样样式的按钮
type: String,
default: "default"
},
size: { // 父组件传递过来的值,经过validator校验器来规定传入的值的范围
type: String,
validator: value => {
return ["medium", "small", "mini"].indexOf(value) !== -1;
}
},
// 如下三个布尔值来做为样式的标志状态,默认为false,为true则添加对应的样式类
// 样式代码已在button.scss中写好
plain: {
type: Boolean,
default: false
},
round: {
type: Boolean,
default: false
},
circle: {
type: Boolean,
default: false
},
disable: {
type: Boolean,
default: false
},
loading: Boolean
},
computed: {
buttonSizeClass() { // 该计算属性用来计算class样式
if (this.size) {
return "z-button--" + this.size;
}
return null;
}
},
};
</script>
<style lang="scss" scoped>
@import "../../theme/components/button.scss"; // 组件样式在这里写的,因为代码过多,就不展现了,按钮尺寸相关样式也已添加在此文件中
</style>
复制代码
views/button/button-view.vue
<template>
<div class="z-button-container">
<div class="z-button-wrap">
<div class="z-row">
<z-button>不一样样式的按钮</z-button>
<z-button type="primary">主要按钮</z-button>
<z-button type="success">成功按钮</z-button>
<z-button type="info">信息按钮</z-button>
<z-button type="warning">警告按钮</z-button>
<z-button type="danger">危险按钮</z-button>
</div>
<div class="z-row">
<z-button>不一样尺寸的按钮</z-button>
<z-button type="primary" size="medium">主要按钮</z-button>
<z-button type="success" size="small">成功按钮</z-button>
<z-button type="info" size="mini">信息按钮</z-button>
</div>
<div class="z-row">
<z-button>不一样形状的按钮</z-button>
<z-button type="primary" plain>主要按钮</z-button>
<z-button type="success" circle>成功按钮</z-button>
<z-button type="info" round>信息按钮</z-button>
</div>
<div class="z-row">
<z-button>禁用及loading按钮</z-button>
<z-button type="primary" plain disabled>主要按钮</z-button>
<z-button type="success" circle loading>成功按钮</z-button>
</div>
</div>
</div>
</template>
<script>
import ZButton from "@/components/button/button";
export default {
name: "ZButtonView",
components: {
ZButton
}
};
</script>
<style lang="scss" scoped>
// 这里的css代码只是为了布局展现美观一些,跟封装组件的样式没啥关系
.z-button-wrap .z-row {
margin-bottom: 20px;
}
.z-button-wrap .z-button + .z-button {
margin-left: 10px;
}
.z-button-wrap .z-button-group + .z-button-group {
margin-left: 10px;
}
.z-button-wrap .z-button-group .z-button {
margin-left: 0;
}
.z-button-wrap .z-button-group {
margin-bottom: 10px;
}
</style>
复制代码
click
事件思路:给按钮绑定click
事件,都是用来处理对应的业务逻辑,因此要把事件往外传递,在父组件中去处理业务逻辑。 实现:
components/button.vue
<template>
<button
:disabled="disable || loading" // 用同一个属性实现禁用状态便可
class="z-button"
:class="[ // 动态绑定class `z-button-- + ${type}`, // 重点在这里,type是父组件传递过来的 buttonSizeClass, // 使用计算属性 { // 以对象的形式为按钮添加不一样形状的样式类 'is-plain': plain, 'is-round': round, 'is-circle': circle } ]"
@click="handleClick" // 给按钮绑定click事件
>
<i v-if="!loading && icon" :class="icon"></i> // 这里加入loading判断条件,loading为false图标才显示
<i v-if="loading" class="z-icon-loading"></i> // loading图标,css其实就是让图标进行循环旋转
<span v-if="$slots.default"> // 这里作个判断,只有插槽内有内容才展现,由于有图标按钮,没文字的那种
<slot></slot> // 该slot插槽用来显示传入的文本内容,以及后面要实现的右侧字体图标
</span>
</button>
</template>
<script>
export default {
name: "ZButton",
props: {
type: { // 这里接受父组件传递过来的type属性,用来拼接动态class,生成不一样样式的按钮
type: String,
default: "default"
},
size: { // 父组件传递过来的值,经过validator校验器来规定传入的值的范围
type: String,
validator: value => {
return ["medium", "small", "mini"].indexOf(value) !== -1;
}
},
// 如下三个布尔值来做为样式的标志状态,默认为false,为true则添加对应的样式类
// 样式代码已在button.scss中写好
plain: {
type: Boolean,
default: false
},
round: {
type: Boolean,
default: false
},
circle: {
type: Boolean,
default: false
},
disable: {
type: Boolean,
default: false
},
loading: Boolean
},
computed: {
buttonSizeClass() { // 该计算属性用来计算class样式
if (this.size) {
return "z-button--" + this.size;
}
return null;
}
},
methods: {
handleClick(event) { // 触发父级click事件,去处理对应的业务逻辑
this.$emit("click", event);
}
}
};
</script>
<style lang="scss" scoped>
@import "../../theme/components/button.scss"; // 组件样式在这里写的,因为代码过多,就不展现了,按钮尺寸相关样式也已添加在此文件中
</style>
复制代码
views/button/button-view.vue
<template>
<div class="z-button-container">
<div class="z-button-wrap">
<div class="z-row">
<z-button>不一样样式的按钮</z-button>
<z-button type="primary">主要按钮</z-button>
<z-button type="success">成功按钮</z-button>
<z-button type="info">信息按钮</z-button>
<z-button type="warning">警告按钮</z-button>
<z-button type="danger">危险按钮</z-button>
</div>
<div class="z-row">
<z-button>不一样尺寸的按钮</z-button>
<z-button type="primary" size="medium">主要按钮</z-button>
<z-button type="success" size="small">成功按钮</z-button>
<z-button type="info" size="mini">信息按钮</z-button>
</div>
<div class="z-row">
<z-button>不一样形状的按钮</z-button>
<z-button type="primary" plain>主要按钮</z-button>
<z-button type="success" circle>成功按钮</z-button>
<z-button type="info" round>信息按钮</z-button>
</div>
<div class="z-row">
<z-button>禁用及loading按钮</z-button>
<z-button type="primary" plain disabled>主要按钮</z-button>
<z-button type="success" circle loading>成功按钮</z-button>
</div>
<div class="z-row">
<z-button @click="handleParentClick">带有click事件的按钮</z-button>
<z-button :loading="loading">loading按钮</z-button>
</div>
</div>
</div>
</template>
<script>
import ZButton from "@/components/button/button";
export default {
name: "ZButtonView",
data() {
return {
loading: false
};
},
components: {
ZButton
},
methods: {
handleParentClick() {
// 执行业务逻辑。好比发送ajax请求,开启Loading,请求结束关闭loading
this.loading = true
// 发送请求
setTimeout(()=>{
this.loading = false
},2000)
} // 此时点击按钮会触发loading效果,并在2s后关闭loading
}
};
</script>
<style lang="scss" scoped>
// 这里的css代码只是为了布局展现美观一些,跟封装组件的样式没啥关系
.z-button-wrap .z-row {
margin-bottom: 20px;
}
.z-button-wrap .z-button + .z-button {
margin-left: 10px;
}
.z-button-wrap .z-button-group + .z-button-group {
margin-left: 10px;
}
.z-button-wrap .z-button-group .z-button {
margin-left: 0;
}
.z-button-wrap .z-button-group {
margin-bottom: 10px;
}
</style>
复制代码
思路:动态绑定按钮的type
属性,父组件传值,实现原生方法的功能。 实现:
components/button.vue
<template>
<button
:type="nativeType" // 动态绑定type属性
:disabled="disable || loading" // 用同一个属性实现禁用状态便可
class="z-button"
:class="[ // 动态绑定class `z-button-- + ${type}`, // 重点在这里,type是父组件传递过来的 buttonSizeClass, // 使用计算属性 { // 以对象的形式为按钮添加不一样形状的样式类 'is-plain': plain, 'is-round': round, 'is-circle': circle } ]"
@click="handleClick" // 给按钮绑定click事件
>
<i v-if="!loading && icon" :class="icon"></i> // 这里加入loading判断条件,loading为false图标才显示
<i v-if="loading" class="z-icon-loading"></i> // loading图标,css其实就是让图标进行循环旋转
<span v-if="$slots.default"> // 这里作个判断,只有插槽内有内容才展现,由于有图标按钮,没文字的那种
<slot></slot> // 该slot插槽用来显示传入的文本内容,以及后面要实现的右侧字体图标
</span>
</button>
</template>
<script>
export default {
name: "ZButton",
props: {
type: { // 这里接受父组件传递过来的type属性,用来拼接动态class,生成不一样样式的按钮
type: String,
default: "default"
},
size: { // 父组件传递过来的值,经过validator校验器来规定传入的值的范围
type: String,
validator: value => {
return ["medium", "small", "mini"].indexOf(value) !== -1;
}
},
// 如下三个布尔值来做为样式的标志状态,默认为false,为true则添加对应的样式类
// 样式代码已在button.scss中写好
plain: {
type: Boolean,
default: false
},
round: {
type: Boolean,
default: false
},
circle: {
type: Boolean,
default: false
},
disable: {
type: Boolean,
default: false
},
loading: Boolean,
nativeType: { // 获取父组件传递过来的type值,并用validator校验让使用者只能选择一下三种之一
type: String,
default: "button",
validator: value => {
return ["button", "reset", "submit"].indexOf(value) !== -1;
}
},
},
computed: {
buttonSizeClass() { // 该计算属性用来计算class样式
if (this.size) {
return "z-button--" + this.size;
}
return null;
}
},
methods: {
handleClick(event) { // 触发父级click事件,去处理对应的业务逻辑
this.$emit("click", event);
}
}
};
</script>
<style lang="scss" scoped>
@import "../../theme/components/button.scss"; // 组件样式在这里写的,因为代码过多,就不展现了,按钮尺寸相关样式也已添加在此文件中
</style>
复制代码
views/button/button-view.vue
<template>
<div class="z-button-container">
<div class="z-button-wrap">
<div class="z-row">
<z-button>不一样样式的按钮</z-button>
<z-button type="primary">主要按钮</z-button>
<z-button type="success">成功按钮</z-button>
<z-button type="info">信息按钮</z-button>
<z-button type="warning">警告按钮</z-button>
<z-button type="danger">危险按钮</z-button>
</div>
<div class="z-row">
<z-button>不一样尺寸的按钮</z-button>
<z-button type="primary" size="medium">主要按钮</z-button>
<z-button type="success" size="small">成功按钮</z-button>
<z-button type="info" size="mini">信息按钮</z-button>
</div>
<div class="z-row">
<z-button>不一样形状的按钮</z-button>
<z-button type="primary" plain>主要按钮</z-button>
<z-button type="success" circle>成功按钮</z-button>
<z-button type="info" round>信息按钮</z-button>
</div>
<div class="z-row">
<z-button>禁用及loading按钮</z-button>
<z-button type="primary" plain disabled>主要按钮</z-button>
<z-button type="success" circle loading>成功按钮</z-button>
</div>
<div class="z-row">
<z-button @click="handleParentClick">带有click事件的按钮</z-button>
<z-button :loading="loading">loading按钮</z-button>
</div>
<div class="z-row">
<z-button autofocus>支持原生事件按钮</z-button>
<z-button native-type="submit">提交按钮</z-button>
<z-button native-type="reset" type="primary">重置按钮</z-button>
</div>
</div>
</div>
</template>
<script>
import ZButton from "@/components/button/button";
export default {
name: "ZButtonView",
data() {
return {
loading: false
};
},
components: {
ZButton
},
methods: {
handleParentClick() {
// 执行业务逻辑。好比发送ajax请求,开启Loading,请求结束关闭loading
this.loading = true
// 发送请求
setTimeout(()=>{
this.loading = false
},2000)
} // 此时点击按钮会触发loading效果,并在2s后关闭loading
}
};
</script>
<style lang="scss" scoped>
// 这里的css代码只是为了布局展现美观一些,跟封装组件的样式没啥关系
.z-button-wrap .z-row {
margin-bottom: 20px;
}
.z-button-wrap .z-button + .z-button {
margin-left: 10px;
}
.z-button-wrap .z-button-group + .z-button-group {
margin-left: 10px;
}
.z-button-wrap .z-button-group .z-button {
margin-left: 0;
}
.z-button-wrap .z-button-group {
margin-bottom: 10px;
}
</style>
复制代码
思路:按钮组的功能实际上就是在外层作曾包裹,把按钮组件放入其中,难点在于css
的样式控制,两端的按钮有圆角,中间若是有多个按钮都没有圆角,用css
的选择器想好逻辑作对应的处理便可。 实现: 这里新建一个文件: /components/button-group.vue
/components/button-group.vue
<template>
<div class="z-button-group">
<slot></slot>
</div>
</template>
<script>
export default {
name: "ZButtonGroup"
};
</script>
<style lang="scss" scoped>
@import "../../theme/components/button-group.scss";
</style>
复制代码
button-group
的样式并不算多,我先展现在这里,这里须要和button
的样式结合。
.z-button-group {
display: inline-block;
.z-button + .z-button {
margin-left: 0;
}
.z-button:first-child:not(:last-child) {
border-top-right-radius: 0;
border-bottom-right-radius: 0;
}
.z-button:last-child:not(:first-child) {
border-top-left-radius: 0;
border-bottom-left-radius: 0;
}
.z-button:not(:first-child):not(:last-child) {
border-top-left-radius: 0;
border-top-right-radius: 0;
border-bottom-left-radius: 0;
border-bottom-right-radius: 0;
}
.z-button--primary:last-child:not(:first-child) {
border-left-color: rgba(255, 255, 255, 0.5);
}
.z-button--primary:not(:last-child):not(:first-child) {
border-left-color: rgba(255, 255, 255, 0.5);
}
.z-button--success:last-child:not(:first-child) {
border-left-color: rgba(255, 255, 255, 0.5);
}
.z-button--success:not(:last-child):not(:first-child) {
border-left-color: rgba(255, 255, 255, 0.5);
}
.z-button--info:last-child:not(:first-child) {
border-left-color: rgba(255, 255, 255, 0.5);
}
.z-button--info:not(:last-child):not(:first-child) {
border-left-color: rgba(255, 255, 255, 0.5);
}
.z-button--warning:last-child:not(:first-child) {
border-left-color: rgba(255, 255, 255, 0.5);
}
.z-button--warning:not(:last-child):not(:first-child) {
border-left-color: rgba(255, 255, 255, 0.5);
}
.z-button--danger:last-child:not(:first-child) {
border-left-color: rgba(255, 255, 255, 0.5);
}
.z-button--danger:not(:last-child):not(:first-child) {
border-left-color: rgba(255, 255, 255, 0.5);
}
}
复制代码
views/button/button-view.vue
<template>
<div class="z-button-container">
<div class="z-button-wrap">
<div class="z-row">
<z-button>不一样样式的按钮</z-button>
<z-button type="primary">主要按钮</z-button>
<z-button type="success">成功按钮</z-button>
<z-button type="info">信息按钮</z-button>
<z-button type="warning">警告按钮</z-button>
<z-button type="danger">危险按钮</z-button>
</div>
<div class="z-row">
<z-button>不一样尺寸的按钮</z-button>
<z-button type="primary" size="medium">主要按钮</z-button>
<z-button type="success" size="small">成功按钮</z-button>
<z-button type="info" size="mini">信息按钮</z-button>
</div>
<div class="z-row">
<z-button>不一样形状的按钮</z-button>
<z-button type="primary" plain>主要按钮</z-button>
<z-button type="success" circle>成功按钮</z-button>
<z-button type="info" round>信息按钮</z-button>
</div>
<div class="z-row">
<z-button>禁用及loading按钮</z-button>
<z-button type="primary" plain disabled>主要按钮</z-button>
<z-button type="success" circle loading>成功按钮</z-button>
</div>
<div class="z-row">
<z-button @click="handleParentClick">带有click事件的按钮</z-button>
<z-button :loading="loading">loading按钮</z-button>
</div>
<div class="z-row">
<z-button autofocus>支持原生事件按钮</z-button>
<z-button native-type="submit">提交按钮</z-button>
<z-button native-type="reset" type="primary">重置按钮</z-button>
</div>
<div class="z-row">
<z-button-group>
<z-button type="warning" plain>按钮组</z-button>
<z-button type="warning" plain>上一页</z-button>
<z-button type="warning" plain>下一页</z-button>
<z-button type="warning" plain>下一页</z-button>
</z-button-group>
<z-button-group>
<z-button type="success" circle></z-button>
<z-button type="success" circle></z-button>
<z-button type="success" circle></z-button>
</z-button-group>
</div>
</div>
</div>
</template>
<script>
import ZButton from "@/components/button/button";
import ZButtonGroup from "@/components/button-group/button-group"; // 引入buttongroup
export default {
name: "ZButtonView",
data() {
return {
loading: false
};
},
components: {
ZButton,
ZButtonGroup
},
methods: {
handleParentClick() {
// 执行业务逻辑。好比发送ajax请求,开启Loading,请求结束关闭loading
this.loading = true
// 发送请求
setTimeout(()=>{
this.loading = false
},2000)
} // 此时点击按钮会触发loading效果,并在2s后关闭loading
}
};
</script>
<style lang="scss" scoped>
// 这里的css代码只是为了布局展现美观一些,跟封装组件的样式没啥关系
.z-button-wrap .z-row {
margin-bottom: 20px;
}
.z-button-wrap .z-button + .z-button {
margin-left: 10px;
}
.z-button-wrap .z-button-group + .z-button-group {
margin-left: 10px;
}
.z-button-wrap .z-button-group .z-button {
margin-left: 0;
}
.z-button-wrap .z-button-group {
margin-bottom: 10px;
}
</style>
复制代码
经过以上的代码,button
组件的封装差很少都封装完毕了,后续整理一下再把这部分总体的代码贴出来,代码中主要的地方我加上了注释,但愿对某些童鞋们能有个总体思路的了解。
今天也是年前在公司的最后一天了,这一年过得也是晕晕乎乎,好的一点是年会得了个二等奖,虽然不是啥贵重东西,起码也预示着新的一年会有个好运吧😜。接下来就是回家过年了😱,没女票都不知道该咋汇报,诶。年后有时间再继续搞一波别的组件,这东西挺费神的,归根结底自身能力仍是有很大欠缺,还需继续努力。
2020
新的愿望: 争取找到另外一半儿,技术方面再升点段位🙃,也就这点追求了。