rrj-astra-ui 1.0.4 → 1.0.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -5,16 +5,42 @@
5
5
  </template>
6
6
 
7
7
  <script setup>
8
- import { ref, computed } from 'vue';
8
+ import { ref, computed, onMounted, watch } from 'vue';
9
9
  import { camelize } from '@vue/shared';
10
10
  import * as svgFiles from '../icons/index.js';
11
- import { DOMParser, XMLSerializer } from '@xmldom/xmldom';
12
11
 
13
- const __name = 'AuiIcon';
12
+ // 核心修复:兼容 xmldom 所有版本的导入逻辑
13
+ let DOMParser, XMLSerializer;
14
+ try {
15
+ // 动态导入避免编译时导出报错,兼容 v0.x(命名导出)和 v1+/v2+(默认导出)
16
+ import('@xmldom/xmldom').then(module => {
17
+ if (module.DOMParser) {
18
+ // v0.x 命名导出
19
+ DOMParser = module.DOMParser;
20
+ XMLSerializer = module.XMLSerializer;
21
+ } else if (module.default) {
22
+ // v1+/v2+ 默认导出
23
+ DOMParser = module.default.DOMParser;
24
+ XMLSerializer = module.default.XMLSerializer;
25
+ }
26
+ // 导入完成后重新加载 SVG
27
+ loadSvg();
28
+ });
29
+ } catch (e) {
30
+ console.error('xmldom 导入失败:', e);
31
+ // 兜底:避免组件崩溃
32
+ DOMParser = function() {
33
+ this.parseFromString = () => ({
34
+ getElementsByTagName: () => [{}]
35
+ });
36
+ };
37
+ XMLSerializer = function() {
38
+ this.serializeToString = () => '';
39
+ };
40
+ }
14
41
 
15
- defineOptions({
16
- name: __name
17
- })
42
+ const __name = 'AuiIcon';
43
+ defineOptions({ name: __name });
18
44
 
