Button组件

饿了么的Element组件库,我打算的是一个一个的尽量分析吧,因为只是分析,架构上可能会不太一样。官方的架构方法可以看这篇文章

首先,我不会使用lerna,来管理多个独立的项目。只会类似于平时开发常用组件一样,把一个组件放在一个文件夹里面,这个组件需要的 scss, images 啊什么的,都放在一起。

其次,应该不会使用postcss-salad,我会翻译成相同功能的scss吧。分析的主要目的还是学习,所以怎么方便怎么来,只是看它实现的思路,不用太过于在意细节。


Button组件的分析,可以了解一些新的东西
1. 对于SCSS中mixin的使用,以及工具方法mix()
2. 对于loading字体图标的动画,animation, 无限次上下翻转
3. line-height设置没有单位的数值,会怎样计算行高
4. 对slot的使用,怎么利用$slots.default等
5. pointer-events的作用
6. 接口的设计思想,为什么字体图标和loading要分开写


var.scss

首先声明一些常用的css属性值,归纳下有以下几类:
colors:
设定常见的颜色

未标题-2.jpg

border:

/* Border--------------------------*/
$--border-width-base: 1px;
$--border-style-base: solid;
$--border-color-base: $--color-grey;
$--border-base: $--border-width-base $--border-style-base $--border-color-base;
$--border-radius-base: 4px;

剩下的就是不同类型的按钮的color, fill, border颜色值了。

$--button-hover-tint-percent: 20%;
$--button-active-shade-percent: 10%;

这两个值会在hover, focus等状态时,设置颜色使用。

Button.vue

首先看下Button组件的模板template

<template>
  <button :disabled="disabled" class="el-button"
          @click="handleClick"
          :autofocus="autofocus"
          :type="nativeType"
          :class="[
            type ? 'el-button-' + type : '',
            size ? 'el-button-' + size : '',
            {
              'is-disabled': disabled,
              'is-loading': loading,
              'is-plain': plain
            }
          ]"
  >
    <i class="el-icon-loading" v-if="loading"></i>
    <i :class="'el-icon-' + icon" v-if="icon && !loading"></i>
    <span v-if="$slots.default"><slot></slot></span>
  </button>
</template>

通用的css样式

/* common
  ------------------------*/
  display: inline-block;
  line-height: 1;
  margin: 0;
  border: $--border-base;
  box-sizing: border-box;
  text-align: center;
  color: $--button-default-color;
  background: $--button-default-fill;
  cursor: pointer;
  white-space: nowrap;
  -webkit-appearance: none;  //消除浏览器默认样式
  outline: none;

  & + .el-button {
    margin-left: 10px;
  }

好了,下面就来进入正题,Button组件的几个设计要点

1. button的尺寸大小

和Bootstrap一样,实现方法其实都是不同的尺寸大小,有不同的类名,设定不同的尺寸。对于Bootstrap,你可能需要显示的把类名写完整,而对于Vue组件,给props传入值就好了,会动态的生成不同的类名,相比更简单点。

<el-button size="large">默认按钮</el-button>

// 生成的
<button class="el-button el-button-large"><span>默认按钮</span></button>

我们仔细看button的公共样式,并没有设置宽高,对于大小有关的,就是line-height了,至于为什么是设置为 1,可以看这篇

一句话总结就是,当line-height设没有单位的值的时候,就根据button的font-size,来计算高度,font-size有多大,button的行高就有多高。

接下来,button就给不同的大小,设定不同的上下左右padding。这里就有一个需要注意的了,我们需要重复写很多相同的css吗,每个尺寸的类名下面都重新写一次padding, font-size, 当然不是!!!既然都用SCSS了,为什么不用mixin呢???

所以,写一个font-size的mixin:

@mixin button-size($padding-vertical, $padding-horizontal, $font-size, $border-radius) {
  padding: $padding-vertical $padding-horizontal;
  font-size: $font-size;
  border-radius: $border-radius;
}

