163 lines
3.0 KiB
Plaintext
163 lines
3.0 KiB
Plaintext
<template>
|
|
<text class="cl-icon" :class="[ptClassName]" :style="iconStyle" :key="cache.key">
|
|
{{ icon.text }}
|
|
</text>
|
|
</template>
|
|
|
|
<script setup lang="ts">
|
|
import { computed, type PropType } from "vue";
|
|
import {
|
|
forInObject,
|
|
get,
|
|
has,
|
|
parsePt,
|
|
useCache,
|
|
isDark,
|
|
ctx,
|
|
hasTextColor,
|
|
isNull
|
|
} from "@/cool";
|
|
import { icons } from "@/icons";
|
|
import { useSize } from "../../hooks";
|
|
|
|
defineOptions({
|
|
name: "cl-icon"
|
|
});
|
|
|
|
// 定义组件属性
|
|
const props = defineProps({
|
|
// 透传样式
|
|
pt: {
|
|
type: Object,
|
|
default: () => ({})
|
|
},
|
|
// 图标名称
|
|
name: {
|
|
type: String,
|
|
default: ""
|
|
},
|
|
// 图标大小
|
|
size: {
|
|
type: [String, Number] as PropType<string | number>,
|
|
default: 32
|
|
},
|
|
// 图标高度
|
|
height: {
|
|
type: [String, Number] as PropType<string | number>,
|
|
default: null
|
|
},
|
|
// 图标宽度
|
|
width: {
|
|
type: [String, Number] as PropType<string | number>,
|
|
default: null
|
|
},
|
|
// 图标颜色
|
|
color: {
|
|
type: String,
|
|
default: ""
|
|
}
|
|
});
|
|
|
|
// 透传样式类型定义
|
|
type PassThrough = {
|
|
className?: string;
|
|
};
|
|
|
|
// 解析透传样式
|
|
const pt = computed(() => parsePt<PassThrough>(props.pt));
|
|
|
|
// 缓存
|
|
const { cache } = useCache(() => [props.color]);
|
|
|
|
// 字号
|
|
const { getRpx, ptClassName } = useSize(() => pt.value.className ?? "");
|
|
|
|
// 图标类型定义
|
|
type Icon = {
|
|
font: string; // 字体名称
|
|
text: string; // 图标文本
|
|
};
|
|
|
|
// 图标信息
|
|
const icon = computed<Icon>(() => {
|
|
let font = "";
|
|
let text = "";
|
|
|
|
try {
|
|
let code = "";
|
|
|
|
// 遍历字体库查找对应图标
|
|
forInObject(icons, (value, key) => {
|
|
if (has(value, props.name)) {
|
|
font = key;
|
|
code = get(value, props.name) as string;
|
|
}
|
|
});
|
|
|
|
text = String.fromCharCode(parseInt(code, 16));
|
|
} catch (e) {
|
|
console.error(`图标 ${props.name} 不存在`, e);
|
|
}
|
|
|
|
return {
|
|
font,
|
|
text
|
|
};
|
|
});
|
|
|
|
// 图标颜色
|
|
const color = computed(() => {
|
|
if (props.color != "" && !isNull(props.color)) {
|
|
switch (props.color) {
|
|
case "primary":
|
|
return ctx.color["primary-500"] as string;
|
|
case "success":
|
|
return "#22c55e";
|
|
case "warn":
|
|
return "#eab308";
|
|
case "error":
|
|
return "#ef4444";
|
|
case "info":
|
|
return ctx.color["surface-500"] as string;
|
|
case "dark":
|
|
return ctx.color["surface-700"] as string;
|
|
case "light":
|
|
return ctx.color["surface-50"] as string;
|
|
case "disabled":
|
|
return ctx.color["surface-300"] as string;
|
|
default:
|
|
return props.color;
|
|
}
|
|
}
|
|
|
|
return isDark.value ? "white" : (ctx.color["surface-700"] as string);
|
|
});
|
|
|
|
// 图标样式
|
|
const iconStyle = computed(() => {
|
|
const style = {};
|
|
|
|
// 判断是不是有颜色样式
|
|
if (!hasTextColor(ptClassName.value)) {
|
|
style["color"] = color.value;
|
|
}
|
|
|
|
// 设置字体
|
|
if (icon.value.font != "") {
|
|
style["fontFamily"] = icon.value.font;
|
|
}
|
|
|
|
// 设置字体大小
|
|
style["fontSize"] = getRpx(props.size!);
|
|
|
|
// 设置高度
|
|
style["height"] = getRpx(props.height ?? props.size!);
|
|
style["lineHeight"] = getRpx(props.size!);
|
|
|
|
// 设置宽度
|
|
style["width"] = getRpx(props.width ?? props.size!);
|
|
|
|
return style;
|
|
});
|
|
</script>
|