@eva/plugin-renderer-text 2.0.1-beta.27 → 2.0.1-beta.29

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.
@@ -60,7 +60,6 @@ var _EVA_IIFE_text = function (exports, pixi_js, eva_js, pluginRenderer, rendere
60
60
  super(...arguments);
61
61
  this.text = '';
62
62
  this.style = {};
63
- this.resolution = 1;
64
63
  }
65
64
  init(obj) {
66
65
  const style = new pixi_js.TextStyle({
@@ -77,15 +76,11 @@ var _EVA_IIFE_text = function (exports, pixi_js, eva_js, pluginRenderer, rendere
77
76
  if (obj) {
78
77
  this.text = obj.text;
79
78
  _extends(this.style, obj.style);
80
- if (obj.resolution !== undefined) {
81
- this.resolution = obj.resolution;
82
- }
83
79
  }
84
80
  }
85
81
  }
86
82
  Text$2.componentName = 'Text';
87
83
  __decorate([type('string')], Text$2.prototype, "text", void 0);
88
- __decorate([type('number')], Text$2.prototype, "resolution", void 0);
89
84
  class HTMLText extends eva_js.Component {
90
85
  constructor() {
91
86
  super(...arguments);
@@ -159,9 +154,6 @@ var _EVA_IIFE_text = function (exports, pixi_js, eva_js, pluginRenderer, rendere
159
154
  delete styleWithoutFont.fontFamily;
160
155
  const initialText = fontFamily ? '' : component.text;
161
156
  const text = new rendererAdapter.Text(initialText, styleWithoutFont);
162
- if (component.resolution !== undefined && component.resolution > 0) {
163
- text.resolution = component.resolution;
164
- }
165
157
  this.containerManager.getContainer(changed.gameObject.id).addChildAt(text, 0);
166
158
  this.texts[changed.gameObject.id] = {
167
159
  text,
@@ -223,11 +215,6 @@ var _EVA_IIFE_text = function (exports, pixi_js, eva_js, pluginRenderer, rendere
223
215
  text.text = component.text;
224
216
  } else if (changed.prop.prop[0] === 'style') {
225
217
  _extends(text.style, component.style);
226
- } else if (changed.prop.prop[0] === 'resolution' && !isHTMLText) {
227
- const textComponent = component;
228
- if (textComponent.resolution !== undefined && textComponent.resolution > 0) {
229
- text.resolution = textComponent.resolution;
230
- }
231
218
  } else if (changed.prop.prop[0] === 'textureStyle' && isHTMLText) {
232
219
  const htmlComponent = component;
233
220
  const container = this.containerManager.getContainer(changed.gameObject.id);
@@ -263,7 +250,7 @@ var _EVA_IIFE_text = function (exports, pixi_js, eva_js, pluginRenderer, rendere
263
250
  Text: ['text', {
264
251
  prop: ['style'],
265
252
  deep: true
266
- }, 'resolution'],
253
+ }],
267
254
  HTMLText: ['text', {
268
255
  prop: ['style'],
269
256
  deep: true
@@ -1 +1 @@
1
- function _extends(){return _extends=Object.assign?Object.assign.bind():function(t){for(var e=1;e<arguments.length;e++){var n=arguments[e];for(var o in n)({}).hasOwnProperty.call(n,o)&&(t[o]=n[o])}return t},_extends.apply(null,arguments)}globalThis.EVA=globalThis.EVA||{},globalThis.EVA.plugin=globalThis.EVA.plugin||{},globalThis.EVA.plugin.renderer=globalThis.EVA.plugin.renderer||{};var _EVA_IIFE_text=function(t,e,n,o,i){"use strict";function s(t,e,n,o){var i,s=arguments.length,r=s<3?e:null===o?o=Object.getOwnPropertyDescriptor(e,n):o;if("object"==typeof Reflect&&"function"==typeof Reflect.decorate)r=Reflect.decorate(t,e,n,o);else for(var l=t.length-1;l>=0;l--)(i=t[l])&&(r=(s<3?i(r):s>3?i(e,n,r):i(e,n))||r);return s>3&&r&&Object.defineProperty(e,n,r),r}function r(t,e,n,o){return new(n||(n=Promise))((function(i,s){function r(t){try{c(o.next(t))}catch(t){s(t)}}function l(t){try{c(o.throw(t))}catch(t){s(t)}}function c(t){var e;t.done?i(t.value):(e=t.value,e instanceof n?e:new n((function(t){t(e)}))).then(r,l)}c((o=o.apply(t,e||[])).next())}))}function l(t){return function(e,n){var o=function(t,e){return t.constructor.IDEProps||(t.constructor.IDEProps={}),t.constructor.IDEProps[e]||(t.constructor.IDEProps[e]={}),t.constructor.IDEProps[e]}(e,n);o.key=n,o.type=t}}class c extends n.Component{constructor(){super(...arguments),this.text="",this.style={},this.resolution=1}init(t){const n=new e.TextStyle({fontSize:20}),o={};for(const t in n)0===t.indexOf("_")&&(o[t.substring(1)]=n[t]);delete o.styleKey,this.style=o,t&&(this.text=t.text,_extends(this.style,t.style),void 0!==t.resolution&&(this.resolution=t.resolution))}}c.componentName="Text",s([l("string")],c.prototype,"text",void 0),s([l("number")],c.prototype,"resolution",void 0);class a extends n.Component{constructor(){super(...arguments),this.text="",this.style={},this.textureStyle={}}init(t){this.style=_extends({fontSize:24,fill:"#000000",fontFamily:"Arial"},null==t?void 0:t.style),this.textureStyle=_extends({scaleMode:"linear",resolution:window.devicePixelRatio||1},null==t?void 0:t.textureStyle),t&&(this.text=t.text)}}a.componentName="HTMLText",s([l("string")],a.prototype,"text",void 0);let d=class extends o.Renderer{constructor(){super(...arguments),this.name="Text",this.texts={}}init(){this.renderSystem=this.game.getSystem(o.RendererSystem),this.renderSystem.rendererManager.register(this)}componentChanged(t){return r(this,void 0,void 0,(function*(){const e="Text"===t.componentName,o="HTMLText"===t.componentName;if(e||o)if(t.type===n.OBSERVER_TYPE.ADD)e?yield this.addTextComponent(t):yield this.addHTMLTextComponent(t),this.setSize(t);else if(t.type===n.OBSERVER_TYPE.REMOVE)this.containerManager.getContainer(t.gameObject.id).removeChild(this.texts[t.gameObject.id].text),this.texts[t.gameObject.id].text.destroy({children:!0}),delete this.texts[t.gameObject.id];else{this.change(t);const e=t.component;if("style"===t.prop.prop[0]&&e.style&&e.style.fontFamily){const{text:n}=this.texts[t.gameObject.id];yield this.waitForFontResource(n,t,e.style.fontFamily)}this.setSize(t)}}))}addTextComponent(t){return r(this,void 0,void 0,(function*(){const e=t.component,n=_extends({},e.style),o=n.fontFamily;delete n.fontFamily;const s=o?"":e.text,r=new i.Text(s,n);void 0!==e.resolution&&e.resolution>0&&(r.resolution=e.resolution),this.containerManager.getContainer(t.gameObject.id).addChildAt(r,0),this.texts[t.gameObject.id]={text:r,component:e},o&&(yield this.waitForFontResource(r,t,o))}))}addHTMLTextComponent(t){return r(this,void 0,void 0,(function*(){const e=t.component,n=_extends({},e.style),o=n.fontFamily;delete n.fontFamily;const s=o?"":e.text,r=new i.HTMLText(_extends({text:s,style:n},e.textureStyle&&{textureStyle:e.textureStyle}));this.containerManager.getContainer(t.gameObject.id).addChildAt(r,0),this.texts[t.gameObject.id]={text:r,component:e},o&&(yield this.waitForFontResource(r,t,o))}))}waitForFontResource(t,e,o){return r(this,void 0,void 0,(function*(){if(o)try{const i=Array.isArray(o)?o[0]:o,s=this.increaseAsyncId(e.gameObject.id);if(yield n.resource.getResource(i),!this.validateAsyncId(e.gameObject.id,s))return;const r=this.texts[e.gameObject.id].component;t.style.fontFamily=o,t.text=r.text}catch(t){console.warn(`字体资源 ${o} 加载失败:`,t)}}))}change(t){const{text:e,component:n}=this.texts[t.gameObject.id],o="HTMLText"===t.componentName;if("text"===t.prop.prop[0])e.text=n.text;else if("style"===t.prop.prop[0])_extends(e.style,n.style);else if("resolution"!==t.prop.prop[0]||o){if("textureStyle"===t.prop.prop[0]&&o){const o=n,s=this.containerManager.getContainer(t.gameObject.id),r=s.getChildIndex(e);s.removeChild(e),e.destroy({children:!0});const l=new i.HTMLText({text:o.text,style:o.style,textureStyle:o.textureStyle});s.addChildAt(l,r),this.texts[t.gameObject.id].text=l}}else{const t=n;void 0!==t.resolution&&t.resolution>0&&(e.resolution=t.resolution)}}setSize(t){const{transform:e}=t.gameObject;if(!e)return;const{text:n}=this.texts[t.gameObject.id],o=n.getSize();e.size.width=o.width,e.size.height=o.height}};d.systemName="Text",d=s([n.decorators.componentObserver({Text:["text",{prop:["style"],deep:!0},"resolution"],HTMLText:["text",{prop:["style"],deep:!0},{prop:["textureStyle"],deep:!0}]})],d);var u=d;return t.HTMLText=a,t.Text=c,t.TextSystem=u,Object.defineProperty(t,"__esModule",{value:!0}),t}({},PIXI,EVA,EVA.plugin.renderer,EVA.rendererAdapter);globalThis.EVA.plugin.renderer.text=globalThis.EVA.plugin.renderer.text||_EVA_IIFE_text;
1
+ function _extends(){return _extends=Object.assign?Object.assign.bind():function(t){for(var e=1;e<arguments.length;e++){var n=arguments[e];for(var i in n)({}).hasOwnProperty.call(n,i)&&(t[i]=n[i])}return t},_extends.apply(null,arguments)}globalThis.EVA=globalThis.EVA||{},globalThis.EVA.plugin=globalThis.EVA.plugin||{},globalThis.EVA.plugin.renderer=globalThis.EVA.plugin.renderer||{};var _EVA_IIFE_text=function(t,e,n,i,o){"use strict";function s(t,e,n,i){var o,s=arguments.length,r=s<3?e:null===i?i=Object.getOwnPropertyDescriptor(e,n):i;if("object"==typeof Reflect&&"function"==typeof Reflect.decorate)r=Reflect.decorate(t,e,n,i);else for(var c=t.length-1;c>=0;c--)(o=t[c])&&(r=(s<3?o(r):s>3?o(e,n,r):o(e,n))||r);return s>3&&r&&Object.defineProperty(e,n,r),r}function r(t,e,n,i){return new(n||(n=Promise))((function(o,s){function r(t){try{l(i.next(t))}catch(t){s(t)}}function c(t){try{l(i.throw(t))}catch(t){s(t)}}function l(t){var e;t.done?o(t.value):(e=t.value,e instanceof n?e:new n((function(t){t(e)}))).then(r,c)}l((i=i.apply(t,e||[])).next())}))}function c(t){return function(e,n){var i=function(t,e){return t.constructor.IDEProps||(t.constructor.IDEProps={}),t.constructor.IDEProps[e]||(t.constructor.IDEProps[e]={}),t.constructor.IDEProps[e]}(e,n);i.key=n,i.type=t}}class l extends n.Component{constructor(){super(...arguments),this.text="",this.style={}}init(t){const n=new e.TextStyle({fontSize:20}),i={};for(const t in n)0===t.indexOf("_")&&(i[t.substring(1)]=n[t]);delete i.styleKey,this.style=i,t&&(this.text=t.text,_extends(this.style,t.style))}}l.componentName="Text",s([c("string")],l.prototype,"text",void 0);class a extends n.Component{constructor(){super(...arguments),this.text="",this.style={},this.textureStyle={}}init(t){this.style=_extends({fontSize:24,fill:"#000000",fontFamily:"Arial"},null==t?void 0:t.style),this.textureStyle=_extends({scaleMode:"linear",resolution:window.devicePixelRatio||1},null==t?void 0:t.textureStyle),t&&(this.text=t.text)}}a.componentName="HTMLText",s([c("string")],a.prototype,"text",void 0);let d=class extends i.Renderer{constructor(){super(...arguments),this.name="Text",this.texts={}}init(){this.renderSystem=this.game.getSystem(i.RendererSystem),this.renderSystem.rendererManager.register(this)}componentChanged(t){return r(this,void 0,void 0,(function*(){const e="Text"===t.componentName,i="HTMLText"===t.componentName;if(e||i)if(t.type===n.OBSERVER_TYPE.ADD)e?yield this.addTextComponent(t):yield this.addHTMLTextComponent(t),this.setSize(t);else if(t.type===n.OBSERVER_TYPE.REMOVE)this.containerManager.getContainer(t.gameObject.id).removeChild(this.texts[t.gameObject.id].text),this.texts[t.gameObject.id].text.destroy({children:!0}),delete this.texts[t.gameObject.id];else{this.change(t);const e=t.component;if("style"===t.prop.prop[0]&&e.style&&e.style.fontFamily){const{text:n}=this.texts[t.gameObject.id];yield this.waitForFontResource(n,t,e.style.fontFamily)}this.setSize(t)}}))}addTextComponent(t){return r(this,void 0,void 0,(function*(){const e=t.component,n=_extends({},e.style),i=n.fontFamily;delete n.fontFamily;const s=i?"":e.text,r=new o.Text(s,n);this.containerManager.getContainer(t.gameObject.id).addChildAt(r,0),this.texts[t.gameObject.id]={text:r,component:e},i&&(yield this.waitForFontResource(r,t,i))}))}addHTMLTextComponent(t){return r(this,void 0,void 0,(function*(){const e=t.component,n=_extends({},e.style),i=n.fontFamily;delete n.fontFamily;const s=i?"":e.text,r=new o.HTMLText(_extends({text:s,style:n},e.textureStyle&&{textureStyle:e.textureStyle}));this.containerManager.getContainer(t.gameObject.id).addChildAt(r,0),this.texts[t.gameObject.id]={text:r,component:e},i&&(yield this.waitForFontResource(r,t,i))}))}waitForFontResource(t,e,i){return r(this,void 0,void 0,(function*(){if(i)try{const o=Array.isArray(i)?i[0]:i,s=this.increaseAsyncId(e.gameObject.id);if(yield n.resource.getResource(o),!this.validateAsyncId(e.gameObject.id,s))return;const r=this.texts[e.gameObject.id].component;t.style.fontFamily=i,t.text=r.text}catch(t){console.warn(`字体资源 ${i} 加载失败:`,t)}}))}change(t){const{text:e,component:n}=this.texts[t.gameObject.id],i="HTMLText"===t.componentName;if("text"===t.prop.prop[0])e.text=n.text;else if("style"===t.prop.prop[0])_extends(e.style,n.style);else if("textureStyle"===t.prop.prop[0]&&i){const i=n,s=this.containerManager.getContainer(t.gameObject.id),r=s.getChildIndex(e);s.removeChild(e),e.destroy({children:!0});const c=new o.HTMLText({text:i.text,style:i.style,textureStyle:i.textureStyle});s.addChildAt(c,r),this.texts[t.gameObject.id].text=c}}setSize(t){const{transform:e}=t.gameObject;if(!e)return;const{text:n}=this.texts[t.gameObject.id],i=n.getSize();e.size.width=i.width,e.size.height=i.height}};d.systemName="Text",d=s([n.decorators.componentObserver({Text:["text",{prop:["style"],deep:!0}],HTMLText:["text",{prop:["style"],deep:!0},{prop:["textureStyle"],deep:!0}]})],d);var x=d;return t.HTMLText=a,t.Text=l,t.TextSystem=x,Object.defineProperty(t,"__esModule",{value:!0}),t}({},PIXI,EVA,EVA.plugin.renderer,EVA.rendererAdapter);globalThis.EVA.plugin.renderer.text=globalThis.EVA.plugin.renderer.text||_EVA_IIFE_text;
@@ -39,13 +39,63 @@ function __awaiter(thisArg, _arguments, P, generator) {
39
39
  });
40
40
  }
41
41
 
42
+ /**
43
+ * 文本组件(基于 PixiJS Text)
44
+ *
45
+ * Text 组件用于渲染文本内容,支持丰富的文本样式配置。
46
+ * 它基于 PixiJS 的 Text 实现,支持字体、颜色、描边、阴影、对齐等多种样式。
47
+ *
48
+ * 主要特性:
49
+ * - 支持多种字体和字号
50
+ * - 支持文本颜色、渐变填充
51
+ * - 支持描边和投影效果
52
+ * - 支持文本对齐和换行
53
+ *
54
+ * @example
55
+ * ```typescript
56
+ * // 基础文本
57
+ * const label = new GameObject('label');
58
+ * label.addComponent(new Text({
59
+ * text: 'Hello EVA!',
60
+ * style: {
61
+ * fontSize: 32,
62
+ * fill: 0xffffff
63
+ * }
64
+ * }));
65
+ *
66
+ * // 带样式的文本
67
+ * label.addComponent(new Text({
68
+ * text: '得分: 9999',
69
+ * style: {
70
+ * fontFamily: 'Arial',
71
+ * fontSize: 48,
72
+ * fontWeight: 'bold',
73
+ * fill: ['#ff0000', '#ffff00'], // 渐变色
74
+ * stroke: '#000000',
75
+ * strokeThickness: 4,
76
+ * dropShadow: true,
77
+ * dropShadowDistance: 3
78
+ * }
79
+ * }));
80
+ * // 如需高清渲染,使用 Render 组件的 resolution 属性
81
+ * label.addComponent(new Render({ resolution: 2 }));
82
+ * ```
83
+ */
42
84
  class Text$2 extends eva_js.Component {
43
85
  constructor() {
44
86
  super(...arguments);
87
+ /** 文本内容 */
45
88
  this.text = '';
89
+ /** 文本样式配置 */
90
+ // @decorators.IDEProp 复杂编辑后续添加
46
91
  this.style = {};
47
- this.resolution = 1;
48
92
  }
93
+ /**
94
+ * 初始化组件
95
+ * @param obj - 初始化参数
96
+ * @param obj.text - 文本内容
97
+ * @param obj.style - 文本样式
98
+ */
49
99
  init(obj) {
50
100
  const style = new pixi_js.TextStyle({
51
101
  fontSize: 20,
@@ -61,27 +111,93 @@ class Text$2 extends eva_js.Component {
61
111
  if (obj) {
62
112
  this.text = obj.text;
63
113
  Object.assign(this.style, obj.style);
64
- if (obj.resolution !== undefined) {
65
- this.resolution = obj.resolution;
66
- }
67
114
  }
68
115
  }
69
116
  }
117
+ /** 组件名称 */
70
118
  Text$2.componentName = 'Text';
71
119
  __decorate([
72
120
  inspectorDecorator.type('string')
73
- ], Text$2.prototype, "text", void 0);
74
- __decorate([
75
- inspectorDecorator.type('number')
76
- ], Text$2.prototype, "resolution", void 0);
121
+ ], Text$2.prototype, "text", void 0);
77
122
 
123
+ /**
124
+ * HTML 富文本组件
125
+ *
126
+ * HTMLText 组件支持渲染带有 HTML 标签的富文本内容。
127
+ * 可以在文本中使用 HTML 标签(如 `<b>`, `<i>`, `<span>` 等)来实现丰富的文本样式,
128
+ * 适用于聊天对话、新闻内容、富文本显示等需要多样式文本的场景。
129
+ *
130
+ * 支持的 HTML 标签:
131
+ * - `<b>` - 粗体
132
+ * - `<i>` - 斜体
133
+ * - `<span style="color:#ff0000">` - 自定义样式
134
+ * - `<br>` - 换行
135
+ * 以及更多标准 HTML 文本标签
136
+ *
137
+ * @example
138
+ * ```typescript
139
+ * // 基础富文本
140
+ * const label = new GameObject('label');
141
+ * label.addComponent(new HTMLText({
142
+ * text: '这是<b>粗体</b>和<i>斜体</i>文本',
143
+ * style: {
144
+ * fontSize: 24,
145
+ * fill: '#000000',
146
+ * fontFamily: 'Arial'
147
+ * }
148
+ * }));
149
+ *
150
+ * // 带颜色的富文本
151
+ * label.addComponent(new HTMLText({
152
+ * text: '欢迎 <span style="color:#ff0000">玩家123</span> 加入游戏!',
153
+ * style: {
154
+ * fontSize: 20,
155
+ * wordWrap: true,
156
+ * wordWrapWidth: 300
157
+ * }
158
+ * }));
159
+ *
160
+ * // 自定义标签样式
161
+ * label.addComponent(new HTMLText({
162
+ * text: '获得 <gold>100</gold> 金币',
163
+ * style: {
164
+ * fontSize: 18,
165
+ * tagStyles: {
166
+ * gold: {
167
+ * fill: '#ffd700',
168
+ * fontWeight: 'bold'
169
+ * }
170
+ * }
171
+ * }
172
+ * }));
173
+ *
174
+ * // 高分辨率渲染(推荐使用 Render 组件的 resolution 属性)
175
+ * label.addComponent(new HTMLText({
176
+ * text: '高清文本',
177
+ * textureStyle: {
178
+ * scaleMode: 'linear'
179
+ * }
180
+ * }));
181
+ * label.addComponent(new Render({ resolution: 2 }));
182
+ * ```
183
+ */
78
184
  class HTMLText extends eva_js.Component {
79
185
  constructor() {
80
186
  super(...arguments);
187
+ /** 富文本内容(支持 HTML 标签) */
81
188
  this.text = '';
189
+ /** 文本样式配置 */
82
190
  this.style = {};
191
+ /** 纹理渲染配置 */
83
192
  this.textureStyle = {};
84
193
  }
194
+ /**
195
+ * 初始化组件
196
+ * @param obj - 初始化参数
197
+ * @param obj.text - 富文本内容
198
+ * @param obj.style - 文本样式
199
+ * @param obj.textureStyle - 纹理配置
200
+ */
85
201
  init(obj) {
86
202
  this.style = Object.assign({ fontSize: 24, fill: '#000000', fontFamily: 'Arial' }, obj === null || obj === void 0 ? void 0 : obj.style);
87
203
  this.textureStyle = Object.assign({ scaleMode: 'linear', resolution: window.devicePixelRatio || 1 }, obj === null || obj === void 0 ? void 0 : obj.textureStyle);
@@ -90,6 +206,7 @@ class HTMLText extends eva_js.Component {
90
206
  }
91
207
  }
92
208
  }
209
+ /** 组件名称 */
93
210
  HTMLText.componentName = 'HTMLText';
94
211
  __decorate([
95
212
  inspectorDecorator.type('string')
@@ -127,6 +244,7 @@ let Text = class Text extends pluginRenderer.Renderer {
127
244
  }
128
245
  else {
129
246
  this.change(changed);
247
+ // 如果样式改变且涉及字体,也需要等待字体资源加载
130
248
  const component = changed.component;
131
249
  if (changed.prop.prop[0] === 'style' && component.style && component.style.fontFamily) {
132
250
  const { text } = this.texts[changed.gameObject.id];
@@ -139,19 +257,18 @@ let Text = class Text extends pluginRenderer.Renderer {
139
257
  addTextComponent(changed) {
140
258
  return __awaiter(this, void 0, void 0, function* () {
141
259
  const component = changed.component;
260
+ // 创建文本样式副本,先不设置 fontFamily
142
261
  const styleWithoutFont = Object.assign({}, component.style);
143
262
  const fontFamily = styleWithoutFont.fontFamily;
144
263
  delete styleWithoutFont.fontFamily;
145
264
  const initialText = fontFamily ? '' : component.text;
146
265
  const text = new rendererAdapter.Text(initialText, styleWithoutFont);
147
- if (component.resolution !== undefined && component.resolution > 0) {
148
- text.resolution = component.resolution;
149
- }
150
266
  this.containerManager.getContainer(changed.gameObject.id).addChildAt(text, 0);
151
267
  this.texts[changed.gameObject.id] = {
152
268
  text,
153
269
  component,
154
270
  };
271
+ // 如果指定了字体资源,等待资源加载完成后设置 fontFamily
155
272
  if (fontFamily) {
156
273
  yield this.waitForFontResource(text, changed, fontFamily);
157
274
  }
@@ -160,6 +277,7 @@ let Text = class Text extends pluginRenderer.Renderer {
160
277
  addHTMLTextComponent(changed) {
161
278
  return __awaiter(this, void 0, void 0, function* () {
162
279
  const component = changed.component;
280
+ // 创建样式副本,先不设置 fontFamily
163
281
  const styleWithoutFont = Object.assign({}, component.style);
164
282
  const fontFamily = styleWithoutFont.fontFamily;
165
283
  delete styleWithoutFont.fontFamily;
@@ -170,11 +288,15 @@ let Text = class Text extends pluginRenderer.Renderer {
170
288
  text: htmlText,
171
289
  component,
172
290
  };
291
+ // 如果指定了字体资源,等待资源加载完成后设置 fontFamily
173
292
  if (fontFamily) {
174
293
  yield this.waitForFontResource(htmlText, changed, fontFamily);
175
294
  }
176
295
  });
177
296
  }
297
+ /**
298
+ * 等待字体资源加载完成并更新文本
299
+ */
178
300
  waitForFontResource(text, changed, fontFamily) {
179
301
  return __awaiter(this, void 0, void 0, function* () {
180
302
  if (!fontFamily) {
@@ -182,13 +304,17 @@ let Text = class Text extends pluginRenderer.Renderer {
182
304
  }
183
305
  try {
184
306
  const fontName = Array.isArray(fontFamily) ? fontFamily[0] : fontFamily;
307
+ // 通过 resource 系统获取字体资源
185
308
  const asyncId = this.increaseAsyncId(changed.gameObject.id);
186
309
  yield eva_js.resource.getResource(fontName);
310
+ // 验证异步操作是否仍然有效(防止组件已被移除)
187
311
  if (!this.validateAsyncId(changed.gameObject.id, asyncId))
188
312
  return;
313
+ // 字体资源加载成功后,设置 fontFamily 并重新设置文本内容以触发重新渲染
189
314
  const component = this.texts[changed.gameObject.id].component;
190
315
  text.style.fontFamily = fontFamily;
191
316
  text.text = component.text;
317
+ // 更新尺寸
192
318
  }
193
319
  catch (error) {
194
320
  console.warn(`字体资源 ${fontFamily} 加载失败:`, error);
@@ -204,13 +330,8 @@ let Text = class Text extends pluginRenderer.Renderer {
204
330
  else if (changed.prop.prop[0] === 'style') {
205
331
  Object.assign(text.style, component.style);
206
332
  }
207
- else if (changed.prop.prop[0] === 'resolution' && !isHTMLText) {
208
- const textComponent = component;
209
- if (textComponent.resolution !== undefined && textComponent.resolution > 0) {
210
- text.resolution = textComponent.resolution;
211
- }
212
- }
213
333
  else if (changed.prop.prop[0] === 'textureStyle' && isHTMLText) {
334
+ // HTMLText 纹理样式变化需要重新创建
214
335
  const htmlComponent = component;
215
336
  const container = this.containerManager.getContainer(changed.gameObject.id);
216
337
  const index = container.getChildIndex(text);
@@ -238,7 +359,7 @@ let Text = class Text extends pluginRenderer.Renderer {
238
359
  Text.systemName = 'Text';
239
360
  Text = __decorate([
240
361
  eva_js.decorators.componentObserver({
241
- Text: ['text', { prop: ['style'], deep: true }, 'resolution'],
362
+ Text: ['text', { prop: ['style'], deep: true }],
242
363
  HTMLText: ['text', { prop: ['style'], deep: true }, { prop: ['textureStyle'], deep: true }],
243
364
  })
244
365
  ], Text);
@@ -1,4 +1,4 @@
1
- "use strict";Object.defineProperty(exports,"__esModule",{value:!0});var e=require("pixi.js"),t=require("@eva/eva.js"),i=require("@eva/inspector-decorator"),o=require("@eva/plugin-renderer"),n=require("@eva/renderer-adapter");
1
+ "use strict";Object.defineProperty(exports,"__esModule",{value:!0});var e=require("pixi.js"),t=require("@eva/eva.js"),n=require("@eva/inspector-decorator"),i=require("@eva/plugin-renderer"),s=require("@eva/renderer-adapter");
2
2
  /*! *****************************************************************************
3
3
  Copyright (c) Microsoft Corporation. All rights reserved.
4
4
  Licensed under the Apache License, Version 2.0 (the "License"); you may not use
@@ -13,4 +13,4 @@ MERCHANTABLITY OR NON-INFRINGEMENT.
13
13
  See the Apache Version 2.0 License for specific language governing permissions
14
14
  and limitations under the License.
15
15
  ***************************************************************************** */
16
- function s(e,t,i,o){var n,s=arguments.length,r=s<3?t:null===o?o=Object.getOwnPropertyDescriptor(t,i):o;if("object"==typeof Reflect&&"function"==typeof Reflect.decorate)r=Reflect.decorate(e,t,i,o);else for(var c=e.length-1;c>=0;c--)(n=e[c])&&(r=(s<3?n(r):s>3?n(t,i,r):n(t,i))||r);return s>3&&r&&Object.defineProperty(t,i,r),r}function r(e,t,i,o){return new(i||(i=Promise))((function(n,s){function r(e){try{l(o.next(e))}catch(e){s(e)}}function c(e){try{l(o.throw(e))}catch(e){s(e)}}function l(e){e.done?n(e.value):new i((function(t){t(e.value)})).then(r,c)}l((o=o.apply(e,t||[])).next())}))}class c extends t.Component{constructor(){super(...arguments),this.text="",this.style={},this.resolution=1}init(t){const i=new e.TextStyle({fontSize:20}),o={};for(const e in i)0===e.indexOf("_")&&(o[e.substring(1)]=i[e]);delete o.styleKey,this.style=o,t&&(this.text=t.text,Object.assign(this.style,t.style),void 0!==t.resolution&&(this.resolution=t.resolution))}}c.componentName="Text",s([i.type("string")],c.prototype,"text",void 0),s([i.type("number")],c.prototype,"resolution",void 0);class l extends t.Component{constructor(){super(...arguments),this.text="",this.style={},this.textureStyle={}}init(e){this.style=Object.assign({fontSize:24,fill:"#000000",fontFamily:"Arial"},null==e?void 0:e.style),this.textureStyle=Object.assign({scaleMode:"linear",resolution:window.devicePixelRatio||1},null==e?void 0:e.textureStyle),e&&(this.text=e.text)}}l.componentName="HTMLText",s([i.type("string")],l.prototype,"text",void 0);let a=class extends o.Renderer{constructor(){super(...arguments),this.name="Text",this.texts={}}init(){this.renderSystem=this.game.getSystem(o.RendererSystem),this.renderSystem.rendererManager.register(this)}componentChanged(e){return r(this,void 0,void 0,(function*(){const i="Text"===e.componentName,o="HTMLText"===e.componentName;if(i||o)if(e.type===t.OBSERVER_TYPE.ADD)i?yield this.addTextComponent(e):yield this.addHTMLTextComponent(e),this.setSize(e);else if(e.type===t.OBSERVER_TYPE.REMOVE)this.containerManager.getContainer(e.gameObject.id).removeChild(this.texts[e.gameObject.id].text),this.texts[e.gameObject.id].text.destroy({children:!0}),delete this.texts[e.gameObject.id];else{this.change(e);const t=e.component;if("style"===e.prop.prop[0]&&t.style&&t.style.fontFamily){const{text:i}=this.texts[e.gameObject.id];yield this.waitForFontResource(i,e,t.style.fontFamily)}this.setSize(e)}}))}addTextComponent(e){return r(this,void 0,void 0,(function*(){const t=e.component,i=Object.assign({},t.style),o=i.fontFamily;delete i.fontFamily;const s=o?"":t.text,r=new n.Text(s,i);void 0!==t.resolution&&t.resolution>0&&(r.resolution=t.resolution),this.containerManager.getContainer(e.gameObject.id).addChildAt(r,0),this.texts[e.gameObject.id]={text:r,component:t},o&&(yield this.waitForFontResource(r,e,o))}))}addHTMLTextComponent(e){return r(this,void 0,void 0,(function*(){const t=e.component,i=Object.assign({},t.style),o=i.fontFamily;delete i.fontFamily;const s=o?"":t.text,r=new n.HTMLText(Object.assign({text:s,style:i},t.textureStyle&&{textureStyle:t.textureStyle}));this.containerManager.getContainer(e.gameObject.id).addChildAt(r,0),this.texts[e.gameObject.id]={text:r,component:t},o&&(yield this.waitForFontResource(r,e,o))}))}waitForFontResource(e,i,o){return r(this,void 0,void 0,(function*(){if(o)try{const n=Array.isArray(o)?o[0]:o,s=this.increaseAsyncId(i.gameObject.id);if(yield t.resource.getResource(n),!this.validateAsyncId(i.gameObject.id,s))return;const r=this.texts[i.gameObject.id].component;e.style.fontFamily=o,e.text=r.text}catch(e){console.warn(`字体资源 ${o} 加载失败:`,e)}}))}change(e){const{text:t,component:i}=this.texts[e.gameObject.id],o="HTMLText"===e.componentName;if("text"===e.prop.prop[0])t.text=i.text;else if("style"===e.prop.prop[0])Object.assign(t.style,i.style);else if("resolution"!==e.prop.prop[0]||o){if("textureStyle"===e.prop.prop[0]&&o){const o=i,s=this.containerManager.getContainer(e.gameObject.id),r=s.getChildIndex(t);s.removeChild(t),t.destroy({children:!0});const c=new n.HTMLText({text:o.text,style:o.style,textureStyle:o.textureStyle});s.addChildAt(c,r),this.texts[e.gameObject.id].text=c}}else{const e=i;void 0!==e.resolution&&e.resolution>0&&(t.resolution=e.resolution)}}setSize(e){const{transform:t}=e.gameObject;if(!t)return;const{text:i}=this.texts[e.gameObject.id],o=i.getSize();t.size.width=o.width,t.size.height=o.height}};a.systemName="Text",a=s([t.decorators.componentObserver({Text:["text",{prop:["style"],deep:!0},"resolution"],HTMLText:["text",{prop:["style"],deep:!0},{prop:["textureStyle"],deep:!0}]})],a);var d=a;exports.HTMLText=l,exports.Text=c,exports.TextSystem=d;
16
+ function o(e,t,n,i){var s,o=arguments.length,r=o<3?t:null===i?i=Object.getOwnPropertyDescriptor(t,n):i;if("object"==typeof Reflect&&"function"==typeof Reflect.decorate)r=Reflect.decorate(e,t,n,i);else for(var c=e.length-1;c>=0;c--)(s=e[c])&&(r=(o<3?s(r):o>3?s(t,n,r):s(t,n))||r);return o>3&&r&&Object.defineProperty(t,n,r),r}function r(e,t,n,i){return new(n||(n=Promise))((function(s,o){function r(e){try{a(i.next(e))}catch(e){o(e)}}function c(e){try{a(i.throw(e))}catch(e){o(e)}}function a(e){e.done?s(e.value):new n((function(t){t(e.value)})).then(r,c)}a((i=i.apply(e,t||[])).next())}))}class c extends t.Component{constructor(){super(...arguments),this.text="",this.style={}}init(t){const n=new e.TextStyle({fontSize:20}),i={};for(const e in n)0===e.indexOf("_")&&(i[e.substring(1)]=n[e]);delete i.styleKey,this.style=i,t&&(this.text=t.text,Object.assign(this.style,t.style))}}c.componentName="Text",o([n.type("string")],c.prototype,"text",void 0);class a extends t.Component{constructor(){super(...arguments),this.text="",this.style={},this.textureStyle={}}init(e){this.style=Object.assign({fontSize:24,fill:"#000000",fontFamily:"Arial"},null==e?void 0:e.style),this.textureStyle=Object.assign({scaleMode:"linear",resolution:window.devicePixelRatio||1},null==e?void 0:e.textureStyle),e&&(this.text=e.text)}}a.componentName="HTMLText",o([n.type("string")],a.prototype,"text",void 0);let d=class extends i.Renderer{constructor(){super(...arguments),this.name="Text",this.texts={}}init(){this.renderSystem=this.game.getSystem(i.RendererSystem),this.renderSystem.rendererManager.register(this)}componentChanged(e){return r(this,void 0,void 0,(function*(){const n="Text"===e.componentName,i="HTMLText"===e.componentName;if(n||i)if(e.type===t.OBSERVER_TYPE.ADD)n?yield this.addTextComponent(e):yield this.addHTMLTextComponent(e),this.setSize(e);else if(e.type===t.OBSERVER_TYPE.REMOVE)this.containerManager.getContainer(e.gameObject.id).removeChild(this.texts[e.gameObject.id].text),this.texts[e.gameObject.id].text.destroy({children:!0}),delete this.texts[e.gameObject.id];else{this.change(e);const t=e.component;if("style"===e.prop.prop[0]&&t.style&&t.style.fontFamily){const{text:n}=this.texts[e.gameObject.id];yield this.waitForFontResource(n,e,t.style.fontFamily)}this.setSize(e)}}))}addTextComponent(e){return r(this,void 0,void 0,(function*(){const t=e.component,n=Object.assign({},t.style),i=n.fontFamily;delete n.fontFamily;const o=i?"":t.text,r=new s.Text(o,n);this.containerManager.getContainer(e.gameObject.id).addChildAt(r,0),this.texts[e.gameObject.id]={text:r,component:t},i&&(yield this.waitForFontResource(r,e,i))}))}addHTMLTextComponent(e){return r(this,void 0,void 0,(function*(){const t=e.component,n=Object.assign({},t.style),i=n.fontFamily;delete n.fontFamily;const o=i?"":t.text,r=new s.HTMLText(Object.assign({text:o,style:n},t.textureStyle&&{textureStyle:t.textureStyle}));this.containerManager.getContainer(e.gameObject.id).addChildAt(r,0),this.texts[e.gameObject.id]={text:r,component:t},i&&(yield this.waitForFontResource(r,e,i))}))}waitForFontResource(e,n,i){return r(this,void 0,void 0,(function*(){if(i)try{const s=Array.isArray(i)?i[0]:i,o=this.increaseAsyncId(n.gameObject.id);if(yield t.resource.getResource(s),!this.validateAsyncId(n.gameObject.id,o))return;const r=this.texts[n.gameObject.id].component;e.style.fontFamily=i,e.text=r.text}catch(e){console.warn(`字体资源 ${i} 加载失败:`,e)}}))}change(e){const{text:t,component:n}=this.texts[e.gameObject.id],i="HTMLText"===e.componentName;if("text"===e.prop.prop[0])t.text=n.text;else if("style"===e.prop.prop[0])Object.assign(t.style,n.style);else if("textureStyle"===e.prop.prop[0]&&i){const i=n,o=this.containerManager.getContainer(e.gameObject.id),r=o.getChildIndex(t);o.removeChild(t),t.destroy({children:!0});const c=new s.HTMLText({text:i.text,style:i.style,textureStyle:i.textureStyle});o.addChildAt(c,r),this.texts[e.gameObject.id].text=c}}setSize(e){const{transform:t}=e.gameObject;if(!t)return;const{text:n}=this.texts[e.gameObject.id],i=n.getSize();t.size.width=i.width,t.size.height=i.height}};d.systemName="Text",d=o([t.decorators.componentObserver({Text:["text",{prop:["style"],deep:!0}],HTMLText:["text",{prop:["style"],deep:!0},{prop:["textureStyle"],deep:!0}]})],d);var l=d;exports.HTMLText=a,exports.Text=c,exports.TextSystem=l;
@@ -13,11 +13,83 @@ import { TextStyleFontWeight } from 'pixi.js';
13
13
  import { TextStyleTextBaseline } from 'pixi.js';
14
14
  import { TextStyleWhiteSpace } from 'pixi.js';
15
15
 
16
+ /**
17
+ * HTML 富文本组件
18
+ *
19
+ * HTMLText 组件支持渲染带有 HTML 标签的富文本内容。
20
+ * 可以在文本中使用 HTML 标签(如 `<b>`, `<i>`, `<span>` 等)来实现丰富的文本样式,
21
+ * 适用于聊天对话、新闻内容、富文本显示等需要多样式文本的场景。
22
+ *
23
+ * 支持的 HTML 标签:
24
+ * - `<b>` - 粗体
25
+ * - `<i>` - 斜体
26
+ * - `<span style="color:#ff0000">` - 自定义样式
27
+ * - `<br>` - 换行
28
+ * 以及更多标准 HTML 文本标签
29
+ *
30
+ * @example
31
+ * ```typescript
32
+ * // 基础富文本
33
+ * const label = new GameObject('label');
34
+ * label.addComponent(new HTMLText({
35
+ * text: '这是<b>粗体</b>和<i>斜体</i>文本',
36
+ * style: {
37
+ * fontSize: 24,
38
+ * fill: '#000000',
39
+ * fontFamily: 'Arial'
40
+ * }
41
+ * }));
42
+ *
43
+ * // 带颜色的富文本
44
+ * label.addComponent(new HTMLText({
45
+ * text: '欢迎 <span style="color:#ff0000">玩家123</span> 加入游戏!',
46
+ * style: {
47
+ * fontSize: 20,
48
+ * wordWrap: true,
49
+ * wordWrapWidth: 300
50
+ * }
51
+ * }));
52
+ *
53
+ * // 自定义标签样式
54
+ * label.addComponent(new HTMLText({
55
+ * text: '获得 <gold>100</gold> 金币',
56
+ * style: {
57
+ * fontSize: 18,
58
+ * tagStyles: {
59
+ * gold: {
60
+ * fill: '#ffd700',
61
+ * fontWeight: 'bold'
62
+ * }
63
+ * }
64
+ * }
65
+ * }));
66
+ *
67
+ * // 高分辨率渲染(推荐使用 Render 组件的 resolution 属性)
68
+ * label.addComponent(new HTMLText({
69
+ * text: '高清文本',
70
+ * textureStyle: {
71
+ * scaleMode: 'linear'
72
+ * }
73
+ * }));
74
+ * label.addComponent(new Render({ resolution: 2 }));
75
+ * ```
76
+ */
16
77
  export declare class HTMLText extends Component<HTMLTextParams> {
78
+ /** 组件名称 */
17
79
  static componentName: string;
80
+ /** 富文本内容(支持 HTML 标签) */
18
81
  text: string;
82
+ /** 文本样式配置 */
19
83
  style: HTMLTextParams['style'];
84
+ /** 纹理渲染配置 */
20
85
  textureStyle: HTMLTextParams['textureStyle'];
86
+ /**
87
+ * 初始化组件
88
+ * @param obj - 初始化参数
89
+ * @param obj.text - 富文本内容
90
+ * @param obj.style - 文本样式
91
+ * @param obj.textureStyle - 纹理配置
92
+ */
21
93
  init(obj?: HTMLTextParams): void;
22
94
  }
23
95
 
@@ -60,11 +132,61 @@ declare interface HTMLTextStyleOptions {
60
132
  whiteSpace?: string;
61
133
  }
62
134
 
135
+ /**
136
+ * 文本组件(基于 PixiJS Text)
137
+ *
138
+ * Text 组件用于渲染文本内容,支持丰富的文本样式配置。
139
+ * 它基于 PixiJS 的 Text 实现,支持字体、颜色、描边、阴影、对齐等多种样式。
140
+ *
141
+ * 主要特性:
142
+ * - 支持多种字体和字号
143
+ * - 支持文本颜色、渐变填充
144
+ * - 支持描边和投影效果
145
+ * - 支持文本对齐和换行
146
+ *
147
+ * @example
148
+ * ```typescript
149
+ * // 基础文本
150
+ * const label = new GameObject('label');
151
+ * label.addComponent(new Text({
152
+ * text: 'Hello EVA!',
153
+ * style: {
154
+ * fontSize: 32,
155
+ * fill: 0xffffff
156
+ * }
157
+ * }));
158
+ *
159
+ * // 带样式的文本
160
+ * label.addComponent(new Text({
161
+ * text: '得分: 9999',
162
+ * style: {
163
+ * fontFamily: 'Arial',
164
+ * fontSize: 48,
165
+ * fontWeight: 'bold',
166
+ * fill: ['#ff0000', '#ffff00'], // 渐变色
167
+ * stroke: '#000000',
168
+ * strokeThickness: 4,
169
+ * dropShadow: true,
170
+ * dropShadowDistance: 3
171
+ * }
172
+ * }));
173
+ * // 如需高清渲染,使用 Render 组件的 resolution 属性
174
+ * label.addComponent(new Render({ resolution: 2 }));
175
+ * ```
176
+ */
63
177
  declare class Text_2 extends Component<TextParams> {
178
+ /** 组件名称 */
64
179
  static componentName: string;
180
+ /** 文本内容 */
65
181
  text: string;
182
+ /** 文本样式配置 */
66
183
  style: TextParams['style'];
67
- resolution: number;
184
+ /**
185
+ * 初始化组件
186
+ * @param obj - 初始化参数
187
+ * @param obj.text - 文本内容
188
+ * @param obj.style - 文本样式
189
+ */
68
190
  init(obj?: TextParams): void;
69
191
  }
70
192
  export { Text_2 as Text }
@@ -102,7 +224,6 @@ export declare interface TextParams {
102
224
  wordWrapWidth?: number;
103
225
  leading?: number;
104
226
  };
105
- resolution?: number;
106
227
  }
107
228
 
108
229
  export declare class TextSystem extends Renderer {
@@ -121,6 +242,9 @@ export declare class TextSystem extends Renderer {
121
242
  componentChanged(changed: ComponentChanged): Promise<void>;
122
243
  private addTextComponent;
123
244
  private addHTMLTextComponent;
245
+ /**
246
+ * 等待字体资源加载完成并更新文本
247
+ */
124
248
  private waitForFontResource;
125
249
  change(changed: ComponentChanged): void;
126
250
  setSize(changed: ComponentChanged): void;
@@ -35,13 +35,63 @@ function __awaiter(thisArg, _arguments, P, generator) {
35
35
  });
36
36
  }
37
37
 
38
+ /**
39
+ * 文本组件(基于 PixiJS Text)
40
+ *
41
+ * Text 组件用于渲染文本内容,支持丰富的文本样式配置。
42
+ * 它基于 PixiJS 的 Text 实现,支持字体、颜色、描边、阴影、对齐等多种样式。
43
+ *
44
+ * 主要特性:
45
+ * - 支持多种字体和字号
46
+ * - 支持文本颜色、渐变填充
47
+ * - 支持描边和投影效果
48
+ * - 支持文本对齐和换行
49
+ *
50
+ * @example
51
+ * ```typescript
52
+ * // 基础文本
53
+ * const label = new GameObject('label');
54
+ * label.addComponent(new Text({
55
+ * text: 'Hello EVA!',
56
+ * style: {
57
+ * fontSize: 32,
58
+ * fill: 0xffffff
59
+ * }
60
+ * }));
61
+ *
62
+ * // 带样式的文本
63
+ * label.addComponent(new Text({
64
+ * text: '得分: 9999',
65
+ * style: {
66
+ * fontFamily: 'Arial',
67
+ * fontSize: 48,
68
+ * fontWeight: 'bold',
69
+ * fill: ['#ff0000', '#ffff00'], // 渐变色
70
+ * stroke: '#000000',
71
+ * strokeThickness: 4,
72
+ * dropShadow: true,
73
+ * dropShadowDistance: 3
74
+ * }
75
+ * }));
76
+ * // 如需高清渲染,使用 Render 组件的 resolution 属性
77
+ * label.addComponent(new Render({ resolution: 2 }));
78
+ * ```
79
+ */
38
80
  class Text$2 extends Component {
39
81
  constructor() {
40
82
  super(...arguments);
83
+ /** 文本内容 */
41
84
  this.text = '';
85
+ /** 文本样式配置 */
86
+ // @decorators.IDEProp 复杂编辑后续添加
42
87
  this.style = {};
43
- this.resolution = 1;
44
88
  }
89
+ /**
90
+ * 初始化组件
91
+ * @param obj - 初始化参数
92
+ * @param obj.text - 文本内容
93
+ * @param obj.style - 文本样式
94
+ */
45
95
  init(obj) {
46
96
  const style = new TextStyle({
47
97
  fontSize: 20,
@@ -57,27 +107,93 @@ class Text$2 extends Component {
57
107
  if (obj) {
58
108
  this.text = obj.text;
59
109
  Object.assign(this.style, obj.style);
60
- if (obj.resolution !== undefined) {
61
- this.resolution = obj.resolution;
62
- }
63
110
  }
64
111
  }
65
112
  }
113
+ /** 组件名称 */
66
114
  Text$2.componentName = 'Text';
67
115
  __decorate([
68
116
  type('string')
69
- ], Text$2.prototype, "text", void 0);
70
- __decorate([
71
- type('number')
72
- ], Text$2.prototype, "resolution", void 0);
117
+ ], Text$2.prototype, "text", void 0);
73
118
 
119
+ /**
120
+ * HTML 富文本组件
121
+ *
122
+ * HTMLText 组件支持渲染带有 HTML 标签的富文本内容。
123
+ * 可以在文本中使用 HTML 标签(如 `<b>`, `<i>`, `<span>` 等)来实现丰富的文本样式,
124
+ * 适用于聊天对话、新闻内容、富文本显示等需要多样式文本的场景。
125
+ *
126
+ * 支持的 HTML 标签:
127
+ * - `<b>` - 粗体
128
+ * - `<i>` - 斜体
129
+ * - `<span style="color:#ff0000">` - 自定义样式
130
+ * - `<br>` - 换行
131
+ * 以及更多标准 HTML 文本标签
132
+ *
133
+ * @example
134
+ * ```typescript
135
+ * // 基础富文本
136
+ * const label = new GameObject('label');
137
+ * label.addComponent(new HTMLText({
138
+ * text: '这是<b>粗体</b>和<i>斜体</i>文本',
139
+ * style: {
140
+ * fontSize: 24,
141
+ * fill: '#000000',
142
+ * fontFamily: 'Arial'
143
+ * }
144
+ * }));
145
+ *
146
+ * // 带颜色的富文本
147
+ * label.addComponent(new HTMLText({
148
+ * text: '欢迎 <span style="color:#ff0000">玩家123</span> 加入游戏!',
149
+ * style: {
150
+ * fontSize: 20,
151
+ * wordWrap: true,
152
+ * wordWrapWidth: 300
153
+ * }
154
+ * }));
155
+ *
156
+ * // 自定义标签样式
157
+ * label.addComponent(new HTMLText({
158
+ * text: '获得 <gold>100</gold> 金币',
159
+ * style: {
160
+ * fontSize: 18,
161
+ * tagStyles: {
162
+ * gold: {
163
+ * fill: '#ffd700',
164
+ * fontWeight: 'bold'
165
+ * }
166
+ * }
167
+ * }
168
+ * }));
169
+ *
170
+ * // 高分辨率渲染(推荐使用 Render 组件的 resolution 属性)
171
+ * label.addComponent(new HTMLText({
172
+ * text: '高清文本',
173
+ * textureStyle: {
174
+ * scaleMode: 'linear'
175
+ * }
176
+ * }));
177
+ * label.addComponent(new Render({ resolution: 2 }));
178
+ * ```
179
+ */
74
180
  class HTMLText extends Component {
75
181
  constructor() {
76
182
  super(...arguments);
183
+ /** 富文本内容(支持 HTML 标签) */
77
184
  this.text = '';
185
+ /** 文本样式配置 */
78
186
  this.style = {};
187
+ /** 纹理渲染配置 */
79
188
  this.textureStyle = {};
80
189
  }
190
+ /**
191
+ * 初始化组件
192
+ * @param obj - 初始化参数
193
+ * @param obj.text - 富文本内容
194
+ * @param obj.style - 文本样式
195
+ * @param obj.textureStyle - 纹理配置
196
+ */
81
197
  init(obj) {
82
198
  this.style = Object.assign({ fontSize: 24, fill: '#000000', fontFamily: 'Arial' }, obj === null || obj === void 0 ? void 0 : obj.style);
83
199
  this.textureStyle = Object.assign({ scaleMode: 'linear', resolution: window.devicePixelRatio || 1 }, obj === null || obj === void 0 ? void 0 : obj.textureStyle);
@@ -86,6 +202,7 @@ class HTMLText extends Component {
86
202
  }
87
203
  }
88
204
  }
205
+ /** 组件名称 */
89
206
  HTMLText.componentName = 'HTMLText';
90
207
  __decorate([
91
208
  type('string')
@@ -123,6 +240,7 @@ let Text = class Text extends Renderer {
123
240
  }
124
241
  else {
125
242
  this.change(changed);
243
+ // 如果样式改变且涉及字体,也需要等待字体资源加载
126
244
  const component = changed.component;
127
245
  if (changed.prop.prop[0] === 'style' && component.style && component.style.fontFamily) {
128
246
  const { text } = this.texts[changed.gameObject.id];
@@ -135,19 +253,18 @@ let Text = class Text extends Renderer {
135
253
  addTextComponent(changed) {
136
254
  return __awaiter(this, void 0, void 0, function* () {
137
255
  const component = changed.component;
256
+ // 创建文本样式副本,先不设置 fontFamily
138
257
  const styleWithoutFont = Object.assign({}, component.style);
139
258
  const fontFamily = styleWithoutFont.fontFamily;
140
259
  delete styleWithoutFont.fontFamily;
141
260
  const initialText = fontFamily ? '' : component.text;
142
261
  const text = new Text$3(initialText, styleWithoutFont);
143
- if (component.resolution !== undefined && component.resolution > 0) {
144
- text.resolution = component.resolution;
145
- }
146
262
  this.containerManager.getContainer(changed.gameObject.id).addChildAt(text, 0);
147
263
  this.texts[changed.gameObject.id] = {
148
264
  text,
149
265
  component,
150
266
  };
267
+ // 如果指定了字体资源,等待资源加载完成后设置 fontFamily
151
268
  if (fontFamily) {
152
269
  yield this.waitForFontResource(text, changed, fontFamily);
153
270
  }
@@ -156,6 +273,7 @@ let Text = class Text extends Renderer {
156
273
  addHTMLTextComponent(changed) {
157
274
  return __awaiter(this, void 0, void 0, function* () {
158
275
  const component = changed.component;
276
+ // 创建样式副本,先不设置 fontFamily
159
277
  const styleWithoutFont = Object.assign({}, component.style);
160
278
  const fontFamily = styleWithoutFont.fontFamily;
161
279
  delete styleWithoutFont.fontFamily;
@@ -166,11 +284,15 @@ let Text = class Text extends Renderer {
166
284
  text: htmlText,
167
285
  component,
168
286
  };
287
+ // 如果指定了字体资源,等待资源加载完成后设置 fontFamily
169
288
  if (fontFamily) {
170
289
  yield this.waitForFontResource(htmlText, changed, fontFamily);
171
290
  }
172
291
  });
173
292
  }
293
+ /**
294
+ * 等待字体资源加载完成并更新文本
295
+ */
174
296
  waitForFontResource(text, changed, fontFamily) {
175
297
  return __awaiter(this, void 0, void 0, function* () {
176
298
  if (!fontFamily) {
@@ -178,13 +300,17 @@ let Text = class Text extends Renderer {
178
300
  }
179
301
  try {
180
302
  const fontName = Array.isArray(fontFamily) ? fontFamily[0] : fontFamily;
303
+ // 通过 resource 系统获取字体资源
181
304
  const asyncId = this.increaseAsyncId(changed.gameObject.id);
182
305
  yield resource.getResource(fontName);
306
+ // 验证异步操作是否仍然有效(防止组件已被移除)
183
307
  if (!this.validateAsyncId(changed.gameObject.id, asyncId))
184
308
  return;
309
+ // 字体资源加载成功后,设置 fontFamily 并重新设置文本内容以触发重新渲染
185
310
  const component = this.texts[changed.gameObject.id].component;
186
311
  text.style.fontFamily = fontFamily;
187
312
  text.text = component.text;
313
+ // 更新尺寸
188
314
  }
189
315
  catch (error) {
190
316
  console.warn(`字体资源 ${fontFamily} 加载失败:`, error);
@@ -200,13 +326,8 @@ let Text = class Text extends Renderer {
200
326
  else if (changed.prop.prop[0] === 'style') {
201
327
  Object.assign(text.style, component.style);
202
328
  }
203
- else if (changed.prop.prop[0] === 'resolution' && !isHTMLText) {
204
- const textComponent = component;
205
- if (textComponent.resolution !== undefined && textComponent.resolution > 0) {
206
- text.resolution = textComponent.resolution;
207
- }
208
- }
209
329
  else if (changed.prop.prop[0] === 'textureStyle' && isHTMLText) {
330
+ // HTMLText 纹理样式变化需要重新创建
210
331
  const htmlComponent = component;
211
332
  const container = this.containerManager.getContainer(changed.gameObject.id);
212
333
  const index = container.getChildIndex(text);
@@ -234,7 +355,7 @@ let Text = class Text extends Renderer {
234
355
  Text.systemName = 'Text';
235
356
  Text = __decorate([
236
357
  decorators.componentObserver({
237
- Text: ['text', { prop: ['style'], deep: true }, 'resolution'],
358
+ Text: ['text', { prop: ['style'], deep: true }],
238
359
  HTMLText: ['text', { prop: ['style'], deep: true }, { prop: ['textureStyle'], deep: true }],
239
360
  })
240
361
  ], Text);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@eva/plugin-renderer-text",
3
- "version": "2.0.1-beta.27",
3
+ "version": "2.0.1-beta.29",
4
4
  "description": "@eva/plugin-renderer-text",
5
5
  "main": "index.js",
6
6
  "module": "dist/plugin-renderer-text.esm.js",
@@ -19,9 +19,9 @@
19
19
  "homepage": "https://eva.js.org",
20
20
  "dependencies": {
21
21
  "@eva/inspector-decorator": "^0.0.5",
22
- "@eva/plugin-renderer": "2.0.1-beta.27",
23
- "@eva/renderer-adapter": "2.0.1-beta.27",
24
- "@eva/eva.js": "2.0.1-beta.27",
22
+ "@eva/plugin-renderer": "2.0.1-beta.29",
23
+ "@eva/renderer-adapter": "2.0.1-beta.29",
24
+ "@eva/eva.js": "2.0.1-beta.29",
25
25
  "pixi.js": "^8.8.1"
26
26
  }
27
27
  }