1

一天一个 Element 组件 - Badge

 2 years ago
source link: https://shiningdan.github.io/2020/01/31/%E4%B8%80%E5%A4%A9%E4%B8%80%E4%B8%AA-Element-%E7%BB%84%E4%BB%B6-Badge/
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.

一天一个 Element 组件 - Badge

发表于 2020-01-31

| 分类于 coding

|

| 阅读次数

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

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

Badge 组件使用文档:badge 标记

.vue 文件:/packages/badge

.scss 文件:/packages/theme-chalk/badge.scss

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

Props

我们先来看一下 el-badge 这个组件的入参

props: {
value: [String, Number],
max: Number,
isDot: Boolean,
hidden: Boolean,
type: {
type: String,
validator(val) {
return ['primary', 'success', 'warning', 'info', 'danger'].indexOf(val) > -1;
}
}
},

is-dot

is-dot 这个属性比较简单,当这个属性赋值为 true 的时候,右上角的标记是一个小圆点。我们来看一下是如何实现的:

<div class="el-badge">
<slot></slot>
<transition name="el-zoom-in-center">
<sup
v-show="!hidden && (content || content === 0 || isDot)"
v-text="content"
class="el-badge__content"
:class="[
'el-badge__content--' + type,
{
'is-fixed': $slots.default,
'is-dot': isDot
}
]">
</sup>
</transition>
</div>

首先,el-badge 的用法,是 <el-badge> 标签,包裹住需要右上角有标签的元素,所以 <template> 中的实现,是返回了一个 <div>,包裹住被需要有标签的元素 <slot>,在外面形成一个壳。然后通过 CSS,将标签定位到该元素的右上角。

首先,标签被包裹在一个动效里面,这个动效是 ElementUI 设计的动效,具体的效果可以参考 内置过渡动画

动效大致的实现思路是,利用 Vue 提供的原生组件 <transition>,然后实现了具体的类。比如这里的 name = el-zoom-in-center,就需要实现 el-zoom-in-center-enterel-zoom-in-center-activeel-zoom-in-center-leave 等。具体要实现哪些类,在 Vue 文档中可以找到:过渡 & 动画 | 过渡的类名

在 ElementUI 中,这些类的实现,可以在 transition.scss 这里找到,大家有兴趣可以去看一下 ~

在不考虑动效之后,我们来看一下 is-dot 是如何实现的。

首先,当用户传入 is-dot 的时候,此时 contentundefined

computed: {
content() {
if (this.isDot) return;
}
}

所以 <sup>classel-badge__contentis-dot

然后 :class 的逻辑里面,还有一句是 'is-fixed': $slots.default。啥意思呢?$slots.default 指的是被 el-badge 包裹住的组件,如果 el-badge 包裹了某个组件,比如一个文本,则 $slots.default 的值就不为空,calss 就还需要加上 is-fixed

我们来看一下这几个类的实现逻辑:

// badge.scss
@include b(badge) {
position: relative;
vertical-align: middle;
display: inline-block;

@include e(content) {
background-color: $--badge-background-color;
border-radius: $--badge-radius;
color: $--color-white;
display: inline-block;
font-size: $--badge-font-size;
height: $--badge-size;
line-height: $--badge-size;
padding: 0 $--badge-padding;
text-align: center;
white-space: nowrap;
border: 1px solid $--color-white;

@include when(fixed) {
position: absolute;
top: 0;
right: #{1 + $--badge-size / 2};
transform: translateY(-50%) translateX(100%);

@include when(dot) {
right: 5px;
}
}

@include when(dot) {
height: 8px;
width: 8px;
padding: 0;
right: 0;
border-radius: 50%;
}
}

大体的实现思路如下:

  1. 使用 <sup> 标签。<sup> 标签在浏览器中,有一个默认的 CSS 属性是 vertical-align: super,该属性的作用是,将 <sup> 垂直对齐文本的上标,也就是放在右上角
  2. 设置 position: relative 包裹住需要有角标的 HTML 元素,方便把角标通过 position: absolute 定位到右上角;设置 display: inline-block,让被包裹元素和角标在一行
  3. 如果被包裹元素存在,则触发 @include when(fixed) 函数,设置 position: absolute; top: 0; right: #{1 + $--badge-size / 2};,将角标调整到右上角向左 10px
  4. 针对元素的宽度和高度,做一些调整:transform: translateY(-50%) translateX(100%);。这句话大概的意思是:把元素沿着横向(x轴)移动自身宽度的100%,一般是从左侧为开始点也就是0点。而数值是100%,所以是从右侧0点向左移动自身宽度的100%。同时,向上移动自身高度的 50%

所以,整体实现的效果是,如果设置 right: 0px; transform: translateY(-50%) translateX(100%);。则 badge 放在被定位元素的右上角,从 X 轴上面没有重合,Y 轴上面,badge 上移了 50% 的高度。然后为了美观,将 right 设置为 #{1 + $--badge-size / 2};。通过 var.scss 文件,我们可以得到 $--badge-size 默认是 18px。所以默认情况下,badge 在被包裹元素的右上角,朝左移动 10px,高度有 50% 的重合。

当然,如果有 is-Dot 的时候,直接将 <sup> 通过 width = height = 8px; border-radius: 50%,画成一个小圆球就好。

max 和 value

value 有值的时候,content 就有值。此时赋值 v-text="content",就是让 <sup> 元素包裹一个文本就好。

我们可以看一下 max 是怎么实现的:

content() {
if (this.isDot) return;

const value = this.value;
const max = this.max;

if (typeof value === 'number' && typeof max === 'number') {
return max < value ? `${max}+` : value;
}

return value;
}

如果 maxvalue 都存在并且是数字类型,则比较 valuemax 的大小,如果 value 小于 max,则 badge 的内容就是 value 的值。如果 value 大于 max,则 badge 的内容就是 ${max}+ 字符串的值。比如 value = 100; max = 10,则 badge 的内容就是 10+


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK