react-native-fxview 1.0.0 → 1.0.2
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/FXCategoryController.d.ts +100 -0
- package/FXCategoryController.js +270 -0
- package/{FXViewCategoryController.ts → FXCategoryController.ts} +14 -11
- package/FXView.d.ts +20 -0
- package/FXView.js +103 -0
- package/FXView.tsx +3 -3
- package/FXViewController.d.ts +115 -0
- package/FXViewController.js +289 -0
- package/FXViewController.ts +14 -11
- package/FXViewManager.d.ts +146 -0
- package/FXViewManager.js +354 -0
- package/FXViewManager.ts +39 -19
- package/README.md +209 -0
- package/index.d.ts +5 -0
- package/index.js +30 -0
- package/index.ts +6 -0
- package/package.json +47 -6
- package/types.d.ts +39 -0
- package/types.js +2 -0
- package/types.ts +7 -2
package/FXViewManager.js
ADDED
|
@@ -0,0 +1,354 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.FXViewManager = void 0;
|
|
4
|
+
const FXViewController_1 = require("./FXViewController");
|
|
5
|
+
const PriorityQueue_1 = require("./queue/PriorityQueue");
|
|
6
|
+
class FXViewManager {
|
|
7
|
+
constructor() {
|
|
8
|
+
// 存储视图控制器
|
|
9
|
+
this.viewControllerMap = new Map();
|
|
10
|
+
this.fxViewIdQueue = new PriorityQueue_1.PriorityQueue(PriorityQueue_1.HeapType.MAX_HEAP, PriorityQueue_1.PriorityOrder.LIFO);
|
|
11
|
+
this.viewLifecycleCallbacks = [];
|
|
12
|
+
//#endregion
|
|
13
|
+
}
|
|
14
|
+
static getInstance() {
|
|
15
|
+
if (!FXViewManager.instance) {
|
|
16
|
+
FXViewManager.instance = new FXViewManager();
|
|
17
|
+
}
|
|
18
|
+
return FXViewManager.instance;
|
|
19
|
+
}
|
|
20
|
+
//#region ========== 主要 API 方法 ==========
|
|
21
|
+
/**
|
|
22
|
+
* 创建并显示组件
|
|
23
|
+
* @param component 组件内容
|
|
24
|
+
* @param fxViewId 视图 ID(可选,使用最近的视图)
|
|
25
|
+
* @param categoryId 分类 ID(可选,默认 "default")
|
|
26
|
+
* @param componentId 组件 ID(可选,自动生成)
|
|
27
|
+
* @returns 组件控制器
|
|
28
|
+
*/
|
|
29
|
+
add(component, fxViewId, categoryId, componentId) {
|
|
30
|
+
console.log("FXViewManager.add", {
|
|
31
|
+
fxViewId,
|
|
32
|
+
categoryId,
|
|
33
|
+
componentId,
|
|
34
|
+
});
|
|
35
|
+
const viewController = this.getViewControllerOrCreate(fxViewId);
|
|
36
|
+
return viewController.add(component, categoryId, componentId);
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* 创建但不显示组件
|
|
40
|
+
* @param component 组件内容
|
|
41
|
+
* @param fxViewId 视图 ID(可选,使用最近的视图)
|
|
42
|
+
* @param categoryId 分类 ID(可选,默认 "default")
|
|
43
|
+
* @param componentId 组件 ID(可选,自动生成)
|
|
44
|
+
* @returns 组件控制器
|
|
45
|
+
*/
|
|
46
|
+
build(component, fxViewId, categoryId, componentId) {
|
|
47
|
+
console.log("FXViewManager.build", {
|
|
48
|
+
fxViewId,
|
|
49
|
+
categoryId,
|
|
50
|
+
componentId,
|
|
51
|
+
});
|
|
52
|
+
const viewController = this.getViewControllerOrCreate(fxViewId);
|
|
53
|
+
return viewController.build(component, categoryId, componentId);
|
|
54
|
+
}
|
|
55
|
+
/**
|
|
56
|
+
* 显示已存在的组件
|
|
57
|
+
* @param componentId 组件 ID
|
|
58
|
+
* @param fxViewId 视图 ID(可选,使用最近的视图)
|
|
59
|
+
* @param categoryId 分类 ID(可选,默认 "default")
|
|
60
|
+
*/
|
|
61
|
+
show(componentId, fxViewId, categoryId) {
|
|
62
|
+
console.log("FXViewManager.show", {
|
|
63
|
+
fxViewId,
|
|
64
|
+
categoryId,
|
|
65
|
+
componentId,
|
|
66
|
+
});
|
|
67
|
+
const viewController = this.getViewController(fxViewId);
|
|
68
|
+
if (!viewController) {
|
|
69
|
+
console.warn(`FXView ${fxViewId || "latest"} not found`);
|
|
70
|
+
return;
|
|
71
|
+
}
|
|
72
|
+
viewController.show(componentId, categoryId);
|
|
73
|
+
}
|
|
74
|
+
/**
|
|
75
|
+
* 隐藏但不删除组件
|
|
76
|
+
* @param componentId 组件 ID
|
|
77
|
+
* @param fxViewId 视图 ID(可选,使用最近的视图)
|
|
78
|
+
* @param categoryId 分类 ID(可选,默认 "default")
|
|
79
|
+
*/
|
|
80
|
+
hide(componentId, fxViewId, categoryId) {
|
|
81
|
+
console.log("FXViewManager.hide", {
|
|
82
|
+
fxViewId,
|
|
83
|
+
categoryId,
|
|
84
|
+
componentId,
|
|
85
|
+
});
|
|
86
|
+
const viewController = this.getViewController(fxViewId);
|
|
87
|
+
if (!viewController) {
|
|
88
|
+
console.warn(`FXView ${fxViewId || "latest"} not found`);
|
|
89
|
+
return;
|
|
90
|
+
}
|
|
91
|
+
viewController.hide(componentId, categoryId);
|
|
92
|
+
}
|
|
93
|
+
/**
|
|
94
|
+
* 更新组件内容
|
|
95
|
+
* @param componentId 组件 ID
|
|
96
|
+
* @param component 新的组件内容
|
|
97
|
+
* @param fxViewId 视图 ID(可选,使用最近的视图)
|
|
98
|
+
* @param categoryId 分类 ID(可选,默认 "default")
|
|
99
|
+
*/
|
|
100
|
+
update(componentId, component, fxViewId, categoryId) {
|
|
101
|
+
console.log("FXViewManager.update", {
|
|
102
|
+
fxViewId,
|
|
103
|
+
categoryId,
|
|
104
|
+
componentId,
|
|
105
|
+
});
|
|
106
|
+
const viewController = this.getViewController(fxViewId);
|
|
107
|
+
if (!viewController) {
|
|
108
|
+
console.warn(`FXView ${fxViewId || "latest"} not found`);
|
|
109
|
+
return;
|
|
110
|
+
}
|
|
111
|
+
viewController.update(componentId, component, categoryId);
|
|
112
|
+
}
|
|
113
|
+
/**
|
|
114
|
+
* 彻底删除组件
|
|
115
|
+
* @param componentId 组件 ID
|
|
116
|
+
* @param fxViewId 视图 ID(可选,使用最近的视图)
|
|
117
|
+
* @param categoryId 分类 ID(可选,默认 "default")
|
|
118
|
+
*/
|
|
119
|
+
remove(componentId, fxViewId, categoryId) {
|
|
120
|
+
console.log("FXViewManager.remove", {
|
|
121
|
+
fxViewId,
|
|
122
|
+
categoryId,
|
|
123
|
+
componentId,
|
|
124
|
+
});
|
|
125
|
+
const viewController = this.getViewController(fxViewId);
|
|
126
|
+
if (!viewController) {
|
|
127
|
+
console.warn(`FXView ${fxViewId || "latest"} not found`);
|
|
128
|
+
return;
|
|
129
|
+
}
|
|
130
|
+
viewController.remove(componentId, categoryId);
|
|
131
|
+
}
|
|
132
|
+
/**
|
|
133
|
+
* 移除最后一个组件(向后兼容)
|
|
134
|
+
* @param fxViewId 视图 ID(可选,使用最近的视图)
|
|
135
|
+
* @param categoryId 分类 ID(可选,默认 "default")
|
|
136
|
+
*/
|
|
137
|
+
removeLast(fxViewId, categoryId) {
|
|
138
|
+
console.log("FXViewManager.removeLast", {
|
|
139
|
+
fxViewId,
|
|
140
|
+
categoryId,
|
|
141
|
+
});
|
|
142
|
+
const viewController = this.getViewController(fxViewId);
|
|
143
|
+
if (!viewController) {
|
|
144
|
+
console.warn(`FXView ${fxViewId || "latest"} not found`);
|
|
145
|
+
return;
|
|
146
|
+
}
|
|
147
|
+
viewController.removeLast(categoryId);
|
|
148
|
+
}
|
|
149
|
+
/**
|
|
150
|
+
* 清空指定视图的所有组件
|
|
151
|
+
* @param fxViewId 视图 ID(可选,清空所有视图)
|
|
152
|
+
*/
|
|
153
|
+
clearAll(fxViewId) {
|
|
154
|
+
console.log("FXViewManager.clearAll", { fxViewId });
|
|
155
|
+
if (fxViewId) {
|
|
156
|
+
// 清空指定视图
|
|
157
|
+
const viewController = this.getViewController(fxViewId);
|
|
158
|
+
if (viewController) {
|
|
159
|
+
viewController.clearAll();
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
else {
|
|
163
|
+
// 清空所有视图
|
|
164
|
+
this.viewControllerMap.forEach((controller) => {
|
|
165
|
+
controller.clearAll();
|
|
166
|
+
});
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
/**
|
|
170
|
+
* 清空指定分类的所有组件
|
|
171
|
+
* @param categoryId 分类 ID
|
|
172
|
+
* @param fxViewId 视图 ID(可选,使用最近的视图)
|
|
173
|
+
*/
|
|
174
|
+
clearCategory(categoryId, fxViewId) {
|
|
175
|
+
console.log("FXViewManager.clearCategory", { fxViewId, categoryId });
|
|
176
|
+
const viewController = this.getViewController(fxViewId);
|
|
177
|
+
if (!viewController) {
|
|
178
|
+
console.warn(`FXView ${fxViewId || "latest"} not found`);
|
|
179
|
+
return;
|
|
180
|
+
}
|
|
181
|
+
viewController.clearCategory(categoryId);
|
|
182
|
+
}
|
|
183
|
+
//#endregion
|
|
184
|
+
//#region ========== 视图管理方法 ==========
|
|
185
|
+
/**
|
|
186
|
+
* 注册视图(FXView 挂载时调用)
|
|
187
|
+
* @param fxViewId 视图 ID
|
|
188
|
+
* @param updateCallback 更新回调函数
|
|
189
|
+
* @returns 视图控制器
|
|
190
|
+
*/
|
|
191
|
+
registerView(fxViewId, updateCallback) {
|
|
192
|
+
console.log("FXViewManager.registerView", fxViewId);
|
|
193
|
+
let viewController = this.viewControllerMap.get(fxViewId);
|
|
194
|
+
if (!viewController) {
|
|
195
|
+
viewController = new FXViewController_1.FXViewController(fxViewId);
|
|
196
|
+
this.viewControllerMap.set(fxViewId, viewController);
|
|
197
|
+
}
|
|
198
|
+
// 注册更新回调
|
|
199
|
+
viewController.registerUpdateCallback(updateCallback);
|
|
200
|
+
if (this.fxViewIdQueue.find((id) => id === fxViewId) !== null) {
|
|
201
|
+
this.fxViewIdQueue.remove(fxViewId);
|
|
202
|
+
}
|
|
203
|
+
this.fxViewIdQueue.enqueue(fxViewId);
|
|
204
|
+
this.viewLifecycleCallbacks.forEach((callback) => {
|
|
205
|
+
var _a;
|
|
206
|
+
(_a = callback.didMount) === null || _a === void 0 ? void 0 : _a.call(callback, fxViewId);
|
|
207
|
+
});
|
|
208
|
+
return viewController;
|
|
209
|
+
}
|
|
210
|
+
/**
|
|
211
|
+
* 注销视图(FXView 卸载时调用)
|
|
212
|
+
* @param fxViewId 视图 ID
|
|
213
|
+
* @returns 是否成功注销
|
|
214
|
+
*/
|
|
215
|
+
unregisterView(fxViewId) {
|
|
216
|
+
console.log("FXViewManager.unregisterView", fxViewId);
|
|
217
|
+
const viewController = this.getViewController(fxViewId);
|
|
218
|
+
if (!viewController) {
|
|
219
|
+
console.warn(`FXView ${fxViewId} not found, cannot unregister`);
|
|
220
|
+
return false;
|
|
221
|
+
}
|
|
222
|
+
// 清空回调
|
|
223
|
+
viewController.registerUpdateCallback(undefined);
|
|
224
|
+
// 清空所有组件
|
|
225
|
+
viewController.clearAll();
|
|
226
|
+
// 从队列中移除
|
|
227
|
+
this.fxViewIdQueue.remove(fxViewId);
|
|
228
|
+
// 从 Map 中删除
|
|
229
|
+
this.viewControllerMap.delete(fxViewId);
|
|
230
|
+
this.viewLifecycleCallbacks.forEach((callback) => {
|
|
231
|
+
var _a;
|
|
232
|
+
(_a = callback.willUnmount) === null || _a === void 0 ? void 0 : _a.call(callback, fxViewId);
|
|
233
|
+
});
|
|
234
|
+
return true;
|
|
235
|
+
}
|
|
236
|
+
registerLifecycleCallbacks(callbacks) {
|
|
237
|
+
console.log("FXViewManager.registerLifecycleCallbacks");
|
|
238
|
+
this.viewLifecycleCallbacks.push(callbacks);
|
|
239
|
+
}
|
|
240
|
+
unregisterLifecycleCallbacks(callbacks) {
|
|
241
|
+
console.log("FXViewManager.unregisterLifecycleCallbacks");
|
|
242
|
+
this.viewLifecycleCallbacks = this.viewLifecycleCallbacks.filter((callback) => callback !== callbacks);
|
|
243
|
+
}
|
|
244
|
+
/**
|
|
245
|
+
* 获取最近使用的视图 ID(栈顶)
|
|
246
|
+
* @returns 最近的视图 ID 或 null
|
|
247
|
+
*/
|
|
248
|
+
getLatestFXViewId() {
|
|
249
|
+
return this.fxViewIdQueue.peek() || null;
|
|
250
|
+
}
|
|
251
|
+
/**
|
|
252
|
+
* 获取组件列表
|
|
253
|
+
* @param fxViewId 视图 ID(可选,使用最近的视图)
|
|
254
|
+
* @param categoryId 分类 ID(可选)
|
|
255
|
+
* @returns 组件列表
|
|
256
|
+
*/
|
|
257
|
+
getComponents(fxViewId, categoryId) {
|
|
258
|
+
console.log("FXViewManager.getComponents", { fxViewId, categoryId });
|
|
259
|
+
const finalFXViewId = fxViewId || this.getLatestFXViewId();
|
|
260
|
+
if (!finalFXViewId) {
|
|
261
|
+
console.warn("No FXView available");
|
|
262
|
+
return [];
|
|
263
|
+
}
|
|
264
|
+
const viewController = this.getViewController(finalFXViewId);
|
|
265
|
+
if (!viewController) {
|
|
266
|
+
console.warn(`FXViewController ${finalFXViewId} not found`);
|
|
267
|
+
return [];
|
|
268
|
+
}
|
|
269
|
+
return viewController.getComponents(categoryId);
|
|
270
|
+
}
|
|
271
|
+
/**
|
|
272
|
+
* 获取组件数量
|
|
273
|
+
* @param fxViewId 视图 ID(可选,使用最近的视图)
|
|
274
|
+
* @returns 组件数量
|
|
275
|
+
*/
|
|
276
|
+
getComponentCount(fxViewId) {
|
|
277
|
+
var _a;
|
|
278
|
+
const viewController = this.getViewController(fxViewId);
|
|
279
|
+
return (_a = viewController === null || viewController === void 0 ? void 0 : viewController.getComponentCount()) !== null && _a !== void 0 ? _a : 0;
|
|
280
|
+
}
|
|
281
|
+
/**
|
|
282
|
+
* 获取可见组件数量
|
|
283
|
+
* @param fxViewId 视图 ID(可选,使用最近的视图)
|
|
284
|
+
* @returns 可见组件数量
|
|
285
|
+
*/
|
|
286
|
+
getVisibleComponentCount(fxViewId) {
|
|
287
|
+
var _a;
|
|
288
|
+
const viewController = this.getViewController(fxViewId);
|
|
289
|
+
return (_a = viewController === null || viewController === void 0 ? void 0 : viewController.getVisibleComponentCount()) !== null && _a !== void 0 ? _a : 0;
|
|
290
|
+
}
|
|
291
|
+
/**
|
|
292
|
+
* 检查组件是否存在
|
|
293
|
+
* @param componentId 组件 ID
|
|
294
|
+
* @param fxViewId 视图 ID(可选,使用最近的视图)
|
|
295
|
+
* @param categoryId 分类 ID(可选)
|
|
296
|
+
* @returns 是否存在
|
|
297
|
+
*/
|
|
298
|
+
hasComponent(componentId, fxViewId, categoryId) {
|
|
299
|
+
var _a;
|
|
300
|
+
const viewController = this.getViewController(fxViewId);
|
|
301
|
+
return (_a = viewController === null || viewController === void 0 ? void 0 : viewController.hasComponent(componentId, categoryId)) !== null && _a !== void 0 ? _a : false;
|
|
302
|
+
}
|
|
303
|
+
/**
|
|
304
|
+
* 检查组件是否可见
|
|
305
|
+
* @param componentId 组件 ID
|
|
306
|
+
* @param fxViewId 视图 ID(可选,使用最近的视图)
|
|
307
|
+
* @param categoryId 分类 ID(可选)
|
|
308
|
+
* @returns 是否可见
|
|
309
|
+
*/
|
|
310
|
+
isComponentVisible(componentId, fxViewId, categoryId) {
|
|
311
|
+
var _a;
|
|
312
|
+
const viewController = this.getViewController(fxViewId);
|
|
313
|
+
return (_a = viewController === null || viewController === void 0 ? void 0 : viewController.isComponentVisible(componentId, categoryId)) !== null && _a !== void 0 ? _a : false;
|
|
314
|
+
}
|
|
315
|
+
//#endregion
|
|
316
|
+
//#region ========== 私有方法 ==========
|
|
317
|
+
/**
|
|
318
|
+
* 获取视图控制器
|
|
319
|
+
* @param fxViewId 视图 ID(可选,使用最近的视图)
|
|
320
|
+
* @returns 视图控制器或 null
|
|
321
|
+
*/
|
|
322
|
+
getViewController(fxViewId) {
|
|
323
|
+
const finalFXViewId = fxViewId || this.getLatestFXViewId();
|
|
324
|
+
if (!finalFXViewId) {
|
|
325
|
+
console.warn("FXViewManager.getViewController: no fxViewId available");
|
|
326
|
+
return null;
|
|
327
|
+
}
|
|
328
|
+
return this.viewControllerMap.get(finalFXViewId) || null;
|
|
329
|
+
}
|
|
330
|
+
/**
|
|
331
|
+
* 获取或创建视图控制器
|
|
332
|
+
* @param fxViewId 视图 ID(可选,使用最近的视图或创建新的)
|
|
333
|
+
* @returns 视图控制器
|
|
334
|
+
*/
|
|
335
|
+
getViewControllerOrCreate(fxViewId) {
|
|
336
|
+
const finalFXViewId = fxViewId || this.getLatestFXViewId() || this.autoFXViewId();
|
|
337
|
+
let viewController = this.viewControllerMap.get(finalFXViewId);
|
|
338
|
+
if (!viewController) {
|
|
339
|
+
console.warn(`FXViewController ${finalFXViewId} not registered, creating a temporary one`);
|
|
340
|
+
viewController = new FXViewController_1.FXViewController(finalFXViewId);
|
|
341
|
+
this.viewControllerMap.set(finalFXViewId, viewController);
|
|
342
|
+
this.fxViewIdQueue.enqueue(finalFXViewId);
|
|
343
|
+
}
|
|
344
|
+
return viewController;
|
|
345
|
+
}
|
|
346
|
+
/**
|
|
347
|
+
* 自动生成 fxViewId
|
|
348
|
+
* @returns 生成的 fxViewId
|
|
349
|
+
*/
|
|
350
|
+
autoFXViewId() {
|
|
351
|
+
return `fxView_${Date.now()}_${Math.random().toString(36).substring(2, 9)}`;
|
|
352
|
+
}
|
|
353
|
+
}
|
|
354
|
+
exports.FXViewManager = FXViewManager;
|
package/FXViewManager.ts
CHANGED
|
@@ -1,15 +1,22 @@
|
|
|
1
1
|
import React from "react";
|
|
2
|
-
import {
|
|
2
|
+
import {
|
|
3
|
+
FXComponentController,
|
|
4
|
+
FXComponentItem,
|
|
5
|
+
FXLifecycleCallbacks,
|
|
6
|
+
} from "./types";
|
|
3
7
|
import { FXViewController } from "./FXViewController";
|
|
4
|
-
import { HeapType, PriorityOrder, PriorityQueue } from "
|
|
8
|
+
import { HeapType, PriorityOrder, PriorityQueue } from "./queue/PriorityQueue";
|
|
5
9
|
|
|
6
10
|
export class FXViewManager {
|
|
7
11
|
private static instance: FXViewManager;
|
|
8
12
|
|
|
9
13
|
// 存储视图控制器
|
|
10
14
|
private viewControllerMap: Map<string, FXViewController> = new Map();
|
|
11
|
-
private
|
|
12
|
-
|
|
15
|
+
private fxViewIdQueue: PriorityQueue<string> = new PriorityQueue(
|
|
16
|
+
HeapType.MAX_HEAP,
|
|
17
|
+
PriorityOrder.LIFO,
|
|
18
|
+
);
|
|
19
|
+
private viewLifecycleCallbacks: Array<FXLifecycleCallbacks> = [];
|
|
13
20
|
|
|
14
21
|
static getInstance(): FXViewManager {
|
|
15
22
|
if (!FXViewManager.instance) {
|
|
@@ -33,7 +40,7 @@ export class FXViewManager {
|
|
|
33
40
|
fxViewId?: string,
|
|
34
41
|
categoryId?: string,
|
|
35
42
|
componentId?: string,
|
|
36
|
-
):
|
|
43
|
+
): FXComponentController {
|
|
37
44
|
console.log("FXViewManager.add", {
|
|
38
45
|
fxViewId,
|
|
39
46
|
categoryId,
|
|
@@ -57,7 +64,7 @@ export class FXViewManager {
|
|
|
57
64
|
fxViewId?: string,
|
|
58
65
|
categoryId?: string,
|
|
59
66
|
componentId?: string,
|
|
60
|
-
):
|
|
67
|
+
): FXComponentController {
|
|
61
68
|
console.log("FXViewManager.build", {
|
|
62
69
|
fxViewId,
|
|
63
70
|
categoryId,
|
|
@@ -242,16 +249,13 @@ export class FXViewManager {
|
|
|
242
249
|
|
|
243
250
|
// 注册更新回调
|
|
244
251
|
viewController.registerUpdateCallback(updateCallback);
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
const existingController = this.viewControllerQueue
|
|
248
|
-
.getAll()
|
|
249
|
-
.find((vc) => vc.fxViewId === fxViewId);
|
|
250
|
-
if (existingController) {
|
|
251
|
-
this.viewControllerQueue.remove(existingController);
|
|
252
|
+
if (this.fxViewIdQueue.find((id) => id === fxViewId) !== null) {
|
|
253
|
+
this.fxViewIdQueue.remove(fxViewId);
|
|
252
254
|
}
|
|
253
|
-
this.
|
|
254
|
-
|
|
255
|
+
this.fxViewIdQueue.enqueue(fxViewId);
|
|
256
|
+
this.viewLifecycleCallbacks.forEach((callback) => {
|
|
257
|
+
callback.didMount?.(fxViewId);
|
|
258
|
+
});
|
|
255
259
|
return viewController;
|
|
256
260
|
}
|
|
257
261
|
|
|
@@ -276,20 +280,36 @@ export class FXViewManager {
|
|
|
276
280
|
viewController.clearAll();
|
|
277
281
|
|
|
278
282
|
// 从队列中移除
|
|
279
|
-
this.
|
|
283
|
+
this.fxViewIdQueue.remove(fxViewId);
|
|
280
284
|
|
|
281
285
|
// 从 Map 中删除
|
|
282
286
|
this.viewControllerMap.delete(fxViewId);
|
|
283
287
|
|
|
288
|
+
this.viewLifecycleCallbacks.forEach((callback) => {
|
|
289
|
+
callback.willUnmount?.(fxViewId);
|
|
290
|
+
});
|
|
291
|
+
|
|
284
292
|
return true;
|
|
285
293
|
}
|
|
286
294
|
|
|
295
|
+
registerLifecycleCallbacks(callbacks: FXLifecycleCallbacks): void {
|
|
296
|
+
console.log("FXViewManager.registerLifecycleCallbacks");
|
|
297
|
+
this.viewLifecycleCallbacks.push(callbacks);
|
|
298
|
+
}
|
|
299
|
+
|
|
300
|
+
unregisterLifecycleCallbacks(callbacks: FXLifecycleCallbacks): void {
|
|
301
|
+
console.log("FXViewManager.unregisterLifecycleCallbacks");
|
|
302
|
+
this.viewLifecycleCallbacks = this.viewLifecycleCallbacks.filter(
|
|
303
|
+
(callback) => callback !== callbacks,
|
|
304
|
+
);
|
|
305
|
+
}
|
|
306
|
+
|
|
287
307
|
/**
|
|
288
308
|
* 获取最近使用的视图 ID(栈顶)
|
|
289
309
|
* @returns 最近的视图 ID 或 null
|
|
290
310
|
*/
|
|
291
311
|
getLatestFXViewId(): string | null {
|
|
292
|
-
return this.
|
|
312
|
+
return this.fxViewIdQueue.peek() || null;
|
|
293
313
|
}
|
|
294
314
|
|
|
295
315
|
/**
|
|
@@ -298,7 +318,7 @@ export class FXViewManager {
|
|
|
298
318
|
* @param categoryId 分类 ID(可选)
|
|
299
319
|
* @returns 组件列表
|
|
300
320
|
*/
|
|
301
|
-
getComponents(fxViewId?: string, categoryId?: string):
|
|
321
|
+
getComponents(fxViewId?: string, categoryId?: string): FXComponentItem[] {
|
|
302
322
|
console.log("FXViewManager.getComponents", { fxViewId, categoryId });
|
|
303
323
|
|
|
304
324
|
const finalFXViewId = fxViewId || this.getLatestFXViewId();
|
|
@@ -403,7 +423,7 @@ export class FXViewManager {
|
|
|
403
423
|
);
|
|
404
424
|
viewController = new FXViewController(finalFXViewId);
|
|
405
425
|
this.viewControllerMap.set(finalFXViewId, viewController);
|
|
406
|
-
this.
|
|
426
|
+
this.fxViewIdQueue.enqueue(finalFXViewId);
|
|
407
427
|
}
|
|
408
428
|
|
|
409
429
|
return viewController;
|
package/README.md
ADDED
|
@@ -0,0 +1,209 @@
|
|
|
1
|
+
# React Native FXView
|
|
2
|
+
|
|
3
|
+
一个革命性的React Native动态UI预埋框架,支持在任何位置预埋容器,然后通过全局管理器在运行时动态注入和控制React组件。
|
|
4
|
+
|
|
5
|
+
## 🎯 核心概念
|
|
6
|
+
|
|
7
|
+
FXView采用**预埋+注入**的设计模式:
|
|
8
|
+
|
|
9
|
+
1. **预埋容器**:在应用的任何位置预埋`FXView`容器
|
|
10
|
+
2. **动态注入**:通过`FXViewManager`在任何时间、任何位置动态注入React组件
|
|
11
|
+
3. **全局控制**:支持跨组件、跨页面的全局UI管理和状态控制
|
|
12
|
+
|
|
13
|
+
## ✨ 功能特性
|
|
14
|
+
|
|
15
|
+
- 🎯 **动态组件注入** - 运行时在任何预埋位置注入React组件
|
|
16
|
+
- 🔄 **实时UI更新** - 支持组件内容的实时更新和状态管理
|
|
17
|
+
- 📂 **智能分类管理** - 按分类组织和管理动态组件
|
|
18
|
+
- 👁️ **显示/隐藏控制** - 灵活控制组件的显示状态
|
|
19
|
+
- 🌍 **全局访问** - 从应用的任何地方访问和管理UI
|
|
20
|
+
- 🚀 **轻量级高性能** - 优化的渲染性能和内存管理
|
|
21
|
+
|
|
22
|
+
## 📦 安装
|
|
23
|
+
|
|
24
|
+
```bash
|
|
25
|
+
npm install react-native-fxview
|
|
26
|
+
# 或者
|
|
27
|
+
yarn add react-native-fxview
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
## 🚀 快速开始
|
|
31
|
+
|
|
32
|
+
### 1. 预埋FXView容器
|
|
33
|
+
|
|
34
|
+
在任何需要动态注入UI的位置预埋FXView:
|
|
35
|
+
|
|
36
|
+
```javascript
|
|
37
|
+
import React from 'react';
|
|
38
|
+
import { View, Text } from 'react-native';
|
|
39
|
+
import { FXView } from 'react-native-fxview';
|
|
40
|
+
|
|
41
|
+
export default function App() {
|
|
42
|
+
return (
|
|
43
|
+
<View style={{ flex: 1 }}>
|
|
44
|
+
<Text>静态内容</Text>
|
|
45
|
+
|
|
46
|
+
{/* 预埋动态UI容器 */}
|
|
47
|
+
<FXView fxViewId="headerArea" style={{ height: 60 }} />
|
|
48
|
+
|
|
49
|
+
<Text>更多静态内容</Text>
|
|
50
|
+
|
|
51
|
+
{/* 在底部预埋另一个容器 */}
|
|
52
|
+
<FXView fxViewId="bottomSheet" style={{ position: 'absolute', bottom: 0 }} />
|
|
53
|
+
</View>
|
|
54
|
+
);
|
|
55
|
+
}
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
### 2. 动态注入组件
|
|
59
|
+
|
|
60
|
+
从应用的任何地方(甚至不同的页面或组件)动态注入UI:
|
|
61
|
+
|
|
62
|
+
```javascript
|
|
63
|
+
import { FXViewManager } from 'react-native-fxview';
|
|
64
|
+
import { Button, View, Text } from 'react-native';
|
|
65
|
+
|
|
66
|
+
// 在headerArea注入一个搜索栏
|
|
67
|
+
const searchBarController = FXViewManager.getInstance().add(
|
|
68
|
+
<View style={{ backgroundColor: '#f0f0f0', padding: 10 }}>
|
|
69
|
+
<Text>搜索栏组件</Text>
|
|
70
|
+
</View>,
|
|
71
|
+
'headerArea', // fxViewId
|
|
72
|
+
'navigation' // categoryId
|
|
73
|
+
);
|
|
74
|
+
|
|
75
|
+
// 在bottomSheet注入一个弹窗
|
|
76
|
+
const sheetController = FXViewManager.getInstance().add(
|
|
77
|
+
<View style={{ backgroundColor: 'white', padding: 20, borderRadius: 10 }}>
|
|
78
|
+
<Text>底部弹窗内容</Text>
|
|
79
|
+
<Button title="关闭" onPress={() => sheetController.hide()} />
|
|
80
|
+
</View>,
|
|
81
|
+
'bottomSheet',
|
|
82
|
+
'modals'
|
|
83
|
+
);
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
### 3. 运行时控制
|
|
87
|
+
|
|
88
|
+
```javascript
|
|
89
|
+
// 隐藏搜索栏
|
|
90
|
+
searchBarController.hide();
|
|
91
|
+
|
|
92
|
+
// 更新搜索栏内容
|
|
93
|
+
searchBarController.update(
|
|
94
|
+
<View style={{ backgroundColor: 'blue', padding: 10 }}>
|
|
95
|
+
<Text style={{ color: 'white' }}>更新后的搜索栏</Text>
|
|
96
|
+
</View>
|
|
97
|
+
);
|
|
98
|
+
|
|
99
|
+
// 显示搜索栏
|
|
100
|
+
searchBarController.show();
|
|
101
|
+
|
|
102
|
+
// 完全移除组件
|
|
103
|
+
searchBarController.remove();
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
## 📖 API 参考
|
|
107
|
+
|
|
108
|
+
### FXView Props
|
|
109
|
+
|
|
110
|
+
- `fxViewId` (string, optional): 容器唯一标识符,用于后续注入组件时的定位
|
|
111
|
+
|
|
112
|
+
### FXViewManager 主要方法
|
|
113
|
+
|
|
114
|
+
#### 组件管理
|
|
115
|
+
- `add(component, fxViewId?, category?, componentId?)` - 创建并显示组件
|
|
116
|
+
- `build(component, fxViewId?, category?, componentId?)` - 创建但不显示组件
|
|
117
|
+
- `show(componentId, fxViewId?, category?)` - 显示已存在的组件
|
|
118
|
+
- `hide(componentId, fxViewId?, category?)` - 隐藏组件
|
|
119
|
+
- `update(componentId, newComponent, fxViewId?, category?)` - 更新组件内容
|
|
120
|
+
- `remove(componentId, fxViewId?, category?)` - 移除组件
|
|
121
|
+
|
|
122
|
+
#### 批量操作
|
|
123
|
+
- `clearAll(fxViewId?)` - 清空指定或所有容器
|
|
124
|
+
- `clearCategory(categoryId, fxViewId?)` - 清空指定分类
|
|
125
|
+
|
|
126
|
+
#### 查询方法
|
|
127
|
+
- `getComponents(fxViewId?, category?)` - 获取组件列表
|
|
128
|
+
- `hasComponent(componentId, fxViewId?, category?)` - 检查组件是否存在
|
|
129
|
+
- `isComponentVisible(componentId, fxViewId?, category?)` - 检查组件是否可见
|
|
130
|
+
|
|
131
|
+
### 组件控制器 (FXComponentController)
|
|
132
|
+
|
|
133
|
+
- `show()` - 显示组件
|
|
134
|
+
- `hide()` - 隐藏组件
|
|
135
|
+
- `remove()` - 移除组件
|
|
136
|
+
- `update(newComponent)` - 更新组件内容
|
|
137
|
+
- `isVisible()` - 获取可见状态
|
|
138
|
+
- `exists()` - 检查组件是否存在
|
|
139
|
+
|
|
140
|
+
## 💡 使用场景
|
|
141
|
+
|
|
142
|
+
### 1. 动态导航栏
|
|
143
|
+
在不同页面根据状态动态改变顶部导航栏内容
|
|
144
|
+
|
|
145
|
+
### 2. 全局弹窗系统
|
|
146
|
+
从任何地方触发全局弹窗、通知、确认框等
|
|
147
|
+
|
|
148
|
+
### 3. 动态表单
|
|
149
|
+
根据用户操作动态添加、移除、更新表单字段
|
|
150
|
+
|
|
151
|
+
### 4. 插件化UI
|
|
152
|
+
支持第三方插件动态注入UI组件到主应用
|
|
153
|
+
|
|
154
|
+
### 5. A/B测试
|
|
155
|
+
动态切换不同的UI组件进行A/B测试
|
|
156
|
+
|
|
157
|
+
## 🎯 最佳实践
|
|
158
|
+
|
|
159
|
+
### 分类管理
|
|
160
|
+
使用分类来组织不同类型的动态组件:
|
|
161
|
+
|
|
162
|
+
```javascript
|
|
163
|
+
// 导航相关
|
|
164
|
+
FXViewManager.getInstance().add(navComponent, 'header', 'navigation');
|
|
165
|
+
|
|
166
|
+
// 弹窗相关
|
|
167
|
+
FXViewManager.getInstance().add(modalComponent, 'overlay', 'modals');
|
|
168
|
+
|
|
169
|
+
// 通知相关
|
|
170
|
+
FXViewManager.getInstance().add(toastComponent, 'notification', 'notifications');
|
|
171
|
+
```
|
|
172
|
+
|
|
173
|
+
### 生命周期管理
|
|
174
|
+
```javascript
|
|
175
|
+
// 创建时
|
|
176
|
+
const controller = FXViewManager.getInstance().build(component, 'container');
|
|
177
|
+
|
|
178
|
+
// 需要时显示
|
|
179
|
+
controller.show();
|
|
180
|
+
|
|
181
|
+
// 不需要时隐藏
|
|
182
|
+
controller.hide();
|
|
183
|
+
|
|
184
|
+
// 完全清理
|
|
185
|
+
controller.remove();
|
|
186
|
+
```
|
|
187
|
+
|
|
188
|
+
## 🔧 高级用法
|
|
189
|
+
|
|
190
|
+
### 生命周期回调
|
|
191
|
+
```javascript
|
|
192
|
+
FXViewManager.getInstance().registerLifecycleCallbacks({
|
|
193
|
+
didMount: (fxViewId) => console.log('FXView挂载:', fxViewId),
|
|
194
|
+
willUnmount: (fxViewId) => console.log('FXView卸载:', fxViewId)
|
|
195
|
+
});
|
|
196
|
+
```
|
|
197
|
+
|
|
198
|
+
### 组件查询和批量操作
|
|
199
|
+
```javascript
|
|
200
|
+
// 获取所有导航组件
|
|
201
|
+
const navComponents = FXViewManager.getInstance().getComponents(null, 'navigation');
|
|
202
|
+
|
|
203
|
+
// 清空所有弹窗
|
|
204
|
+
FXViewManager.getInstance().clearCategory('modals');
|
|
205
|
+
```
|
|
206
|
+
|
|
207
|
+
## 📄 许可证
|
|
208
|
+
|
|
209
|
+
MIT
|