本文是 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"; 这个引用中找到。