@wsxjs/wsx-core 0.0.23 → 0.0.24
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.
- package/dist/{chunk-ESZYREJK.mjs → chunk-5Q2VEEUH.mjs} +160 -35
- package/dist/index.js +226 -64
- package/dist/index.mjs +67 -30
- package/dist/jsx-runtime.js +160 -35
- package/dist/jsx-runtime.mjs +1 -1
- package/dist/jsx.js +160 -35
- package/dist/jsx.mjs +1 -1
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/package.json +2 -2
- package/src/base-component.ts +27 -0
- package/src/light-component.ts +20 -8
- package/src/render-context.ts +4 -0
- package/src/utils/cache-key.ts +27 -21
- package/src/utils/element-creation.ts +5 -0
- package/src/utils/element-update.ts +122 -45
- package/src/utils/update-children-helpers.ts +184 -18
- package/src/web-component.ts +72 -41
- package/dist/chunk-BPQGLNOQ.mjs +0 -1140
- package/dist/chunk-OGMB43J4.mjs +0 -1131
- package/dist/chunk-OXFZ575O.mjs +0 -1091
- package/dist/chunk-TKHKPLBM.mjs +0 -1142
package/src/web-component.ts
CHANGED
|
@@ -79,6 +79,9 @@ export abstract class WebComponent extends BaseComponent {
|
|
|
79
79
|
const hasActualContent =
|
|
80
80
|
allChildren.length > styleElements.length + slotElements.length;
|
|
81
81
|
|
|
82
|
+
// 调用子类的初始化钩子
|
|
83
|
+
this.onConnected?.();
|
|
84
|
+
|
|
82
85
|
// 如果有错误元素,需要重新渲染以恢复正常
|
|
83
86
|
// 如果有实际内容且没有错误,跳过渲染(避免重复元素)
|
|
84
87
|
if (hasActualContent && !hasErrorElement) {
|
|
@@ -110,9 +113,6 @@ export abstract class WebComponent extends BaseComponent {
|
|
|
110
113
|
// 初始化事件监听器
|
|
111
114
|
this.initializeEventListeners();
|
|
112
115
|
|
|
113
|
-
// 调用子类的初始化钩子
|
|
114
|
-
this.onConnected?.();
|
|
115
|
-
|
|
116
116
|
// 如果进行了渲染,调用 onRendered 钩子
|
|
117
117
|
if (hasActualContent === false || hasErrorElement) {
|
|
118
118
|
// 使用 requestAnimationFrame 确保 DOM 已完全更新
|
|
@@ -173,12 +173,21 @@ export abstract class WebComponent extends BaseComponent {
|
|
|
173
173
|
const focusState = this.captureFocusState();
|
|
174
174
|
this._pendingFocusState = focusState;
|
|
175
175
|
|
|
176
|
-
// 2. 保存当前的 adopted stylesheets
|
|
176
|
+
// 2. 保存当前的 adopted stylesheets 并检测实际的样式状态
|
|
177
177
|
const adoptedStyleSheets = this.shadowRoot.adoptedStyleSheets || [];
|
|
178
|
+
// 自动检测模式:检查实际的 ShadowRoot 样式状态,而不仅仅是保存的数组
|
|
179
|
+
// 这样可以更准确地检测样式是否真的已应用
|
|
180
|
+
const hasActualAdoptedStyles =
|
|
181
|
+
this.shadowRoot.adoptedStyleSheets && this.shadowRoot.adoptedStyleSheets.length > 0;
|
|
182
|
+
// 检查 fallback 模式的样式元素
|
|
183
|
+
const hasFallbackStyleElement = Array.from(this.shadowRoot.children).some(
|
|
184
|
+
(child) => child instanceof HTMLStyleElement
|
|
185
|
+
);
|
|
178
186
|
|
|
179
187
|
try {
|
|
180
|
-
// 3.
|
|
181
|
-
|
|
188
|
+
// 3. 自动检测模式:只有在没有实际样式时才重新应用样式
|
|
189
|
+
// 检查 adoptedStyleSheets 和 fallback 样式元素
|
|
190
|
+
if (!hasActualAdoptedStyles && !hasFallbackStyleElement) {
|
|
182
191
|
const stylesToApply = this._autoStyles || this.config.styles;
|
|
183
192
|
if (stylesToApply) {
|
|
184
193
|
const styleName = this.config.styleName || this.constructor.name;
|
|
@@ -205,46 +214,68 @@ export abstract class WebComponent extends BaseComponent {
|
|
|
205
214
|
}
|
|
206
215
|
}
|
|
207
216
|
|
|
208
|
-
// 6.
|
|
209
|
-
|
|
217
|
+
// 6. 执行 DOM 操作(同步,不使用 RAF,因为已经在 scheduleRerender 的 RAF 中)
|
|
218
|
+
// 关键修复 (RFC-0042):检查 content 是否已经在 shadowRoot 中(元素复用场景)
|
|
219
|
+
// 如果 content 已经在 shadowRoot 中,不需要再次添加
|
|
220
|
+
// 这样可以避免移动元素,导致文本节点更新丢失
|
|
221
|
+
const isContentAlreadyInShadowRoot = content.parentNode === this.shadowRoot;
|
|
222
|
+
|
|
223
|
+
if (!isContentAlreadyInShadowRoot) {
|
|
224
|
+
// 添加新内容(仅在不在 shadowRoot 中时)
|
|
225
|
+
this.shadowRoot.appendChild(content);
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
// 移除旧内容(保留样式元素和未标记元素)
|
|
229
|
+
// 关键修复:使用 shouldPreserveElement() 来保护第三方库注入的元素
|
|
230
|
+
const oldChildren = Array.from(this.shadowRoot.children).filter((child) => {
|
|
231
|
+
// 保留新添加的内容(或已经在 shadowRoot 中的 content)
|
|
232
|
+
if (child === content) {
|
|
233
|
+
return false;
|
|
234
|
+
}
|
|
235
|
+
// 保留样式元素
|
|
236
|
+
if (child instanceof HTMLStyleElement) {
|
|
237
|
+
return false;
|
|
238
|
+
}
|
|
239
|
+
// 保留未标记的元素(第三方库注入的元素、自定义元素)
|
|
240
|
+
// 这是 RFC 0037 Phase 5 的核心:保护未标记元素
|
|
241
|
+
if (shouldPreserveElement(child)) {
|
|
242
|
+
return false;
|
|
243
|
+
}
|
|
244
|
+
return true;
|
|
245
|
+
});
|
|
246
|
+
oldChildren.forEach((child) => child.remove());
|
|
247
|
+
|
|
248
|
+
// 7. 恢复 adopted stylesheets(在 DOM 操作之后,确保样式不被意外移除)
|
|
249
|
+
// 关键修复:在 DOM 操作之后恢复样式,防止样式在 DOM 操作过程中被意外清空
|
|
250
|
+
// 自动检测模式:检查实际的样式状态,确保样式正确恢复
|
|
251
|
+
const hasStylesAfterDOM =
|
|
252
|
+
this.shadowRoot.adoptedStyleSheets && this.shadowRoot.adoptedStyleSheets.length > 0;
|
|
253
|
+
const hasStyleElementAfterDOM = Array.from(this.shadowRoot.children).some(
|
|
254
|
+
(child) => child instanceof HTMLStyleElement
|
|
255
|
+
);
|
|
256
|
+
|
|
257
|
+
if (adoptedStyleSheets.length > 0) {
|
|
258
|
+
// 恢复保存的 adoptedStyleSheets
|
|
210
259
|
this.shadowRoot.adoptedStyleSheets = adoptedStyleSheets;
|
|
260
|
+
} else if (!hasStylesAfterDOM && !hasStyleElementAfterDOM) {
|
|
261
|
+
// 自动检测模式:如果 DOM 操作后没有样式,自动重新应用(防止样式丢失)
|
|
262
|
+
// 关键修复:在元素复用场景中,如果 _autoStyles 存在但样式未应用,需要重新应用
|
|
263
|
+
const stylesToApply = this._autoStyles || this.config.styles;
|
|
264
|
+
if (stylesToApply) {
|
|
265
|
+
const styleName = this.config.styleName || this.constructor.name;
|
|
266
|
+
StyleManager.applyStyles(this.shadowRoot, styleName, stylesToApply);
|
|
267
|
+
}
|
|
211
268
|
}
|
|
212
269
|
|
|
213
|
-
//
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
this.shadowRoot.appendChild(content);
|
|
270
|
+
// 8. 恢复焦点状态并清除渲染标志
|
|
271
|
+
this.restoreFocusState(focusState);
|
|
272
|
+
this._pendingFocusState = null;
|
|
217
273
|
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
const oldChildren = Array.from(this.shadowRoot.children).filter((child) => {
|
|
221
|
-
// 保留新添加的内容
|
|
222
|
-
if (child === content) {
|
|
223
|
-
return false;
|
|
224
|
-
}
|
|
225
|
-
// 保留样式元素
|
|
226
|
-
if (child instanceof HTMLStyleElement) {
|
|
227
|
-
return false;
|
|
228
|
-
}
|
|
229
|
-
// 保留未标记的元素(第三方库注入的元素、自定义元素)
|
|
230
|
-
// 这是 RFC 0037 Phase 5 的核心:保护未标记元素
|
|
231
|
-
if (shouldPreserveElement(child)) {
|
|
232
|
-
return false;
|
|
233
|
-
}
|
|
234
|
-
return true;
|
|
235
|
-
});
|
|
236
|
-
oldChildren.forEach((child) => child.remove());
|
|
274
|
+
// 9. 调用 onRendered 生命周期钩子
|
|
275
|
+
this.onRendered?.();
|
|
237
276
|
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
this.restoreFocusState(focusState);
|
|
241
|
-
this._pendingFocusState = null;
|
|
242
|
-
// 调用 onRendered 生命周期钩子
|
|
243
|
-
this.onRendered?.();
|
|
244
|
-
// 在 onRendered() 完成后清除渲染标志,允许后续的 scheduleRerender()
|
|
245
|
-
this._isRendering = false;
|
|
246
|
-
});
|
|
247
|
-
});
|
|
277
|
+
// 10. 清除渲染标志,允许后续的 scheduleRerender()
|
|
278
|
+
this._isRendering = false;
|
|
248
279
|
} catch (error) {
|
|
249
280
|
logger.error("Error in _rerender:", error);
|
|
250
281
|
this.renderError(error);
|