一个任性前端的饿了么组件解析(1)- Button

1,551 阅读6分钟

前言

警告:本文的作者十分任性,不定期更新各种前端文章。所有的对代码的理解都不会使用专业的语言,适合新手阅读。当然也欢迎各路大神指正,至于改不改看心情~(ball ball you 多给点意见吧)。篇目只针对组件进行解析,对于整体的饿了么实现逻辑待我整理过后再看看。好,废话不多说直接进入正题。

阅读所需技能

  • vue相关知识
  • 饿了么ui相关知识
  • scss相关知识

相关文件

1.主文件

button.vue - packages\button\src\button.vue

2.样式主文件

button.scss - packages\theme-chalk\src\button.scss

3.样式依赖文件

var.scss - packages\theme-chalk\src\common\var.scss

_button.scss - packages\theme-chalk\src\mixins_button.scss

mixin.scss - packages\theme-chalk\src\mixins\mixins.scss

utils.scss - packages\theme-chalk\src\mixins\utils.scss

config.scss - packages\theme-chalk\src\mixins\config.scss

文档解析

1.size (决定组件尺寸)

首先,从主文件button.vue上可以知道组件的尺寸由buttonSize决定

而buttonSize定义在计算属性中
由size、_elFormItemSize、另一个size决定。其中this.size定义在props中就是我们在使用时的size值。
而_elFormItemSize而定义在inject中
为祖先组件中定义的,依据名称猜测这边为form组件中定义的size值(待验证)。

而最后一个size值应为整个element定义的size值(待验证)。

三者的值将按顺序取第一个有定义的值作为结果,最终在组件上定义了一个el-button--xx的class,从api上看class可能被定义为el-button--medium,el-button--small,el-button--mini。

知道了class后从样式主文件入手,开始就使用了一个方法

这个b() 定义在mixins.scss中
可以知道最终定义了一个$B的class,而$B定义为$namespace加上传入的值。

$namespace在config.scss中定义

所以最终生成了我们在button组件都能看到的el-button。
其中许多值定义在var.scss中,自行查看。

接下来我们继续查看到

这边有三个函数调用,并且传入medium、small、mini,推测class定义在这。这个m()定义在mixins.scss里面。
&代表的是父选择器,在这边是包括在上面的选择器中也就是el-button,接下来循环了传入的参数并且拼接出了新的选择器,$modifier-separator定义在config.scss中
所以综上最后$currentSelector的值为el-button--xx,在事例中为el-button--medium,由于前面跟上了@at-root,所以此选择器是定义在根节点中的,并不是嵌套的形式。

接着我们看看里面的定义。首先,调用了button-size()用了此方法定义在_button.scss中

非常简单,这个方法将传入的四个参数分别设置了的padding、font-size、border-radius以及在加上了另一个子选择器is-round并对应设置其padding,这边应该是用于圆角按钮的实现,跳过。至此一个el-button--medium选择器设置完毕。如图。

2.type(决定组件类型)

主文件button.scss上可以发现组件的类型就是由传入的type决定的

若不传入则默认值为default
故这边给组件添加了一个可能为el-button--default、el-button--primary、el-button--success 、el-button--warning 、el-button--danger 、el-button--info 、el-button--text的class。

从button.scss中找到

首先m()为在根节点定义el-button--primary的class,其中button-variant()定义在_button.scss中传入的三个参数均在var.scss中定义的常量。
看下来是正常的设置几个样式以及各种状态的样式,其中的常量基本都在var.scss中定义,值得提的几个点,mix()是scss中的方法用于按照百分比混合颜色,后面三个css分别为 .el-button--primary .is-active、.el-button--primary .is-disabled、.el-button--primary .is-plain为其他api下按钮的表现,这边先跳过。

至此简单的primary、success、warning、danger、info设置的css就是这样。

说个比较奇怪的text类型,其设置是直接在外部直接定义,与其他的不同,不过具体的设置也都差不多,这边大概是因为其他的api无法影响种类为text的按钮。

3.plain(决定组件是否为朴素按钮)

主文件button.scss上可以发现朴素由传入plain决定的

通过传入的plain值,确定是否在组件上添加is-plain的class
接着从主样式button.scss中可以看到
这个when()定义在mixins.scss中
此方法在根节点定义由父节点,$state-prefix(定义在config.scss)和传入的值组成的css
在示例中最终为.el-button .is-plain,再根据常量(var.scss中)设置各种样式,最后如图。
这就是默认的朴素按钮,若按钮的种类为其他时朴素按钮的样式就是上文中所定义的。

_button.scss的button-variant()中

在示例中此为.el-button--primary .is-plain。再看这个button-plain()定义在本文件中
这边也是通过传入的值与各常量设置样式,要提一句的是这边还有一个is-disabled组成 .el-button--primary .is-plain .isdisabled猜测与禁用有关。通过以上的设置,不同种类的按钮都设置了不同的样式,如下图。

4.round(决定组件是否为圆角按钮)

这个round的实现与plain基本一致,唯一的区别可能是round与size挂钩所以按着之前的size路线查就可以看到相关信息。

button.vue

button.scss
_button.scss

5.circle(决定组件是否为圆型按钮)

circle比round的还要简单,基本一致。也是关联size。

button.vue

button.scss

6.loading(决定组件是否为加载中状态)

首先loading也是由传入的值决定是否在组件上加上is-loading的class

此外这里还有一个添加loading图标的操作
在button.scss中
有个这样的css,按照之前的逻辑这里面的样式将归在.el-button.is-loading下,最终表现如下图。

7.disabled(决定组件是否为禁用状态)

disabled比较复杂,先看class

是否添加is-disabled由buttonDisabled决elForm定,而其定义在计算属性中
由传入的disabled值与祖先传过来的elForm中的disabled属性决定
此外button标签自带的disabled的属性由buttonDisabled与api中的loading决定
在button.scss中找到disabled相关
根据之前的when()该方法创建了一个.el-button.is-disabled的选择器,并且将下面的样式赋值进去最后结果为
而下面是在朴素按钮与文字按钮下禁用时的css最后生成为
由于禁用的样式与按钮种类有关联,故按着之前的type的路线走的话就能发现
_button.scss中
最终表现为
值得注意的是在下面的朴素按钮样式中
说明禁用的样式与朴素按钮有关,最后表现为

8.icon(决定组件的图标)

这边非常简单就是将传入的值赋值到其中i标签的class上,不过要注意,当loading为true的时候i标签不出现。之后再通过引入的字体文件映射最终形成图标

值得注意的是在button.scss中
这边有一个小的样式用于图标与文字的分离。

9.autofocus(决定组件是否聚焦),native-type(原生 type 属性)

这两个都是button上原生的属性值,都是通过传入的对应值直接进行赋值。

结语

这边就是所有button在官方文档上面的用法,与其他的组件的联动也是有很多,建议大家多看看源码,对自己的提升还是蛮大的。至于其他组件的解析那就再说了,各位,后会有期。