feat: GiTag 组件功能扩展,提供 color 属性,用于自定义颜色

This commit is contained in:
2024-08-06 21:46:36 +08:00
parent ad53e1d419
commit 050a171e91
2 changed files with 185 additions and 124 deletions

View File

@@ -1,23 +1,43 @@
import { type PropType, computed, defineComponent } from 'vue'
import { type CSSProperties, type PropType, computed, defineComponent } from 'vue'
import './tag.scss'
type TPropsType = 'dark' | 'light' | 'outline' | 'light-outline'
type TPropsStatus = 'primary' | 'success' | 'warning' | 'danger' | 'info'
type TPropsSize = 'mini' | 'small' | 'large'
type PropsType = 'dark' | 'light' | 'outline' | 'light-outline'
type PropsStatus = 'primary' | 'success' | 'warning' | 'danger' | 'info'
type PropsSize = 'mini' | 'small' | 'large'
const baseColorObj = {
red: '#FF0000 ',
orangered: '#f77234',
orange: '#ff7d00',
gold: '#f7ba1e',
lime: '#9fdb1d',
green: '#00b42a',
cyan: '#14c9c9',
blue: '#3491fa',
purple: '#722ed1',
pink: '#f5319d',
gray: '#86909c'
}
type BaseColor = keyof typeof baseColorObj
export default defineComponent({
name: 'GiTag',
props: {
type: {
type: String as PropType<TPropsType>,
type: String as PropType<PropsType>,
default: 'light'
},
status: {
type: String as PropType<TPropsStatus>,
type: String as PropType<PropsStatus>,
default: 'primary'
},
color: {
type: String as PropType<BaseColor | string>,
default: ''
},
size: {
type: String as PropType<TPropsSize>,
type: String as PropType<PropsSize>,
default: 'small'
},
closable: {
@@ -30,17 +50,60 @@ export default defineComponent({
const className = computed(() => {
const arr = ['gi-tag']
if (props.type) {
arr.push(`gi-tag-${props.type}`)
arr.push(`gi-tag__type--${props.type}`)
}
if (props.size) {
arr.push(`gi-tag-size-${props.size}`)
arr.push(`gi-tag__size--${props.size}`)
}
if (props.status) {
arr.push(`gi-tag-status-${props.status === 'info' ? 'gray' : props.status}`)
arr.push(`gi-tag__status--${props.status}`)
}
return arr
})
// 十六进制颜色 转 rgb
function hexToRgb(hex: string) {
if (hex.includes('#')) {
hex = hex.slice(1)
}
const r = Number.parseInt(hex.slice(0, 2), 16)
const g = Number.parseInt(hex.slice(2, 4), 16)
const b = Number.parseInt(hex.slice(4, 6), 16)
return { r, g, b }
}
const calcStyle = computed(() => {
const obj: CSSProperties = {}
if (props.color) {
const color = baseColorObj[props.color] || props.color
const { r, g, b } = hexToRgb(color)
if (props.type === 'light') {
obj.color = color
obj.backgroundColor = `rgba(${r}, ${g}, ${b}, 0.1)`
obj['--tag-close-hover-bg-color'] = color
}
if (props.type === 'dark') {
obj.color = '#fff'
obj.backgroundColor = color
obj['--tag-close-hover-color'] = color
obj['--tag-close-hover-bg-color'] = `rgba(255, 255, 255, 0.9)`
}
if (props.type === 'outline') {
obj.color = color
obj.backgroundColor = 'transparent'
obj.borderColor = color
obj['--tag-close-hover-bg-color'] = color
}
if (props.type === 'light-outline') {
obj.color = color
obj.backgroundColor = `rgba(${r}, ${g}, ${b}, 0.1)`
obj.borderColor = `rgba(${r}, ${g}, ${b}, 0.2)`
obj['--tag-close-hover-bg-color'] = color
}
}
return obj
})
const handleClick = () => {
emit('click')
}
@@ -57,7 +120,7 @@ export default defineComponent({
)
return () => (
<span class={className.value} onClick={handleClick}>
<span class={className.value} style={calcStyle.value} onClick={handleClick}>
{slots.default?.()}
{props.closable && CloseIcon}
</span>

View File

@@ -1,8 +1,17 @@
$status: primary, success, warning, danger;
$tag-size-mini-height: 20px;
$tag-size-small-height: 22px;
$tag-size-large-height: 24px;
$tag-size-mini-padding: 0 6px;
$tag-size-small-padding: 0 8px;
$tag-size-large-padding: 0 10px;
.gi-tag {
display: inline-flex;
padding: 0 8px;
// padding-top: 1px;
height: 20px;
padding: $tag-size-small-padding;
height: $tag-size-small-height;
font-size: 12px;
line-height: 1;
border-radius: 3px;
@@ -15,122 +24,28 @@
.gi-tag-close-btn {
position: relative;
display: inline-flex;
display: flex;
justify-content: center;
align-items: center;
cursor: pointer;
margin-left: 4px;
width: 16px;
height: 16px;
box-sizing: border-box;
background-color: transparent;
border-radius: var(--border-radius-circle);
transition: background-color 0.1s cubic-bezier(0, 0, 1, 1);
.close-icon {
width: 12px;
height: 12px;
z-index: 9;
}
&::before {
width: 16px;
height: 16px;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
content: '';
position: absolute;
display: block;
box-sizing: border-box;
background-color: transparent;
border-radius: var(--border-radius-circle);
transition: background-color 0.1s cubic-bezier(0, 0, 1, 1);
}
}
$status: primary, success, warning, danger, 'gray';
.gi-tag-dark {
color: #fff;
@each $i in $status {
&.gi-tag-status-#{$i} {
border: 1px solid rgb(var(--#{$i}-6));
background-color: rgb(var(--#{$i}-6));
.gi-tag-close-btn {
&:hover {
color: rgb(var(--#{$i}-6));
&::before {
background-color: rgb(var(--#{$i}-2));
}
}
}
}
}
}
.gi-tag-light {
color: #fff;
@each $i in $status {
&.gi-tag-status-#{$i} {
color: rgb(var(--#{$i}-6));
background-color: rgb(var(--#{$i}-1));
.gi-tag-close-btn {
&:hover {
color: #fff;
&::before {
background-color: rgb(var(--#{$i}-6));
}
}
}
}
}
}
.gi-tag-outline {
background: transparent;
@each $i in $status {
&.gi-tag-status-#{$i} {
color: rgb(var(--#{$i}-6));
border: 1px solid rgb(var(--#{$i}-6));
.gi-tag-close-btn {
&:hover {
color: #fff;
&::before {
background-color: rgb(var(--#{$i}-6));
}
}
}
}
}
}
.gi-tag-light-outline {
@each $i in $status {
&.gi-tag-status-#{$i} {
color: rgb(var(--#{$i}-6));
border: 1px solid rgb(var(--#{$i}-2));
background-color: rgb(var(--#{$i}-1));
.gi-tag-close-btn {
&:hover {
color: #fff;
&::before {
background-color: rgb(var(--#{$i}-6));
}
}
}
}
}
}
.gi-tag-size-mini {
height: 22px;
padding: 0 4px;
.gi-tag__size--mini {
height: $tag-size-mini-height;
padding: $tag-size-mini-padding;
.gi-tag-close-btn {
.close-icon {
@@ -145,12 +60,95 @@ $status: primary, success, warning, danger, 'gray';
}
}
.gi-tag-size-small {
height: 24px;
.gi-tag__size--small {
height: $tag-size-small-height;
padding: $tag-size-small-padding;
}
.gi-tag-size-large {
height: 28px;
padding: 0 10px;
font-size: 14px;
.gi-tag__size--large {
height: $tag-size-large-height;
padding: $tag-size-small-padding;
}
.gi-tag__type--light {
color: #fff;
@each $i in $status {
&.gi-tag__status--#{$i} {
color: rgb(var(--#{$i}-6));
background-color: rgb(var(--#{$i}-1));
--tag-close-hover-color: #fff;
--tag-close-hover-bg-color: rgb(var(--#{$i}-6));
.gi-tag-close-btn {
&:hover {
color: var(--tag-close-hover-color);
background-color: var(--tag-close-hover-bg-color);
}
}
}
}
}
.gi-tag__type--dark {
color: #fff;
@each $i in $status {
&.gi-tag__status--#{$i} {
background-color: rgb(var(--#{$i}-6));
--tag-close-hover-color: rgb(var(--#{$i}-6));
--tag-close-hover-bg-color: rgba(255, 255, 255, 0.9);
.gi-tag-close-btn {
&:hover {
color: var(--tag-close-hover-color);
background-color: var(--tag-close-hover-bg-color);
}
}
}
}
}
.gi-tag__type--outline {
background: transparent;
border-width: 1px;
border-style: solid;
@each $i in $status {
&.gi-tag__status--#{$i} {
color: rgb(var(--#{$i}-6));
border-color: rgb(var(--#{$i}-6));
--tag-close-hover-color: #fff;
--tag-close-hover-bg-color: rgb(var(--#{$i}-6));
.gi-tag-close-btn {
&:hover {
color: var(--tag-close-hover-color);
background-color: var(--tag-close-hover-bg-color);
}
}
}
}
}
.gi-tag__type--light-outline {
border-width: 1px;
border-style: solid;
@each $i in $status {
&.gi-tag__status--#{$i} {
color: rgb(var(--#{$i}-6));
border-color: rgb(var(--#{$i}-2));
background-color: rgb(var(--#{$i}-1));
--tag-close-hover-color: #fff;
--tag-close-hover-bg-color: rgb(var(--#{$i}-6));
.gi-tag-close-btn {
&:hover {
color: var(--tag-close-hover-color);
background-color: var(--tag-close-hover-bg-color);
}
}
}
}
}