本文是 Element 的组件源码学习系列。
项目源码:ElemeFE/element | GitHub,Tag:v2.13.0
Tag 组件使用文档:Tag 标签
.vue 文件:/packages/tag
.scss 文件:/packages/theme-chalk/tag.scss
.d.ts 文件:/types/tag.d.ts
el-tag
是基于 span
封装的标签组件。因为 Tag 的使用形式,大多为一排多个 Tag 进行选择,所以并没有基于 div
进行封装
Props
首先我们来看一下 el-tag
的 Props,了解使用这个组建的入参:
1 | props: { |
closable
设置 closable
属性可以定义一个标签是否可移除。在显示效果上来说,设置了 closable
的 el-tag
,标签内部靠后,有一个小 x
,点击即可触发 close
事件。
我们开看一下相关的实现方案:
1 | render(h) { |
由于 el-tag
标签的内部,会接收文字或者一些 HTML 子元素,所以 span
标签的第一个子元素,就是先补充 this.$slots.default
。
当设置了 this.cloable
的时候,会在 span
内部追加一个 i
标签,用来显示小小的删除按钮,同时点击删除按钮的时候,会调用 this.handleClose
方法:
1 | handleClose(event) { |
这里有一个细节大家需要注意一下,我们点击 i
标签的时候,触发的事件是 click
事件,但是 el-tag
对外提供的是 close
事件,所以我们要把 click
事件转换成 close
事件。并且为了防止子元素的 click
事件冒泡出去,还需要调用 event.stopPropagation();
。
同样,el-tag
也提供了 click
事件,直接使用的是 span
标签的 click
事件。逻辑非常简单,感觉这样的设计挺冗余的:
1 | handleClick(event) { |
由上,我们可以总结出一些写高级组件的事件处理的一些套路:
- 高级组件的事件,都是需要主动
emit
出来的,所以我们对于每一个要提供的事件,都需要有对应的handler
函数,虽然这个函数的逻辑可能非常简单 - 所有对外提供的事件,因为事件的冒泡特性,都要考虑一下是不是会互相影响。
type & hit
将这两个属性放在一起介绍,主要是因为这两个属性,都是直接操作 CSS class 来影响样式的,没有太多的逻辑耦合。
1 | const classes = [ |
相关的 CSS 代码为:
1 | @mixin genTheme($backgroundColorWeight, $borderColorWeight, $fontColorWeight, $hoverColorWeight) { |
通过 CSS 相关的代码,我们可以知道:
- 设置了
type
之后,改变了对应的background-color
,border-color
和color
hit
属性决定是否有边框描边,当然改变的是border-color
- 当设置为 Tag 可以删除时,会在
span
中新增一个i
标签来显示删除按钮,对应的 CSS 类名都为el-tag__close
,相关的样式也可以在这里找到。
size & effect
1 | computed: { |
size
和 type
的变化,同样也反应到 span
标签的 CSS 类上,来触发大小的改变,以及主题的变换。
我们来看一下相关的 SCSS 实现:
1 | @include b(tag) { |
在这段 SCSS 里面,基础的 CSS 语法,比如设置 border
,设置 height
之类的,我们都能够看懂。问题是,这段 SCSS 是如何确认当前的主题是 light
还是 dark
,当前的大小是 medium
还是 small
呢?
答案都在 m
这个函数上。
Element 在对 CSS 类进行命名的时候,使用的是 BEM 命名法。具体什么是 BEM 命名法,大家可以去自行搜一下,我们这里主要看 BEM 命名法如何在 el-tag
中应用的:
当设置主题 effect
为 dark
,设置大小 size
为 small
的时候
1 | const classes = [ |
el-tag
对应的 span
标签会被加上两个 CSS 类名:el-tag--small
和 el-tag--dark
。在 BEM 命名法中,B 代表的 block 为 tag
,M 代表的 module 为 small
和 dark
。
这里的 b
函数和 m
函数,就代表着匹配 block,以及匹配 module 的能力。当 span
标签的 block 为 tag
, module 为 small
和 dark
的时候,就会运行对应的 CSS 代码。
module 为 dark
的 HTML 元素,会被应用定义好的 genTheme
函数,传递对应的颜色设置: genTheme(100%, 100%, 0, 80%);
module 为 small
的 HTML 元素,会被设置 CSS 样式 height: 24px; padding: 0 8px;
等。
1 | @include b(tag) { |
b
函数的定义和 m
函数的实现方法,都可以在 tag.scss
文件的最上面:@import "mixins/mixins";
这个引用中找到。