5

一天一个 Element 组件 - Link

 2 years ago
source link: https://shiningdan.github.io/2020/01/09/%E4%B8%80%E5%A4%A9%E4%B8%80%E4%B8%AA-Element-%E7%BB%84%E4%BB%B6-Link/
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client

一天一个 Element 组件 - Link

发表于 2020-01-09

| 分类于 coding

|

| 阅读次数

本文是 Element 的组件源码学习系列。

项目源码:ElemeFE/element | GitHub,Tag:v2.13.0

Link 组件使用文档:Link 文字链接

.vue 文件:/packages/link

.scss 文件:[/packages/theme-chalk/link.scss](https://github.com/ElemeFE/element/blob/dev/packages/theme-chalk/src/link.scss

.d.ts 文件:/types/link.d.ts

el-link 的实现方案,基于原生 <a> 元素

Props

首先我们来看一下 el-link 的 Props,了解使用这个组建的入参:

props: {
type: {
type: String,
default: 'default'
},
underline: {
type: Boolean,
default: true
},
disabled: Boolean,
href: String,
icon: String
}

type 字段是用来控制 el-link 组件的样式(主要是颜色),并不影响行为,我们来看一下实现方案:

首先,用户传入 type 属性,type 只会被自动注入到 a 标签的样式类中:

<a
:class="[
'el-link',
type ? `el-link--${type}` : '',
]"
>

如果设置了 typesuccess,则 a 标签会自动添加 el-link--success 的样式类。

我们来看一下 el-link--success 这个样式类做了什么,打开 scss 文件,/packages/theme-chalk/link.scss

定位到这一段相关的代码:

@import "common/var";

$typeMap: (
primary: $--link-primary-font-color,
danger: $--link-danger-font-color,
success: $--link-success-font-color,
warning: $--link-warning-font-color,
info: $--link-info-font-color);

@each $type, $primaryColor in $typeMap {
&.el-link--#{$type} {
color: $primaryColor;
&:hover {
color: mix($primaryColor, $--color-white, 80%)
}
&:after {
border-color: $primaryColor
}
@include when(disabled) {
color: mix($primaryColor, $--color-white, 50%)
}
@include when(underline) {
&:hover:after {
border-color: $primaryColor
}
}
}
}

首先,引入 scss 全局颜色变量,然后定义 el-link 标签使用的 $typeMap 变量,将 type 和 颜色变量映射起来。

其次,遍历映射表 $typeMap,创建 el-link--#{$type} 样式类。比如当 typesuccess 的时候,就映射到 el-link--success 样式类了。

我们可以通过样式类的定义,大致看到 element 具体做了哪些样式的修改,比如

  1. 设置了 el-link 标签内的文字颜色 color
  2. 设置鼠标 hover 上去后,文字颜色会有 80% 的透明度
  3. 设置了 disable 属性后,50% 的透明度
  4. 设置了 underline 属性后,hover :after 伪元素也要设置边框颜色

所以当 <a> 标签设置了 el-link--success 这个样式类的时候,会应用到 scss 中 typesuccess的样式。

disable

同理,disable 属性设置后,对应也是修改的 <a> 标签的样式类,以及 href 属性:

<a
:class="[
disabled && 'is-disabled',
]"
:href="disabled ? null : href"
>

从样式上面来说,输了参考 type 中,有 disable 相关的样式改变外,disabled 还设置了鼠标上移时的鼠标样式反馈:

@include when(disabled) {
cursor: not-allowed;
}

除此以外,还有一个细节:当设置 disabled 的时候,点击这个链接应该是没有跳转行为的。此时,HTML 中的 <a> 标签,应该没有 href 这个属性。经过测试,如果是设置 href="",点击 <a> 标签会重复跳转当前页面。

# 点击不会跳转
<a class="el-link el-link--default is-disabled">

# 点击后会有跳转当前页面的行为
<a href class="el-link el-link--default is-disabled">

underline

underline 属性的设置,也是反映到 <a> 中 class 的变化。

<a
:class="[
'el-link',
underline && !disabled && 'is-underline'
]"
>

el-link 有一个比较细节的地方,就是它的下划线,并没有使用 HTML <a> 的原生 text-decoration: underline 属性,估计是满足不了设计师的设计,太丑了 hhhh。

其实现方案是,创建一个伪元素::after,通过 position: absolute 设置伪元素和当前 <a> 标签的位置与大小重合。设置 content: "" 设置伪元素没有内容,不会影响 <a> 标签内的内容。最后设置 border-bottom,来自定义下划线的样式。即 el-link 的下划线,其实是伪元素的 border-bottom 来模拟的。

参考 SCSS 的实现部分:

@include when(underline) {
&:hover:after {
content: "";
position: absolute;
left: 0;
right: 0;
height: 0;
bottom: 0;
border-bottom: 1px solid $--link-default-active-color
}
}

slot 与 icon

这两部分放在一起,是因为 sloticon 属性,都是在 <a> 标签的子元素:

<a>
<i :class="icon" v-if="icon"></i>

<span v-if="$slots.default" class="el-link--inner">
<slot></slot>
</span>

<template v-if="$slots.icon"><slot v-if="$slots.icon" name="icon"></slot></template>
</a>

从这段代码中可以看出来,el-link 支持 icon 属性,也支持默认 slot,以及具名 slot=icon,虽然具名 slot 并没有在例子中体现出来。

Template

v-bind="$attrs"

在封装 <a> 的时候,有一个属性大家要注意:

<a v-bind="$attrs"></a>

通过 v-bind="$attrs" 这种方法,可以将 el-link 中非 props 属性都传给 <a> 标签,这样我们在封装高级组件的时候,特别是封装基础标签的高级组件,不同将该标签的每一个属性都通过 props 单独设置一遍,这在封装基础 HTML 标签的时候很重要。(PS: 为什么 el-button 没有设置 v-bind="$attrs" 呢?我暂时没想出来,大家知道的,非常欢迎在下面留言,我会补充到文章里的~)

click 事件

<template>
<a
@click="handleClick">
</a>
</template>
<script>
export default {
methods: {
handleClick(event) {
if (!this.disabled) {
if (!this.href) {
this.$emit('click', event);
}
}
}
}
}
</script>

当设置了 disabled 属性,或者没有设置 href 属性的时候,我们可以通过设置 el-linkclick 事件,来监听 a 标签的点击事件。

CSS 相关的源码解读,之后再补充


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK