IconUtils.ts 3.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114
  1. import { ref } from "vue";
  2. export type IconItem = {
  3. type: 'iconfont'|'image'|'svg'|'none',
  4. value: string,
  5. rawSvg?: string,
  6. fontFamily?: string,
  7. };
  8. export type IconMap = Record<string, IconItem>;
  9. //图标集
  10. const iconMap = {} as IconMap;
  11. export const IconUtils = {
  12. iconCount: ref(0),
  13. /**
  14. * 设置 Icon 组件的图标名称映射。
  15. * 如果已存在同名数据,则会覆盖之前的。
  16. *
  17. * key是图标的名字,value 可以是以下几种情况:
  18. * * 是一个 iconfont:name 字符,则会渲染为字体形式的图标,通过 : 分割,前面是字体名称,后面是图标名称。
  19. * * 是一个 `data:***` 或者 http/https URL,则会尝试使用 Image 渲染为图片
  20. * * 是一个 `&lt;svg` 开头的字符串,会渲染为 svg
  21. * * 否则,作为默认字体 iconfont 渲染为字体形式的图标。
  22. */
  23. configIconMap(map: Record<string, string>) {
  24. for (const key in map) {
  25. let result : IconItem;
  26. const v = map[key];
  27. if (v.startsWith('http') || v.startsWith('data:') || v.startsWith('/')) {
  28. result = {
  29. type: 'image',
  30. value: v,
  31. }
  32. } else if (v.startsWith('<svg') || v.includes('<svg')) {
  33. result = {
  34. type: 'svg',
  35. rawSvg: v,
  36. value: toDataSvg(v),
  37. }
  38. } else if (v.includes(':')) {
  39. const vv = v.split(':');
  40. result = {
  41. type: 'iconfont',
  42. value: vv[1],
  43. fontFamily: vv[0],
  44. }
  45. } else {
  46. result = {
  47. type: 'iconfont',
  48. value: v,
  49. }
  50. }
  51. iconMap[key] = result;
  52. }
  53. this.iconCount.value = Object.keys(iconMap).length;
  54. },
  55. getColoredSvg(svg: string, color: string) {
  56. return toDataSvg(
  57. svg.includes('fill=') ? svg : svg.replace(/<path /g, `<path fill="${color}" `)
  58. );
  59. },
  60. /**
  61. * 获取图标名称映射集
  62. * @returns
  63. */
  64. getIconMap() {
  65. return iconMap;
  66. },
  67. /**
  68. * 从图标名称映射中获取指定名称的图标数据。
  69. * @param key 图标名称
  70. * @returns 返回图标数据,如果找不到,返回 undefined。
  71. */
  72. getIconDataFromMap(key: string) {
  73. return iconMap[key];
  74. },
  75. /**
  76. * 加载默认图标。可选从本地或者网络加载。
  77. * @param urlOrJson 图标URL或者JSON字符串
  78. */
  79. async loadDefaultIcons(urlOrJson: string | Record<string, string>) : Promise<void> {
  80. if (typeof urlOrJson === 'object') {
  81. this.configIconMap(urlOrJson);
  82. return;
  83. }
  84. if (urlOrJson.startsWith('http') || urlOrJson.startsWith('https')) {
  85. return await new Promise((resolve, reject) => {
  86. uni.request({
  87. url: urlOrJson,
  88. method: 'GET',
  89. success: (res) => {
  90. this.configIconMap(typeof res.data === 'string' ? JSON.parse(res.data) : res.data);
  91. resolve();
  92. },
  93. fail: (err) => {
  94. console.error('加载默认图标失败', err);
  95. reject(err);
  96. },
  97. });
  98. });
  99. } else {
  100. this.configIconMap(JSON.parse(urlOrJson));
  101. }
  102. },
  103. }
  104. function toDataSvg(str: string) {
  105. if (!str.includes('xmlns'))
  106. str = str.replace("<svg ", "<svg xmlns='http://www.w3.org/2000/svg' ");
  107. return `data:image/svg+xml,${encodeURIComponent(str.replace(/\'/g, '"'))}`.replace(/\#/g, '%23');
  108. }