整体
<template>
<div class="el-badge">
<slot></slot>
<transition name="el-zoom-in-center">
<sup
v-show="!hidden"
v-text="content"
class="el-badge__content"
:class="{ 'is-fixed': $slots.default, 'is-dot': isDot }">
</sup>
</transition>
</div>
</template>
el-badge包裹
首先最外层是一个div.el-badge
来包裹整体。
<div class="el-badge">
</div>
slot
然后是一个slot
,这是用来承载整个标记的部分,这样才能将标记组件用于其他地方,这一部分没有做任何处理。
<slot></slot>
transition包裹
标记动画使用了el-zoom-in-center
。
<transition name="el-zoom-in-center">
</transition>
这一动画的css代码如下,可以实现从中心开始放大的效果。
.el-zoom-in-center-enter-active,
.el-zoom-in-center-leave-active {
transition: all .3s cubic-bezier(.55,0,.1,1);
}
.el-zoom-in-center-enter,
.el-zoom-in-center-leave-active {
opacity: 0;
transform: scaleX(0);
}
可以看出,效果的实现原理是改变透明度以及横向的缩放。
sup
然后是标记的主要实现部分,用一个上标标签sup
来包裹,这样的做法十分符合语义,可以看出来饿了吗这一前端团队的基础挺好。
<sup
v-show="!hidden"
v-text="content"
class="el-badge__content"
:class="{ 'is-fixed': $slots.default, 'is-dot': isDot }">
</sup>
它做了如下几件事:
- 通过
hidden
这一prop
决定是否显示; - 通过
v-text
来渲染content
这一计算属性
; - 根据
slot
的有无决定is-fixed
类的有无; - 根据
isDot
这一prop
决定是否is-dot
类的有无。
hidden
hidden
很简单,就是一个Boolean
类型的prop
。
props: {
hidden: Boolean
}
content
content
这一计算属性相对复杂一点,首先我们看一下它的代码,加上一点注释。
computed: {
content() {
if (this.isDot) return; // isDot为true,直接返回,这样就不存在内容
const value = this.value; // 当前值
const max = this.max; // 最大值
// value和max都是数字时,进行比较
// 小于max的时候,显示确切值
// 大于max的时候,显示最大值+
if (typeof value === 'number' && typeof max === 'number') {
return max < value ? `${max}+` : value;
}
// 返回非数字的value
return value;
}
}
其中用到的几个prop
如下:
props: {
value: {},
max: Number,
isDot: Boolean
}
这里value
可以是string
或者number
,可能因为懒,才直接写的{}
,具体原因不明,整体来说,这一个组件在props
上的定义较为粗糙。
is-fixed
值得注意的是,这一部分的样式的处理。
@when fixed {
position: absolute 0 calc(var(--badge-size) / 2 + 1) * *;
transform: translateY(-50%) translateX(100%);
@when dot {
right: 5px;
}
}
当存在slot
,即有依托的其他部分的时候,sup
会变成absolute
放置于右上角,这样文本流里面只有依托的slot
,反之文本流里直接就是sup
。