cl-icon.uvue 3.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162
  1. <template>
  2. <text class="cl-icon" :class="[ptClassName]" :style="iconStyle" :key="cache.key">
  3. {{ icon.text }}
  4. </text>
  5. </template>
  6. <script setup lang="ts">
  7. import { computed, type PropType } from "vue";
  8. import {
  9. forInObject,
  10. get,
  11. has,
  12. parsePt,
  13. useCache,
  14. isDark,
  15. ctx,
  16. hasTextColor,
  17. isNull
  18. } from "@/cool";
  19. import { icons } from "@/icons";
  20. import { useSize } from "../../hooks";
  21. defineOptions({
  22. name: "cl-icon"
  23. });
  24. // 定义组件属性
  25. const props = defineProps({
  26. // 透传样式
  27. pt: {
  28. type: Object,
  29. default: () => ({})
  30. },
  31. // 图标名称
  32. name: {
  33. type: String,
  34. default: ""
  35. },
  36. // 图标大小
  37. size: {
  38. type: [String, Number] as PropType<string | number>,
  39. default: 32
  40. },
  41. // 图标高度
  42. height: {
  43. type: [String, Number] as PropType<string | number>,
  44. default: null
  45. },
  46. // 图标宽度
  47. width: {
  48. type: [String, Number] as PropType<string | number>,
  49. default: null
  50. },
  51. // 图标颜色
  52. color: {
  53. type: String,
  54. default: ""
  55. }
  56. });
  57. // 透传样式类型定义
  58. type PassThrough = {
  59. className?: string;
  60. };
  61. // 解析透传样式
  62. const pt = computed(() => parsePt<PassThrough>(props.pt));
  63. // 缓存
  64. const { cache } = useCache(() => [props.color]);
  65. // 字号
  66. const { getRpx, ptClassName } = useSize(() => pt.value.className ?? "");
  67. // 图标类型定义
  68. type Icon = {
  69. font: string; // 字体名称
  70. text: string; // 图标文本
  71. };
  72. // 图标信息
  73. const icon = computed<Icon>(() => {
  74. let font = "";
  75. let text = "";
  76. try {
  77. let code = "";
  78. // 遍历字体库查找对应图标
  79. forInObject(icons, (value, key) => {
  80. if (has(value, props.name)) {
  81. font = key;
  82. code = get(value, props.name) as string;
  83. }
  84. });
  85. text = String.fromCharCode(parseInt(code, 16));
  86. } catch (e) {
  87. console.error(`图标 ${props.name} 不存在`, e);
  88. }
  89. return {
  90. font,
  91. text
  92. };
  93. });
  94. // 图标颜色
  95. const color = computed(() => {
  96. if (props.color != "" && !isNull(props.color)) {
  97. switch (props.color) {
  98. case "primary":
  99. return ctx.color["primary-500"] as string;
  100. case "success":
  101. return "#22c55e";
  102. case "warn":
  103. return "#eab308";
  104. case "error":
  105. return "#ef4444";
  106. case "info":
  107. return ctx.color["surface-500"] as string;
  108. case "dark":
  109. return ctx.color["surface-700"] as string;
  110. case "light":
  111. return ctx.color["surface-50"] as string;
  112. case "disabled":
  113. return ctx.color["surface-300"] as string;
  114. default:
  115. return props.color;
  116. }
  117. }
  118. return isDark.value ? "white" : (ctx.color["surface-700"] as string);
  119. });
  120. // 图标样式
  121. const iconStyle = computed(() => {
  122. const style = {};
  123. // 判断是不是有颜色样式
  124. if (!hasTextColor(ptClassName.value)) {
  125. style["color"] = color.value;
  126. }
  127. // 设置字体
  128. if (icon.value.font != "") {
  129. style["fontFamily"] = icon.value.font;
  130. }
  131. // 设置字体大小
  132. style["fontSize"] = getRpx(props.size!);
  133. // 设置高度
  134. style["height"] = getRpx(props.height ?? props.size!);
  135. style["lineHeight"] = getRpx(props.size!);
  136. // 设置宽度
  137. style["width"] = getRpx(props.width ?? props.size!);
  138. return style;
  139. });
  140. </script>