前言
在Vue
的世界中已经充满了各种各样的UI库了,尤其出名的有ElementUI、Iview、MuseUI等,这几个也是我们日常业务开发中经常使用的UI库。只使用UI库的工程师被调侃为api调用师
,这算是一种工程师之间的鄙视了,这种鄙视迟早要还回去的。
最近在家比较闲,尝试着以成熟UI库的视角来感受下其的开发过程,看了这些优秀的代码,真的觉得自己的代码有点屎味
了!不多说了,让我们开始打造自己的UI库吧,首先看下按钮是怎么开发出来的。
按钮的使用
在正式开发按钮之前,我们先看下按钮是如何使用的,以及有哪些主要属性或者功能。这对接下来的api定义是很有用处的,意义重大。
按钮的主要属性有这么几点:
- 是否圆角
- 是否有边框
- 是否可点击(disabled)
- 颜色
- 大小
- ...
其实还有更多的属性,这里我们不赘述了,知道了某些属性的开发过程,其他的也只是照葫芦画瓢的;再来看下真实场景中是如何使用的:
<xch-button color="primary" :disabled="true" :noBorder="true" circle size="m">按钮</xch-button>
开发前的目录规划
清晰的目录规划,能为后面的代码带来意想不到的可读性。一个项目随着时间的推移,人员的变动,往往会变得越来越大,越来越难维护。能在前期就规划好一切当然是最好的,但是又有几人能做到呢。看下我们这个按钮组件的目录:
本项目使用的是vue-cli 4.0
脚手架生成的,和以前版本生成的目录大致相同。我们编写的代码基本都在src
目录下,其中components
里放的是我们的.vue
文件,style
中放的是样式文件,本项目我们采用的是less,和其他几个css预处理器都差不多。更具体的代码逻辑,在下文会依次详细解说。
props 的定义
本文的最低要求是你已经具备了vue的基础知识
。在开发一个组件之前,我们最好的做法是规划好这个组件的能力和相关的属性以及api。特别是api,轻易不要乱改,任何不兼容的修改都是不成熟的标志,对组件的使用者来说也是不负责任的表现,这也是为什么我们总是选择成熟优秀框架的原因,没有人希望隔三差五去修改不兼容的代码。回归正题,我们首先定义下我们需要的props:
props: {
circle: Boolean, // 圆角
noBorder: Boolean, // 边框
disabled: Boolean, // 可点击
color: String, // 颜色
textColor: String, // 文本颜色
size: {
type: String,
validator(value) {
return ["l", "m", "s", "xs"].indexOf(value) != -1;
}
} // 按钮大小
}
先说一下思想:这些传入的props,多数是为了控制某个样式的class是否需要应用,比如,circle
传入的话,就代表着应用class: btn-circle
,size
传入'l'的话,就代表着应用class: btn-l
。其他的属性也都大致一样。
样式的计算属性
上文也讲了,props的传入,其实多数是为了控制某个样式是否应用。我们使用vue的对象语法<div v-bind:class="{ active: isActive }"></div>
来定义一个计算属性buttonCls
控制着样式class这一块。
computed: {
buttonCls() {
return {
[`${prefix}`]: true,
[`${prefix}-circle`]: !!this.circle,
[`${prefix}-no-border`]: this.noBorder === true,
[`${prefix}-${this.color}`]: !!this.color,
[`${prefix}-text-${this.textColor}`]: !!this.textColor,
[`${prefix}-${this.size}`]: !!this.size
};
}
}
整齐划一的代码真好看,其中变量是prefix
是自己定义的前缀,这样能很好的区分其他UI库,ElementUI是以el-
开头,Iview是以i-
开头。这么一操作,立刻高大上起来了。不愧是皇家按钮
, 哈哈。
template
template
部分相对简单些,主要是将props和计算属性应用到button
标签上:
<template>
<button
type="button"
:class="buttonCls"
:disabled="!!this.disabled"
@click="click"
>
<slot></slot>
</button>
</template>
重头戏:样式
写到这里,逻辑部分基本写完了,一共50行不到的代码,虽然没有ElementUI的el-button
的功能齐全,但也算是麻雀虽小五脏俱全吧,有兴趣的同学可以仿照el-button
进一步扩展。下面我们重点学习下怎么规划和书写整洁的less代码(这部分代码真的惊艳到我了,我之前一直不重视css的代码)
在动手写代码之前,我们先梳理下有哪些要点:
- 全局的样式抽离成单独的变量文件,这里就是
var.less
,这个习惯一定要养成,在编写大型的项目或者插件库的时候,面对堆积成山的代码量,会复用代码的人是快乐的
,剩下的就是和稀泥的人,每天痛苦不堪。 - 每个组件都有自己的less文件,这里是
button.less
less
语法是很强大的,平时用的最多的就是嵌套语法和变量模式,其实less
还有很多的强大的功能,比如函数,混合等,都是很值得我们去好好理解和学习的
我们先看下var.less文件,里面我们定义了很多变量,比如,颜色、padding等,不仅是button
组件会用到,以后的其他组件也会用到,先大概看下:
@prefix: xch-;
// 颜色
@primary-color : #45b984;
@blue-color : #3B91FF; //info
@green-color : #13CE66; //success
@yellow-color : #FFAE00; //warn
@red-color : #E11617; //error
@white-color : #fff;
//Dark, Gray 1-4 more
@dark-color: #333333;
@dark1-color: #555555;
@dark2-color: #666666;
@dark3-color: #777777;
@dark4-color: #999999;
@gray-color: #c1c1c1;
@gray1-color: #d3d3d3;
@gray2-color: #eeeeee;
@gray3-color: #f3f3f3;
@gray4-color: #f5f5f5;
// 按钮padding
@button-size-normal-padding: 8px 15px;
@button-size-l-padding: 10px 20px;
@button-size-m-padding: 7px 16px;
@button-size-s-padding: 5px 10px;
@button-size-xs-padding: 2px 6px;
// radius
@border-radius : 4px;
//font-size
@font-size : 14px;
// Animation
@animation-time : .3s;
@transition-time : .2s;
@box-shadow-button: 0 1px 1px 0 @gray2-color;
//disabled
@disabled-cursor: not-allowed;
@disabled-color: @dark4-color;
@disabled-border-color: @gray1-color;
@disabled-background-color: @gray4-color;
button.less
的代码,我使用了注释的方法,尽量详细的解说其中的奥妙
@btn-prefix: ~"@{prefix}btn"; // 定义前缀,这是UI组件库通用的做法
// 定义一个函数,方便控制颜色的切换
// 其中的darken和lighten方法是less自带的,变浅或者变深,甚是好用
.btn-color(@color, @percent: 10%) {
background-color: @color;
border-color: darken(@color, @percent);
color: @white-color;
&:hover{
border-color: lighten(@color, @percent);
background-color: lighten(@color, @percent);
}
&:active {
border-color: darken(@color, @percent);
background-color: darken(@color, @percent);
}
}
.@{btn-prefix} {
border: none;
outline: none;
padding: @button-size-normal-padding;
display: inline-block;
border-radius: @border-radius;
font-size: @font-size;
...
// 颜色切换的精髓
&.@{btn-prefix} {
&-primary{
.btn-color(@primary-color)
}
&-red {
.btn-color(@red-color);
}
...
&-no-border{
box-shadow: none;
border-color: transparent !important;
}
&-circle {
border-radius: 20px;
}
}
// 不可点击时的样式
&[disabled] {
cursor: @disabled-cursor;
background-color: @disabled-background-color;
border-color: @disabled-border-color;
color: @disabled-color;
&:hover {
background-color: @disabled-background-color;
border-color: @disabled-border-color;
color: @disabled-color;
}
}
// 控制按钮大小,其实是控制padding
&.@{btn-prefix}-l {
padding: @button-size-l-padding;
}
&.@{btn-prefix}-m {
padding: @button-size-m-padding;
}
...
}
全局注册和使用
最后就是将本组件注册到全局,这部分代码在入口文件main.js中,比较简单就不累述了;感兴趣的同学可以思考下怎么定义另一个组件button-group
来完成按钮的组合使用。
源码
还有些细枝末叶的代码和具体的按钮效果,这里也没有提到,可以去源码查看更多详细的代码。或者直接下载到本地,跑起来,运行下: git clone https://github.com/xch1029/vue-study.git
。附上一句心里话,自己去实现一些UI库级别的代码真的能提升很多
。