load.ts 2.0 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879
  1. import type { IconifyIconStructure } from '@vben-core/icons';
  2. import { addIcon } from '@vben-core/icons';
  3. let loaded = false;
  4. if (!loaded) {
  5. loadSvgIcons();
  6. loaded = true;
  7. }
  8. function parseSvg(svgData: string): IconifyIconStructure {
  9. const parser = new DOMParser();
  10. const xmlDoc = parser.parseFromString(svgData, 'image/svg+xml');
  11. const svgElement = xmlDoc.documentElement;
  12. // 提取 SVG 根元素的关键样式属性
  13. const getAttrs = (el: Element, attrs: string[]) =>
  14. attrs
  15. .map((attr) =>
  16. el.hasAttribute(attr) ? `${attr}="${el.getAttribute(attr)}"` : '',
  17. )
  18. .filter(Boolean)
  19. .join(' ');
  20. const rootAttrs = getAttrs(svgElement, [
  21. 'fill',
  22. 'stroke',
  23. 'fill-rule',
  24. 'stroke-width',
  25. ]);
  26. const svgContent = [...svgElement.childNodes]
  27. .filter((node) => node.nodeType === Node.ELEMENT_NODE)
  28. .map((node) => new XMLSerializer().serializeToString(node))
  29. .join('');
  30. // 若根有属性,用一个 g 标签包裹内容并继承属性
  31. const body = rootAttrs ? `<g ${rootAttrs}>${svgContent}</g>` : svgContent;
  32. const viewBoxValue = svgElement.getAttribute('viewBox') || '';
  33. const [left, top, width, height] = viewBoxValue.split(' ').map((val) => {
  34. const num = Number(val);
  35. return Number.isNaN(num) ? undefined : num;
  36. });
  37. return {
  38. body,
  39. height,
  40. left,
  41. top,
  42. width,
  43. };
  44. }
  45. /**
  46. * 自定义的svg图片转化为组件
  47. * @example ./svg/avatar.svg
  48. * <Icon icon="svg:avatar"></Icon>
  49. */
  50. async function loadSvgIcons() {
  51. const svgEagers = import.meta.glob('./icons/**', {
  52. eager: true,
  53. query: '?raw',
  54. });
  55. await Promise.all(
  56. Object.entries(svgEagers).map((svg) => {
  57. const [key, body] = svg as [string, string | { default: string }];
  58. // ./icons/xxxx.svg => xxxxxx
  59. const start = key.lastIndexOf('/') + 1;
  60. const end = key.lastIndexOf('.');
  61. const iconName = key.slice(start, end);
  62. return addIcon(`svg:${iconName}`, {
  63. ...parseSvg(typeof body === 'object' ? body.default : body),
  64. });
  65. }),
  66. );
  67. }