@wsxjs/wsx-router 0.0.17 → 0.0.18

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/src/WsxView.wsx CHANGED
@@ -1,5 +1,6 @@
1
1
  /** @jsxImportSource @wsxjs/wsx-core */
2
- import { LightComponent, autoRegister, createLogger } from "@wsxjs/wsx-core";
2
+ import { LightComponent, autoRegister } from "@wsxjs/wsx-core";
3
+ import { createLogger } from "@wsxjs/wsx-logger";
3
4
  import styles from "./WsxView.css?inline";
4
5
 
5
6
  const logger = createLogger("WsxView");
@@ -24,6 +25,7 @@ export default class WsxView extends LightComponent {
24
25
  private component: string | null = null;
25
26
  private params: Record<string, string> = {};
26
27
  private componentInstance: HTMLElement | null = null;
28
+ private isLoading: boolean = false; // 防止重复加载的标志
27
29
 
28
30
  constructor() {
29
31
  super({
@@ -41,58 +43,129 @@ export default class WsxView extends LightComponent {
41
43
  }
42
44
 
43
45
  protected onConnected() {
44
- // Check if component attribute is already set and load it
45
- const componentName = this.getAttribute("component");
46
- if (componentName && !this.componentInstance) {
47
- this.loadComponent(componentName);
48
- }
46
+ // 延迟加载,避免在 connectedCallback 中同步执行
47
+ requestAnimationFrame(() => {
48
+ // 重新检查,防止在延迟期间已经加载
49
+ if (!this.connected || this.isLoading || this.componentInstance) {
50
+ return;
51
+ }
52
+
53
+ const componentName = this.getAttribute("component");
54
+ if (componentName) {
55
+ this.loadComponent(componentName);
56
+ }
57
+ });
49
58
  }
50
59
 
51
60
  protected onAttributeChanged(name: string, _oldValue: string, newValue: string) {
52
- if (name === "component" && newValue && !this.componentInstance) {
53
- this.loadComponent(newValue);
61
+ // 只在组件已连接时处理属性变化
62
+ if (!this.connected) {
63
+ return;
64
+ }
65
+
66
+ if (name === "component" && newValue && !this.componentInstance && !this.isLoading) {
67
+ // 延迟加载,避免在 attributeChangedCallback 中同步执行
68
+ requestAnimationFrame(() => {
69
+ if (this.connected && !this.componentInstance && !this.isLoading) {
70
+ this.loadComponent(newValue);
71
+ }
72
+ });
54
73
  } else if (name === "params" && this.componentInstance) {
55
74
  // 更新组件参数
56
75
  try {
57
76
  this.params = JSON.parse(newValue);
77
+ logger.debug(
78
+ `WsxView: params attribute changed, setting on component:`,
79
+ this.params
80
+ );
58
81
  Object.entries(this.params).forEach(([key, value]) => {
59
82
  this.componentInstance!.setAttribute(key, value);
60
83
  });
84
+ logger.debug(`WsxView: params set on component ${this.componentInstance.tagName}`);
61
85
  } catch (e) {
62
- logger.error("Failed to parse params:", e);
86
+ logger.warn("Failed to parse params:", e);
63
87
  }
64
88
  }
65
89
  }
66
90
 
67
91
  private async loadComponent(componentName: string) {
68
- // 清理旧组件
69
- if (this.componentInstance) {
70
- this.componentInstance.remove();
71
- this.componentInstance = null;
92
+ // 防止重复加载
93
+ if (!this.connected || this.isLoading || this.componentInstance) {
94
+ logger.debug(
95
+ `Skipping loadComponent for ${componentName}: connected=${this.connected}, isLoading=${this.isLoading}, hasInstance=${!!this.componentInstance}`
96
+ );
97
+ return;
72
98
  }
73
99
 
74
- // 检查组件是否已注册
75
- const elementClass = customElements.get(componentName);
100
+ logger.debug(`WsxView: Loading component ${componentName}`);
101
+ this.isLoading = true; // 设置标志
76
102
 
77
- if (!elementClass) {
78
- logger.warn(`Component ${componentName} not found in customElements registry`);
79
- return;
80
- }
103
+ try {
104
+ // 清理旧组件(虽然理论上不应该有,但为了安全起见)
105
+ const instance = this.componentInstance;
106
+ if (instance) {
107
+ (instance as HTMLElement).remove();
108
+ this.componentInstance = null;
109
+ }
81
110
 
82
- this.componentInstance = document.createElement(componentName);
111
+ // 检查组件是否已注册
112
+ const elementClass = customElements.get(componentName);
83
113
 
84
- // 传递初始参数
85
- if (Object.keys(this.params).length > 0) {
86
- Object.entries(this.params).forEach(([key, value]) => {
87
- this.componentInstance!.setAttribute(key, value);
88
- });
89
- }
114
+ if (!elementClass) {
115
+ logger.warn(`Component ${componentName} not found in customElements registry`);
116
+ this.isLoading = false; // 重置标志
117
+ return;
118
+ }
119
+
120
+ logger.warn(`WsxView: Creating instance of ${componentName}`);
121
+ this.componentInstance = document.createElement(componentName); // 立即设置实例,防止重复创建
90
122
 
91
- const container = this.querySelector(".route-view");
92
- if (container) {
93
- container.appendChild(this.componentInstance);
94
- } else {
95
- logger.error("Route view container not found");
123
+ // 传递初始参数
124
+ if (Object.keys(this.params).length > 0) {
125
+ logger.warn(`WsxView: Setting initial params on ${componentName}:`, this.params);
126
+ Object.entries(this.params).forEach(([key, value]) => {
127
+ this.componentInstance!.setAttribute(key, value);
128
+ });
129
+ }
130
+
131
+ const container = this.querySelector(".route-view");
132
+ if (container) {
133
+ logger.warn(`WsxView: Appending ${componentName} to container`);
134
+ // 在追加之前,确保组件已注册
135
+ if (!customElements.get(componentName)) {
136
+ logger.error(
137
+ `WsxView: Component ${componentName} is not registered in customElements registry!`
138
+ );
139
+ this.isLoading = false;
140
+ this.componentInstance = null;
141
+ return;
142
+ }
143
+ container.appendChild(this.componentInstance); // 这会触发新组件的 connectedCallback
144
+ logger.warn(
145
+ `WsxView: Component ${componentName} appended successfully, waiting for connectedCallback...`
146
+ );
147
+ // 使用 setTimeout 验证组件是否真的连接了
148
+ setTimeout(() => {
149
+ if (this.componentInstance && this.componentInstance.isConnected) {
150
+ logger.warn(`WsxView: Component ${componentName} is now connected to DOM`);
151
+ } else {
152
+ logger.error(
153
+ `WsxView: Component ${componentName} was not connected to DOM!`
154
+ );
155
+ }
156
+ }, 0);
157
+ } else {
158
+ logger.error("WsxView: Route view container not found");
159
+ this.componentInstance = null; // 清除实例
160
+ }
161
+ } catch (error) {
162
+ logger.warn(`Error loading component ${componentName}:`, error);
163
+ this.componentInstance = null; // 清除实例
164
+ } finally {
165
+ this.isLoading = false; // 重置标志
166
+ logger.warn(
167
+ `WsxView: loadComponent for ${componentName} completed, isLoading=${this.isLoading}`
168
+ );
96
169
  }
97
170
  }
98
171
 
package/src/index.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  /**
2
- * WSX Router - Native History API-based routing for WSX Framework
2
+ * WSX Router - Native History API-based routing for WSXJS
3
3
  *
4
4
  * 提供基于原生 History API 的路由功能:
5
5
  * - 零依赖路由器组件
@@ -1,6 +1,7 @@
1
1
  // Type declaration for .wsx files
2
2
  declare module "*.wsx" {
3
3
  import { WebComponent, LightComponent } from "@wsxjs/wsx-core";
4
- const component: new (...args: unknown[]) => WebComponent | LightComponent;
5
- export default component;
4
+ // Allow any class that extends WebComponent or LightComponent
5
+ const Component: new (...args: unknown[]) => WebComponent | LightComponent;
6
+ export default Component;
6
7
  }