svgIcon.vue 1.9 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798
  1. <template>
  2. <svg aria-hidden="true" class="svg-icon" :class="[className, attrs.class]" v-bind="svgAttrs">
  3. <use :xlink:href="symbolId" />
  4. </svg>
  5. </template>
  6. <script setup>
  7. import { computed, useAttrs } from "vue";
  8. defineOptions({
  9. inheritAttrs: false,
  10. });
  11. const props = defineProps({
  12. prefix: {
  13. type: String,
  14. default: "icon",
  15. },
  16. name: {
  17. type: String,
  18. required: true,
  19. },
  20. color: {
  21. type: String,
  22. default: "",
  23. },
  24. size: {
  25. type: [String, Number],
  26. default: "",
  27. },
  28. width: {
  29. type: String,
  30. default: "",
  31. },
  32. height: {
  33. type: String,
  34. default: "",
  35. },
  36. });
  37. const attrs = useAttrs();
  38. const symbolId = computed(() => `#${props.prefix}-${props.name}`);
  39. const className = computed(() => {
  40. return {
  41. [`svg-icon-${props.name}`]: !!props.name,
  42. };
  43. });
  44. const style = computed(() => {
  45. const mergedStyle = {};
  46. if (props.size) {
  47. mergedStyle.width =
  48. typeof props.size === "string" ? props.size : `${props.size}px`;
  49. mergedStyle.height = mergedStyle.width;
  50. }
  51. if (props.width && props.height) {
  52. mergedStyle.width = props.width;
  53. mergedStyle.height = props.height;
  54. }
  55. if (props.color) {
  56. mergedStyle.color = props.color;
  57. mergedStyle.fill = props.color;
  58. }
  59. const externalStyle = attrs.style;
  60. if (!externalStyle) return mergedStyle;
  61. if (Array.isArray(externalStyle)) {
  62. return externalStyle.reduce(
  63. (acc, item) => ({ ...acc, ...(item || {}) }),
  64. mergedStyle,
  65. );
  66. }
  67. if (typeof externalStyle === "object") {
  68. return { ...mergedStyle, ...externalStyle };
  69. }
  70. return mergedStyle;
  71. });
  72. const svgAttrs = computed(() => {
  73. const { class: _class, style: _style, ...rest } = attrs;
  74. return { ...rest, style: style.value };
  75. });
  76. </script>
  77. <style scoped>
  78. .svg-icon {
  79. width: 1em;
  80. height: 1em;
  81. vertical-align: -0.15em;
  82. fill: currentColor;
  83. overflow: hidden;
  84. outline: none;
  85. }
  86. .svg-icon use {
  87. pointer-events: none;
  88. }
  89. </style>