19
45
  const props = defineProps({
20
46
  name: {
@@ -41,7 +67,6 @@ const props = defineProps({
41
67
  type: [String, Number],
42
68
  default: 0,
43
69
  validator: (value) => {
44
- // 允许数值角度或预设值
45
70
  return !isNaN(Number(value)) || ['90', '180', '270', 'clockwise', 'counter-clockwise'].includes(value);
46
71
  }
47
72
  }
@@ -49,97 +74,117 @@ const props = defineProps({
49
74
 
50
75
  const svgContent = ref('');
51
76
 
77
+ // 优化:封装 SVG 加载逻辑,支持 props 变化时重新加载
52
78
  const loadSvg = () => {
79
+ // 未加载完 xmldom 时跳过
80
+ if (!DOMParser || !XMLSerializer) return;
81
+
53
82
  const svg = svgFiles[props.name];
54
- if (svg) {
55
- let parser = new DOMParser();
56
- let doc = parser.parseFromString(svg, 'image/svg+xml');
57
- let svgElement = doc.getElementsByTagName('svg')[0];
83
+ if (!svg) {
84
+ console.error(`Icon "${props.name}" 不存在,请检查 icons/index.js 导出`);
85
+ svgContent.value = '';
86
+ return;
87
+ }
88
+
89
+ try {
90
+ const parser = new DOMParser();
91
+ const doc = parser.parseFromString(svg, 'image/svg+xml');
92
+ const svgElement = doc.getElementsByTagName('svg')[0];
93
+
58
94
  if (svgElement) {
59
- // 移除 SVG 根元素的 width、height、fill 和 stroke 属性
95
+ // 清除默认尺寸和颜色,统一由 props 控制
60
96
  svgElement.removeAttribute('width');
61
97
  svgElement.removeAttribute('height');
98
+ svgElement.removeAttribute('fill'); // 补充移除 fill,避免覆盖 color
62
99
  svgElement.removeAttribute('stroke');
63
100
  svgElement.setAttribute('stroke', props.color);
64
-
65
- // 递归设置所有子元素的 stroke 属性
66
- function setStrokeAttributes(element) {
101
+ svgElement.setAttribute('fill', 'currentColor'); // 统一填充色为继承
102
+
103
+ // 递归设置子元素 stroke
104
+ const setStrokeAttributes = (element) => {
105
+ if (!element || !element.hasAttribute) return;
67
106
  if (element.hasAttribute('stroke')) {
68
107
  element.removeAttribute('stroke');
69
108
  element.setAttribute('stroke', props.color);
70
109
  } else {
71
110
  element.setAttribute('stroke', 'none');
72
111
  }
73
- const children = element.childNodes;
112
+ const children = element.childNodes || [];
74
113
  for (let i = 0; i < children.length; i++) {
75
114
  if (children[i].nodeType === 1) {
76
115
  setStrokeAttributes(children[i]);
77
116
  }
78
117
  }
79
- }
118
+ };
80
119
  setStrokeAttributes(svgElement);
81
120
  }
82
- let serializer = new XMLSerializer();
83
- let processedSvg = serializer.serializeToString(doc);
84
- svgContent.value = processedSvg;
85
- } else {
86
- console.error(`Icon not found: ${props.name}`);
121
+
122
+ const serializer = new XMLSerializer();
123
+ svgContent.value = serializer.serializeToString(doc);
124
+ } catch (e) {
125
+ console.error(`处理 Icon "${props.name}" 失败:`, e);
126
+ svgContent.value = '';
87
127
  }
88
128
  };
89
129
 
90
- loadSvg();
130
+ // 监听 props 变化,重新加载 SVG(比如动态改 name/color/rotate)
131
+ watch([() => props.name, () => props.color, () => props.rotate], () => {
132
+ loadSvg();
133
+ }, { immediate: true });
91
134
 
135
+ // 样式计算(保持原有逻辑,优化可读性)
92
136
  const style = computed(() => {
93
- const width = typeof props.size === 'number' ? `${props.size}px` : props.size;
94
- const height = typeof props.size === 'number' ? `${props.size}px` : props.size;
95
-
96
- // 处理旋转逻辑
137
+ const sizeVal = typeof props.size === 'number' ? `${props.size}px` : props.size;
97
138
  let rotation = '0deg';
98
-
139
+
99
140
  if (!isNaN(Number(props.rotate))) {
100
- // 直接使用数值角度
101
141
  rotation = `${Number(props.rotate)}deg`;
102
142
  } else {
103
- // 处理预设值
104
- switch (props.rotate) {
105
- case '90':
106
- case 'clockwise':
107
- rotation = '90deg';
108
- break;
109
- case '180':
110
- rotation = '180deg';
111
- break;
112
- case '270':
113
- case 'counter-clockwise':
114
- rotation = '270deg';
115
- break;
116
- }
143
+ const rotateMap = {
144
+ '90': '90deg',
145
+ '180': '180deg',
146
+ '270': '270deg',
147
+ 'clockwise': '90deg',
148
+ 'counter-clockwise': '270deg'
149
+ };
150
+ rotation = rotateMap[props.rotate] || '0deg';
117
151
  }
118
-
152
+
119
153
  return {
120
- width,
121
- height,
154
+ width: sizeVal,
155
+ height: sizeVal,
122
156
  display: 'inline-block',
123
157
  verticalAlign: 'middle',
124
158
  transform: `rotate(${rotation})`,
125
- transition: 'transform 0.3s ease'
159
+ transition: 'transform 0.3s ease',
160
+ color: props.color // 确保 color 生效
126
161
  };
127
162
  });
128
163
 
164
+ // 类名计算(优化逻辑,兼容更多 class 类型)
129
165
  const classes = computed(() => {
130
166
  const baseClass = `icon-${camelize(props.name)}`;
131
- if (typeof props.class === 'string') {
132
- return [baseClass, props.class];
133
- }
134
- if (Array.isArray(props.class)) {
135
- return [baseClass, ...props.class];
136
- }
137
- if (typeof props.class === 'object') {
138
- return [baseClass, ...Object.keys(props.class).filter((key) => props.class[key])];
167
+ const classList = [baseClass];
168
+
169
+ if (typeof props.class === 'string' && props.class) {
170
+ classList.push(...props.class.split(' ').filter(Boolean));
171
+ } else if (Array.isArray(props.class)) {
172
+ classList.push(...props.class.filter(Boolean));
173
+ } else if (typeof props.class === 'object' && props.class !== null) {
174
+ Object.entries(props.class).forEach(([key, value]) => {
175
+ if (value) classList.push(key);
176
+ });
139
177
  }
140
- return [baseClass];
178
+
179
+ return classList;
141
180
  });
142
181
  </script>
143
182
 
144
183
  <style scoped>
184
+ /* 补充基础样式,避免 SVG 溢出 */
185
+ :deep(svg) {
186
+ width: 100%;
187
+ height: 100%;
188
+ overflow: hidden;
189
+ }
145
190
  </style>
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "rrj-astra-ui",
3
- "version": "1.0.4",
3
+ "version": "1.0.6",
4
4
  "description": "RRJ - AstraUI - A powerful UI framework for UniApp with global SCSS color variables",
5
5
  "main": "index.js",
6
6
  "keywords": [