u
This commit is contained in:
1 parent
d37d92996a
commit
a8f3e58a27
25 files changed
+1401
-399
No files matched your search
@@ -0,0 +1,79 @@
|
||||
<script setup lang="ts">
|
||||
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="container">
|
||||
<ABadge count="12">
|
||||
<AButton>测试</AButton>
|
||||
</ABadge>
|
||||
|
||||
<ABadge type="dot">
|
||||
<AButton>测试</AButton>
|
||||
</ABadge>
|
||||
|
||||
<ABadge type="custom">
|
||||
<template #content>
|
||||
<AIcon icon="material-symbols:10k-outline-rounded" />
|
||||
</template>
|
||||
<AButton>测试</AButton>
|
||||
</ABadge>
|
||||
|
||||
<ABadge count="12" :offset="[10, -5]">
|
||||
<AButton>测试</AButton>
|
||||
</ABadge>
|
||||
|
||||
<ABadge count="12" color="blue">
|
||||
<AButton>测试</AButton>
|
||||
</ABadge>
|
||||
|
||||
<ABadge count="12" type="ribbon" ribbon-text="123" background-color="red">
|
||||
<div
|
||||
style="
|
||||
width: 200px;
|
||||
height: 120px;
|
||||
background-color: #fff;
|
||||
border-radius: 12px;
|
||||
box-shadow: 0 4px 12px rgba(0,0,0,0.1);
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
font-size: 16px;
|
||||
color: #333;
|
||||
"
|
||||
>
|
||||
测试卡片
|
||||
</div>
|
||||
</ABadge>
|
||||
|
||||
<ABadge count="12" type="ribbon" ribbon-text="123" background-color="red" color="blue">
|
||||
<div
|
||||
style="
|
||||
width: 200px;
|
||||
height: 120px;
|
||||
background-color: #fff;
|
||||
border-radius: 12px;
|
||||
box-shadow: 0 4px 12px rgba(0,0,0,0.1);
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
font-size: 16px;
|
||||
color: #333;
|
||||
"
|
||||
>
|
||||
测试卡片
|
||||
</div>
|
||||
</ABadge>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.container {
|
||||
height: 800px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
flex-direction: column;
|
||||
gap: 16px;
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,83 @@
|
||||
@use '../_styles/_variables.scss' as *;
|
||||
@use 'sass:color';
|
||||
|
||||
$badge-prefix: '#{$prefix}-badge';
|
||||
|
||||
.#{$badge-prefix} {
|
||||
box-sizing: border-box;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
list-style: none;
|
||||
position: relative;
|
||||
display: inline-block;
|
||||
|
||||
.#{$badge-prefix}-dot,
|
||||
.#{$badge-prefix}-circle,
|
||||
.#{$badge-prefix}-custom {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
right: 0;
|
||||
color: $text-color-anti;
|
||||
text-align: center;
|
||||
font-size: 12px;
|
||||
transform: translate(50%, -50%);
|
||||
transform-origin: 100% 0;
|
||||
box-sizing: content-box;
|
||||
}
|
||||
|
||||
.#{$badge-prefix}-circle {
|
||||
padding: 0px 6px;
|
||||
min-width: 8px;
|
||||
height: 20px;
|
||||
background-color: $danger-color;
|
||||
line-height: 20px;
|
||||
border-radius: 10px;
|
||||
box-shadow: 0 0 0 2px $bg-color-container;
|
||||
}
|
||||
|
||||
.#{$badge-prefix}-dot {
|
||||
right: 1px;
|
||||
margin-top: 1px;
|
||||
width: 6px;
|
||||
height: 6px;
|
||||
border-radius: 50%;
|
||||
background-color: $danger-color;
|
||||
box-shadow: 0 0 0 2px $bg-color-container;
|
||||
}
|
||||
|
||||
.#{$badge-prefix}-custom {
|
||||
color: $text-color-base;
|
||||
background-color: $bg-color-container;
|
||||
}
|
||||
|
||||
.#{$badge-prefix}-ribbon {
|
||||
margin: 0;
|
||||
padding: 0 6px;
|
||||
font-size: 14px;
|
||||
line-height: 22px;
|
||||
list-style: none;
|
||||
position: absolute;
|
||||
top: 8px;
|
||||
white-space: nowrap;
|
||||
background-color: $primary-color;
|
||||
border-radius: 4px;
|
||||
inset-inline-end: -8px;
|
||||
border-end-end-radius: 0;
|
||||
color: $primary-color;
|
||||
|
||||
&-text {
|
||||
color: $text-color-anti;
|
||||
}
|
||||
|
||||
&-corner {
|
||||
position: absolute;
|
||||
top: 100%;
|
||||
right: 0;
|
||||
width: 0;
|
||||
height: 0;
|
||||
border-style: solid;
|
||||
border-width: 8px 8px 0 0;
|
||||
border-color: currentColor transparent transparent transparent;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,160 @@
|
||||
import type { PropType, VNode } from 'vue'
|
||||
import { computed, defineComponent } from 'vue'
|
||||
import { getPrefixCls } from '../_utils/getPrefixCls'
|
||||
|
||||
export default defineComponent({
|
||||
name: 'Badge',
|
||||
props: {
|
||||
type: {
|
||||
type: String as () => 'circle' | 'dot' | 'custom' | 'ribbon',
|
||||
default: 'circle',
|
||||
},
|
||||
count: {
|
||||
type: [Number, String] as PropType<number | string>,
|
||||
},
|
||||
minCount: {
|
||||
type: [Number, String] as PropType<number | string>,
|
||||
default: undefined,
|
||||
},
|
||||
maxCount: {
|
||||
type: [Number, String] as PropType<number | string>,
|
||||
},
|
||||
showZero: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
ribbonText: {
|
||||
type: [String, Object, Function] as PropType<string | VNode | (() => VNode)>,
|
||||
default: '',
|
||||
},
|
||||
offset: {
|
||||
type: Array as PropType<(string | number)[]>,
|
||||
default: undefined,
|
||||
},
|
||||
color: {
|
||||
type: String,
|
||||
default: '',
|
||||
},
|
||||
backgroundColor: {
|
||||
type: String,
|
||||
default: '',
|
||||
},
|
||||
class: {
|
||||
type: [String, Array, Object],
|
||||
default: '',
|
||||
},
|
||||
style: {
|
||||
type: Object,
|
||||
default: () => ({}),
|
||||
},
|
||||
},
|
||||
setup(props, { slots }) {
|
||||
const prefixCls = getPrefixCls('badge')
|
||||
|
||||
const displayCount = computed(() => {
|
||||
if (props.type !== 'circle')
|
||||
return props.count
|
||||
|
||||
let countNum = Number(props.count)
|
||||
const maxNum = props.maxCount != null ? Number(props.maxCount) : null
|
||||
const minNum = props.minCount != null ? Number(props.minCount) : null
|
||||
|
||||
const isCountNumeric = Number.isFinite(countNum)
|
||||
const isMaxNumeric = maxNum !== null && Number.isFinite(maxNum)
|
||||
const isMinNumeric = minNum !== null && Number.isFinite(minNum)
|
||||
|
||||
// 如果传了 minCount,showZero 不生效
|
||||
if (!isMinNumeric && !props.showZero && countNum === 0)
|
||||
return undefined
|
||||
|
||||
// 先处理 minCount
|
||||
if (isCountNumeric && isMinNumeric && countNum < (minNum as number)) {
|
||||
countNum = minNum as number
|
||||
}
|
||||
|
||||
// 再处理 maxCount
|
||||
if (isCountNumeric && isMaxNumeric && countNum > (maxNum as number)) {
|
||||
return `${maxNum}+`
|
||||
}
|
||||
|
||||
return countNum
|
||||
})
|
||||
|
||||
return () => {
|
||||
const supStyle: Record<string, string> = {}
|
||||
|
||||
if (props.offset && props.offset.length === 2) {
|
||||
const [x, y] = props.offset
|
||||
supStyle.top = typeof y === 'number' ? `${y}px` : y
|
||||
supStyle.right = typeof x === 'number' ? `${x}px` : x
|
||||
}
|
||||
|
||||
// backgroundColor
|
||||
if (props.backgroundColor) {
|
||||
if (props.type === 'ribbon') {
|
||||
supStyle.backgroundColor = props.backgroundColor
|
||||
supStyle.color = props.backgroundColor
|
||||
}
|
||||
else {
|
||||
supStyle.color = props.backgroundColor
|
||||
}
|
||||
}
|
||||
const ribbonTextStyle: Record<string, string> = {}
|
||||
|
||||
// color
|
||||
if (props.color) {
|
||||
if (props.type === 'ribbon') {
|
||||
ribbonTextStyle.color = props.color
|
||||
}
|
||||
else {
|
||||
supStyle.color = props.color
|
||||
}
|
||||
}
|
||||
|
||||
let supNode = null
|
||||
|
||||
if (props.type === 'dot') {
|
||||
supNode = <sup class={`${prefixCls}-dot`} style={supStyle}></sup>
|
||||
}
|
||||
else if (props.type === 'circle' && displayCount.value !== undefined) {
|
||||
supNode = (
|
||||
<sup class={`${prefixCls}-circle`} style={supStyle}>
|
||||
{displayCount.value}
|
||||
</sup>
|
||||
)
|
||||
}
|
||||
else if (props.type === 'custom') {
|
||||
supNode = (
|
||||
<sup class={`${prefixCls}-custom`} style={supStyle}>
|
||||
{slots.content?.()}
|
||||
</sup>
|
||||
)
|
||||
}
|
||||
else if (props.type === 'ribbon') {
|
||||
const renderRibbonText = () => {
|
||||
if (slots.ribbon)
|
||||
return slots.ribbon()
|
||||
if (typeof props.ribbonText === 'function')
|
||||
return props.ribbonText()
|
||||
return props.ribbonText
|
||||
}
|
||||
|
||||
supNode = (
|
||||
<sup class={`${prefixCls}-ribbon`} style={supStyle}>
|
||||
<div class={`${prefixCls}-ribbon-text`} style={ribbonTextStyle}>
|
||||
{renderRibbonText()}
|
||||
</div>
|
||||
<div class={`${prefixCls}-ribbon-corner`}></div>
|
||||
</sup>
|
||||
)
|
||||
}
|
||||
|
||||
return (
|
||||
<div class={[prefixCls, props.class]} style={{ ...props.style }}>
|
||||
{slots.default?.()}
|
||||
{supNode}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
},
|
||||
})
|
||||
Reference in new issue
Block a user