但是,后面我就犯傻了,还是scss用的不熟练的原因,我想,既然large, small, mini都是差不多的,只是改变一点不同的地方,为什么不用循环呢???但是尝试了过后发现,好像并不可以,在循环的时候,通过循环的变量,动态改变css选择器可以,动态改变属性值也是可以的,但是对于已经定义好的变量,不能这样拼接。。。

  &-large {
    @include button-size($--button-large-padding-vertical, $--button-large-padding-horizontal, $--button-large-font-size, $--button-border-radius)
  }

// 也就是本来变量是 $--button-large-font-size
// 不能通过 $--button-#{type}-font-size来进行拼接,
// 识别不出来

2. button类型(颜色倾向)

同样,还是写一个mixin, 不过这里面有一个就是,在设置hover, focus状态的样式时,通过mix()函数来混合颜色,这个以前倒是没有用过。

@mixin button-variant($color, $background-color, $border-color) {
  color: $color;
  background-color: $background-color;
  border-color: $border-color;

  &:hover,
  &:focus {
    background: mix(#fff, $background-color, $--button-hover-tint-percent);
    border-color: mix(#fff, $border-color, $--button-hover-tint-percent);
    color: $color;
  }

  &:active {
    background: mix(#000, $background-color, $--button-active-shade-percent);
    border-color: mix(#000, $border-color, $--button-active-shade-percent);
    color: $color;
    outline: none;
  }

.............
}

3. 图标按钮和loading状态

这里面涉及了一个设计的问题,开始的时候我在考虑,为什么要加一个loading的prop呢?直接通过设置icon为loading也可以啊。

但是,想一下,在实际的应用中的使用场景,常常时点击后,ajax请求数据,完成后结束loading状态,所以,试想,到底是在这期间改变icon的值好呢,还是直接通过一个computed属性,动态设置loading的boolean值好呢???对吧,虽然只是很小的细节,但对于后面的使用来说,易用性完全不一样呐

还有一点,对于loading按钮,设置了css3属性,pointer-events: none,相当于直接去除了onclick点击效果。

4.内容分发slot

<i class="el-icon-loading" v-if="loading"></i>
<i :class="'el-icon-' + icon" v-if="icon && !loading"></i>
<span v-if="$slots.default"><slot></slot></span>

注意模板中的内容分发这句,其实写的非常的漂亮!!!
想一想,我们要实现一个按钮组件,是不是需要一个slot来放外部环境传入的按钮文字。

接着,我们要实现图标按钮,图标和按钮文字之间肯定要隔一段距离啊,但是slot,css选择器没办法查找到啊,没办法,加个span标签包裹slot吧

 /* 图标按钮
  -----------------------*/
  & [class*='el-icon-'] {
    & + span {
      margin-left: 5px;
    }
  }

看着好像差不多了,但是,如果图标按钮只有图标没有文字呢???图标按钮i后面接着的span标签还是会产生5px距离啊,button莫名就给撑开了。

所以啊,v-if 判断的用处就来了,通过判断$slots.default来判断有没有传入按钮文字,有,才添加span节点。。。。

6啊,对内容分发的理解又加深了很多啊!!!!

5.按钮组
其实,按钮组已经是一个新的组件了,相当于是组件之间的嵌套。

对于button-group组件中的button子组件,左浮动,清除圆角,再首尾按钮添加圆角。

对于button边框的间隔,首节点设置右边框,尾节点设置左边框,中间的margin-right: -1px, 就实现了按钮组中按钮间的1px白色边框间隔了。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,293评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,604评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,958评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,729评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,719评论 5 366
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,630评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,000评论 3 397
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,665评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,909评论 1 299
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,646评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,726评论 1 330
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,400评论 4 321
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,986评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,959评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,197评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 44,996评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,481评论 2 342

推荐阅读更多精彩内容