@lytjs/platform-adapter 6.0.0
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/index.cjs +193 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +370 -0
- package/dist/index.d.ts +370 -0
- package/dist/index.mjs +190 -0
- package/dist/index.mjs.map +1 -0
- package/package.json +53 -0
package/dist/index.cjs
ADDED
|
@@ -0,0 +1,193 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
var commonIs = require('@lytjs/common-is');
|
|
4
|
+
|
|
5
|
+
// src/adapter-registry.ts
|
|
6
|
+
var AdapterRegistry = class {
|
|
7
|
+
constructor() {
|
|
8
|
+
/** 已注册的适配器映射(平台名称 -> 适配器实例) */
|
|
9
|
+
this.adapters = /* @__PURE__ */ new Map();
|
|
10
|
+
/** 平台插件映射(平台名称 -> 插件数组) */
|
|
11
|
+
this.plugins = /* @__PURE__ */ new Map();
|
|
12
|
+
}
|
|
13
|
+
/**
|
|
14
|
+
* 注册平台适配器
|
|
15
|
+
*
|
|
16
|
+
* @description
|
|
17
|
+
* 将适配器实例注册到注册表中,以适配器的 name 为键。
|
|
18
|
+
* 如果同名适配器已存在,将被覆盖。
|
|
19
|
+
*
|
|
20
|
+
* @param adapter - 平台适配器实例
|
|
21
|
+
* @throws {Error} 当 adapter.name 为空时抛出错误
|
|
22
|
+
*/
|
|
23
|
+
register(adapter) {
|
|
24
|
+
if (!commonIs.isString(adapter.name) || adapter.name.length === 0) {
|
|
25
|
+
throw new Error(
|
|
26
|
+
"[platform-adapter] \u9002\u914D\u5668\u540D\u79F0\u4E0D\u80FD\u4E3A\u7A7A"
|
|
27
|
+
);
|
|
28
|
+
}
|
|
29
|
+
this.adapters.set(adapter.name, adapter);
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* 注销平台适配器
|
|
33
|
+
*
|
|
34
|
+
* @description
|
|
35
|
+
* 从注册表中移除指定名称的适配器,同时清除该平台关联的所有插件。
|
|
36
|
+
*
|
|
37
|
+
* @param name - 平台名称
|
|
38
|
+
* @returns 是否成功注销(名称不存在时返回 false)
|
|
39
|
+
*/
|
|
40
|
+
unregister(name) {
|
|
41
|
+
const removed = this.adapters.delete(name);
|
|
42
|
+
if (removed) {
|
|
43
|
+
this.plugins.delete(name);
|
|
44
|
+
}
|
|
45
|
+
return removed;
|
|
46
|
+
}
|
|
47
|
+
/**
|
|
48
|
+
* 获取指定名称的平台适配器
|
|
49
|
+
*
|
|
50
|
+
* @param name - 平台名称
|
|
51
|
+
* @returns 适配器实例,未找到时返回 undefined
|
|
52
|
+
*/
|
|
53
|
+
get(name) {
|
|
54
|
+
return this.adapters.get(name);
|
|
55
|
+
}
|
|
56
|
+
/**
|
|
57
|
+
* 检查指定名称的适配器是否已注册
|
|
58
|
+
*
|
|
59
|
+
* @param name - 平台名称
|
|
60
|
+
* @returns 是否已注册
|
|
61
|
+
*/
|
|
62
|
+
has(name) {
|
|
63
|
+
return this.adapters.has(name);
|
|
64
|
+
}
|
|
65
|
+
/**
|
|
66
|
+
* 获取所有已注册的适配器名称
|
|
67
|
+
*
|
|
68
|
+
* @returns 平台名称数组
|
|
69
|
+
*/
|
|
70
|
+
getNames() {
|
|
71
|
+
return Array.from(this.adapters.keys());
|
|
72
|
+
}
|
|
73
|
+
/**
|
|
74
|
+
* 为指定平台添加插件
|
|
75
|
+
*
|
|
76
|
+
* @description
|
|
77
|
+
* 将插件添加到目标平台的插件列表中。
|
|
78
|
+
* 如果目标平台不存在,会自动创建空的插件列表。
|
|
79
|
+
*
|
|
80
|
+
* @param platformName - 目标平台名称
|
|
81
|
+
* @param plugin - 平台插件实例
|
|
82
|
+
*/
|
|
83
|
+
addPlugin(platformName, plugin) {
|
|
84
|
+
const existing = this.plugins.get(platformName);
|
|
85
|
+
if (existing) {
|
|
86
|
+
existing.push(plugin);
|
|
87
|
+
} else {
|
|
88
|
+
this.plugins.set(platformName, [plugin]);
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
/**
|
|
92
|
+
* 从指定平台移除插件
|
|
93
|
+
*
|
|
94
|
+
* @param platformName - 目标平台名称
|
|
95
|
+
* @param pluginName - 要移除的插件名称
|
|
96
|
+
* @returns 是否成功移除(插件不存在时返回 false)
|
|
97
|
+
*/
|
|
98
|
+
removePlugin(platformName, pluginName) {
|
|
99
|
+
const list = this.plugins.get(platformName);
|
|
100
|
+
if (!list) return false;
|
|
101
|
+
const index = list.findIndex((p) => p.name === pluginName);
|
|
102
|
+
if (index === -1) return false;
|
|
103
|
+
list.splice(index, 1);
|
|
104
|
+
return true;
|
|
105
|
+
}
|
|
106
|
+
/**
|
|
107
|
+
* 获取指定平台的所有插件
|
|
108
|
+
*
|
|
109
|
+
* @param platformName - 目标平台名称
|
|
110
|
+
* @returns 插件数组,平台无插件时返回空数组
|
|
111
|
+
*/
|
|
112
|
+
getPlugins(platformName) {
|
|
113
|
+
return this.plugins.get(platformName) ?? [];
|
|
114
|
+
}
|
|
115
|
+
};
|
|
116
|
+
var adapterRegistry = new AdapterRegistry();
|
|
117
|
+
function createPlatformRenderer(adapter, config) {
|
|
118
|
+
let currentChild = null;
|
|
119
|
+
const renderer = {
|
|
120
|
+
/**
|
|
121
|
+
* 将 VNode 渲染到容器中
|
|
122
|
+
*
|
|
123
|
+
* @description
|
|
124
|
+
* 根据 vnode 类型创建对应的宿主节点,并插入到容器中。
|
|
125
|
+
* 如果容器中已有内容,会先卸载再重新渲染。
|
|
126
|
+
*/
|
|
127
|
+
render(vnode, container) {
|
|
128
|
+
if (currentChild !== null) {
|
|
129
|
+
this.unmount(container);
|
|
130
|
+
}
|
|
131
|
+
const node = createHostNodeFromVNode(adapter, vnode);
|
|
132
|
+
if (node !== null) {
|
|
133
|
+
adapter.insert(node, container, null);
|
|
134
|
+
currentChild = node;
|
|
135
|
+
}
|
|
136
|
+
if (config?.debug) {
|
|
137
|
+
console.log(`[platform-adapter:${adapter.name}] \u6E32\u67D3\u5B8C\u6210`, vnode);
|
|
138
|
+
}
|
|
139
|
+
},
|
|
140
|
+
/**
|
|
141
|
+
* 卸载容器中的内容
|
|
142
|
+
*/
|
|
143
|
+
unmount(_container) {
|
|
144
|
+
if (currentChild !== null) {
|
|
145
|
+
adapter.remove(currentChild);
|
|
146
|
+
currentChild = null;
|
|
147
|
+
}
|
|
148
|
+
if (config?.debug) {
|
|
149
|
+
console.log(`[platform-adapter:${adapter.name}] \u5378\u8F7D\u5B8C\u6210`);
|
|
150
|
+
}
|
|
151
|
+
},
|
|
152
|
+
/**
|
|
153
|
+
* 获取关联的平台适配器
|
|
154
|
+
*/
|
|
155
|
+
getAdapter() {
|
|
156
|
+
return adapter;
|
|
157
|
+
}
|
|
158
|
+
};
|
|
159
|
+
return renderer;
|
|
160
|
+
}
|
|
161
|
+
function createHostNodeFromVNode(adapter, vnode) {
|
|
162
|
+
const { type, children } = vnode;
|
|
163
|
+
if (commonIs.isString(type)) {
|
|
164
|
+
const el = adapter.createElement(type);
|
|
165
|
+
if (vnode.props) {
|
|
166
|
+
for (const [key, value] of Object.entries(vnode.props)) {
|
|
167
|
+
if (key === "style" && commonIs.isString(value)) {
|
|
168
|
+
adapter.setStyle(el, value);
|
|
169
|
+
} else if (key === "class" && commonIs.isString(value)) {
|
|
170
|
+
adapter.addClass(el, value);
|
|
171
|
+
} else if (commonIs.isString(value)) {
|
|
172
|
+
adapter.setAttribute(el, key, value);
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
if (children && commonIs.isString(children)) {
|
|
177
|
+
adapter.setElementText(el, children);
|
|
178
|
+
}
|
|
179
|
+
return el;
|
|
180
|
+
}
|
|
181
|
+
if (commonIs.isString(children)) {
|
|
182
|
+
return adapter.createText(children);
|
|
183
|
+
}
|
|
184
|
+
if (commonIs.isFunction(type) === false && type !== null && !commonIs.isString(type)) {
|
|
185
|
+
return adapter.createComment(String(children ?? ""));
|
|
186
|
+
}
|
|
187
|
+
return null;
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
exports.adapterRegistry = adapterRegistry;
|
|
191
|
+
exports.createPlatformRenderer = createPlatformRenderer;
|
|
192
|
+
//# sourceMappingURL=index.cjs.map
|
|
193
|
+
//# sourceMappingURL=index.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/adapter-registry.ts","../src/create-renderer.ts"],"names":["isString","isFunction"],"mappings":"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","file":"index.cjs","sourcesContent":["/**\r\n * 平台适配器注册表\r\n *\r\n * @description\r\n * 管理所有已注册的平台适配器和插件,提供统一的注册、查询和插件管理能力。\r\n * 采用单例模式,全局共享同一个注册表实例。\r\n */\r\n\r\nimport { isString } from '@lytjs/common-is';\r\nimport type { PlatformAdapter, PlatformPlugin } from './types';\r\n\r\n/**\r\n * 适配器注册表类\r\n *\r\n * @description\r\n * 维护平台适配器的注册信息,支持适配器的注册、注销、查询,\r\n * 以及平台级插件的管理。\r\n */\r\nclass AdapterRegistry {\r\n /** 已注册的适配器映射(平台名称 -> 适配器实例) */\r\n private adapters = new Map<string, PlatformAdapter>();\r\n /** 平台插件映射(平台名称 -> 插件数组) */\r\n private plugins = new Map<string, PlatformPlugin[]>();\r\n\r\n /**\r\n * 注册平台适配器\r\n *\r\n * @description\r\n * 将适配器实例注册到注册表中,以适配器的 name 为键。\r\n * 如果同名适配器已存在,将被覆盖。\r\n *\r\n * @param adapter - 平台适配器实例\r\n * @throws {Error} 当 adapter.name 为空时抛出错误\r\n */\r\n register(adapter: PlatformAdapter): void {\r\n if (!isString(adapter.name) || adapter.name.length === 0) {\r\n throw new Error(\r\n '[platform-adapter] 适配器名称不能为空',\r\n );\r\n }\r\n this.adapters.set(adapter.name, adapter);\r\n }\r\n\r\n /**\r\n * 注销平台适配器\r\n *\r\n * @description\r\n * 从注册表中移除指定名称的适配器,同时清除该平台关联的所有插件。\r\n *\r\n * @param name - 平台名称\r\n * @returns 是否成功注销(名称不存在时返回 false)\r\n */\r\n unregister(name: string): boolean {\r\n const removed = this.adapters.delete(name);\r\n if (removed) {\r\n this.plugins.delete(name);\r\n }\r\n return removed;\r\n }\r\n\r\n /**\r\n * 获取指定名称的平台适配器\r\n *\r\n * @param name - 平台名称\r\n * @returns 适配器实例,未找到时返回 undefined\r\n */\r\n get(name: string): PlatformAdapter | undefined {\r\n return this.adapters.get(name);\r\n }\r\n\r\n /**\r\n * 检查指定名称的适配器是否已注册\r\n *\r\n * @param name - 平台名称\r\n * @returns 是否已注册\r\n */\r\n has(name: string): boolean {\r\n return this.adapters.has(name);\r\n }\r\n\r\n /**\r\n * 获取所有已注册的适配器名称\r\n *\r\n * @returns 平台名称数组\r\n */\r\n getNames(): string[] {\r\n return Array.from(this.adapters.keys());\r\n }\r\n\r\n /**\r\n * 为指定平台添加插件\r\n *\r\n * @description\r\n * 将插件添加到目标平台的插件列表中。\r\n * 如果目标平台不存在,会自动创建空的插件列表。\r\n *\r\n * @param platformName - 目标平台名称\r\n * @param plugin - 平台插件实例\r\n */\r\n addPlugin(platformName: string, plugin: PlatformPlugin): void {\r\n const existing = this.plugins.get(platformName);\r\n if (existing) {\r\n existing.push(plugin);\r\n } else {\r\n this.plugins.set(platformName, [plugin]);\r\n }\r\n }\r\n\r\n /**\r\n * 从指定平台移除插件\r\n *\r\n * @param platformName - 目标平台名称\r\n * @param pluginName - 要移除的插件名称\r\n * @returns 是否成功移除(插件不存在时返回 false)\r\n */\r\n removePlugin(platformName: string, pluginName: string): boolean {\r\n const list = this.plugins.get(platformName);\r\n if (!list) return false;\r\n\r\n const index = list.findIndex((p) => p.name === pluginName);\r\n if (index === -1) return false;\r\n\r\n list.splice(index, 1);\r\n return true;\r\n }\r\n\r\n /**\r\n * 获取指定平台的所有插件\r\n *\r\n * @param platformName - 目标平台名称\r\n * @returns 插件数组,平台无插件时返回空数组\r\n */\r\n getPlugins(platformName: string): PlatformPlugin[] {\r\n return this.plugins.get(platformName) ?? [];\r\n }\r\n}\r\n\r\n/** 全局适配器注册表单例 */\r\nexport const adapterRegistry = new AdapterRegistry();\r\n","/**\r\n * 跨平台渲染器工厂\r\n *\r\n * @description\r\n * 基于平台适配器创建渲染器实例,提供统一的 render/unmount API,\r\n * 屏蔽底层平台差异。\r\n */\r\n\r\nimport { isFunction, isString } from '@lytjs/common-is';\r\nimport type { VNode } from '@lytjs/common-vnode';\r\nimport type { PlatformAdapter, PlatformConfig } from './types';\r\n\r\n/**\r\n * 平台渲染器接口\r\n *\r\n * @description\r\n * 封装了平台适配器,提供高层的渲染和卸载 API。\r\n *\r\n * @template HN - 宿主节点类型\r\n * @template HE - 宿主元素类型(extends HN)\r\n */\r\nexport interface PlatformRenderer<HN, HE extends HN> {\r\n /**\r\n * 将 VNode 渲染到指定容器中\r\n *\r\n * @param vnode - 要渲染的虚拟节点\r\n * @param container - 宿主容器节点\r\n */\r\n render(vnode: VNode, container: HN): void;\r\n\r\n /**\r\n * 卸载指定容器中的内容\r\n *\r\n * @param container - 宿主容器节点\r\n */\r\n unmount(container: HN): void;\r\n\r\n /**\r\n * 获取关联的平台适配器\r\n *\r\n * @returns 平台适配器实例\r\n */\r\n getAdapter(): PlatformAdapter<HN, HE>;\r\n}\r\n\r\n/**\r\n * 创建平台渲染器\r\n *\r\n * @description\r\n * 工厂函数,基于给定的平台适配器和配置创建渲染器实例。\r\n * 渲染器内部委托适配器完成实际的 DOM 操作。\r\n *\r\n * @template HN - 宿主节点类型\r\n * @template HE - 宿主元素类型(extends HN)\r\n * @param adapter - 平台适配器实例\r\n * @param config - 平台配置(可选)\r\n * @returns 平台渲染器实例\r\n *\r\n * @example\r\n * ```typescript\r\n * const renderer = createPlatformRenderer(myAdapter, { debug: true });\r\n * renderer.render(vnode, container);\r\n * ```\r\n */\r\nexport function createPlatformRenderer<HN, HE extends HN>(\r\n adapter: PlatformAdapter<HN, HE>,\r\n config?: PlatformConfig,\r\n): PlatformRenderer<HN, HE> {\r\n // 当前容器中已渲染的子节点引用\r\n let currentChild: HN | null = null;\r\n\r\n const renderer: PlatformRenderer<HN, HE> = {\r\n /**\r\n * 将 VNode 渲染到容器中\r\n *\r\n * @description\r\n * 根据 vnode 类型创建对应的宿主节点,并插入到容器中。\r\n * 如果容器中已有内容,会先卸载再重新渲染。\r\n */\r\n render(vnode: VNode, container: HN): void {\r\n // 先卸载已有内容\r\n if (currentChild !== null) {\r\n this.unmount(container);\r\n }\r\n\r\n const node = createHostNodeFromVNode(adapter, vnode);\r\n if (node !== null) {\r\n adapter.insert(node, container, null);\r\n currentChild = node;\r\n }\r\n\r\n if (config?.debug) {\r\n // eslint-disable-next-line no-console\r\n console.log(`[platform-adapter:${adapter.name}] 渲染完成`, vnode);\r\n }\r\n },\r\n\r\n /**\r\n * 卸载容器中的内容\r\n */\r\n unmount(_container: HN): void {\r\n if (currentChild !== null) {\r\n adapter.remove(currentChild);\r\n currentChild = null;\r\n }\r\n\r\n if (config?.debug) {\r\n // eslint-disable-next-line no-console\r\n console.log(`[platform-adapter:${adapter.name}] 卸载完成`);\r\n }\r\n },\r\n\r\n /**\r\n * 获取关联的平台适配器\r\n */\r\n getAdapter(): PlatformAdapter<HN, HE> {\r\n return adapter;\r\n },\r\n };\r\n\r\n return renderer;\r\n}\r\n\r\n/**\r\n * 根据 VNode 类型创建宿主节点\r\n *\r\n * @description\r\n * 将 VNode 映射为平台适配器可操作的宿主节点。\r\n * 支持元素节点、文本节点和注释节点。\r\n *\r\n * @param adapter - 平台适配器\r\n * @param vnode - 虚拟节点\r\n * @returns 宿主节点,无法识别的类型返回 null\r\n */\r\nfunction createHostNodeFromVNode<HN, HE extends HN>(\r\n adapter: PlatformAdapter<HN, HE>,\r\n vnode: VNode,\r\n): HN | null {\r\n const { type, children } = vnode;\r\n\r\n // 元素节点\r\n if (isString(type)) {\r\n const el = adapter.createElement(type);\r\n\r\n // 设置属性\r\n if (vnode.props) {\r\n for (const [key, value] of Object.entries(vnode.props)) {\r\n if (key === 'style' && isString(value)) {\r\n adapter.setStyle(el, value);\r\n } else if (key === 'class' && isString(value)) {\r\n adapter.addClass(el, value);\r\n } else if (isString(value)) {\r\n adapter.setAttribute(el, key, value);\r\n }\r\n }\r\n }\r\n\r\n // 递归处理子节点\r\n if (children && isString(children)) {\r\n adapter.setElementText(el, children);\r\n }\r\n\r\n return el as unknown as HN;\r\n }\r\n\r\n // 文本节点\r\n if (isString(children)) {\r\n return adapter.createText(children);\r\n }\r\n\r\n // 注释节点\r\n if (isFunction(type) === false && type !== null && !isString(type)) {\r\n // 非 string、非 function、非 null 的 type 可能是 Comment Symbol\r\n return adapter.createComment(String(children ?? ''));\r\n }\r\n\r\n return null;\r\n}\r\n"]}
|
package/dist/index.d.cts
ADDED
|
@@ -0,0 +1,370 @@
|
|
|
1
|
+
import { VNode } from '@lytjs/common-vnode';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* @lytjs/platform-adapter
|
|
5
|
+
* 平台适配器类型定义
|
|
6
|
+
*
|
|
7
|
+
* @description
|
|
8
|
+
* 定义跨平台渲染适配器的核心接口,所有平台实现必须遵循此契约。
|
|
9
|
+
* HN = Host Node(宿主节点),HE = Host Element(宿主元素)
|
|
10
|
+
*/
|
|
11
|
+
/**
|
|
12
|
+
* 平台适配器接口 - 所有平台必须实现此接口
|
|
13
|
+
*
|
|
14
|
+
* @description
|
|
15
|
+
* 提供跨平台的 DOM 操作抽象层,将底层平台差异封装为统一 API。
|
|
16
|
+
* 每个平台(Web、小程序、Node.js SSR 等)都需要提供自己的实现。
|
|
17
|
+
*
|
|
18
|
+
* @template HN - 宿主节点类型
|
|
19
|
+
* @template HE - 宿主元素类型(extends HN)
|
|
20
|
+
*
|
|
21
|
+
* @example
|
|
22
|
+
* ```typescript
|
|
23
|
+
* const webAdapter: PlatformAdapter<Node, Element> = {
|
|
24
|
+
* name: 'web',
|
|
25
|
+
* version: '1.0.0',
|
|
26
|
+
* createElement(tag) { return document.createElement(tag); },
|
|
27
|
+
* // ... 其他方法
|
|
28
|
+
* };
|
|
29
|
+
* ```
|
|
30
|
+
*/
|
|
31
|
+
interface PlatformAdapter<HN = unknown, HE = unknown> {
|
|
32
|
+
/** 平台名称(如 'web'、'miniapp'、'ssr') */
|
|
33
|
+
readonly name: string;
|
|
34
|
+
/** 平台版本号 */
|
|
35
|
+
readonly version: string;
|
|
36
|
+
/**
|
|
37
|
+
* 创建元素节点
|
|
38
|
+
* @param tag - 标签名
|
|
39
|
+
* @returns 创建的元素节点
|
|
40
|
+
*/
|
|
41
|
+
createElement(tag: string): HE;
|
|
42
|
+
/**
|
|
43
|
+
* 创建文本节点
|
|
44
|
+
* @param text - 文本内容
|
|
45
|
+
* @returns 创建的文本节点
|
|
46
|
+
*/
|
|
47
|
+
createText(text: string): HN;
|
|
48
|
+
/**
|
|
49
|
+
* 创建注释节点
|
|
50
|
+
* @param text - 注释内容
|
|
51
|
+
* @returns 创建的注释节点
|
|
52
|
+
*/
|
|
53
|
+
createComment(text: string): HN;
|
|
54
|
+
/**
|
|
55
|
+
* 插入子节点到父节点中
|
|
56
|
+
* @param child - 子节点
|
|
57
|
+
* @param parent - 父节点
|
|
58
|
+
* @param anchor - 参考锚点,插入到锚点之前
|
|
59
|
+
*/
|
|
60
|
+
insert(child: HN, parent: HN, anchor?: HN | null): void;
|
|
61
|
+
/**
|
|
62
|
+
* 移除子节点
|
|
63
|
+
* @param child - 要移除的节点
|
|
64
|
+
*/
|
|
65
|
+
remove(child: HN): void;
|
|
66
|
+
/**
|
|
67
|
+
* 设置元素节点的文本内容
|
|
68
|
+
* @param node - 元素节点
|
|
69
|
+
* @param text - 文本内容
|
|
70
|
+
*/
|
|
71
|
+
setElementText(node: HE, text: string): void;
|
|
72
|
+
/**
|
|
73
|
+
* 设置文本节点的内容
|
|
74
|
+
* @param node - 文本节点
|
|
75
|
+
* @param text - 文本内容
|
|
76
|
+
*/
|
|
77
|
+
setText(node: HN, text: string): void;
|
|
78
|
+
/**
|
|
79
|
+
* 设置元素属性
|
|
80
|
+
* @param el - 元素节点
|
|
81
|
+
* @param key - 属性名
|
|
82
|
+
* @param value - 属性值
|
|
83
|
+
*/
|
|
84
|
+
setAttribute(el: HE, key: string, value: string): void;
|
|
85
|
+
/**
|
|
86
|
+
* 移除元素属性
|
|
87
|
+
* @param el - 元素节点
|
|
88
|
+
* @param key - 属性名
|
|
89
|
+
*/
|
|
90
|
+
removeAttribute(el: HE, key: string): void;
|
|
91
|
+
/**
|
|
92
|
+
* 获取元素属性值
|
|
93
|
+
* @param el - 元素节点
|
|
94
|
+
* @param key - 属性名
|
|
95
|
+
* @returns 属性值,不存在时返回 null
|
|
96
|
+
*/
|
|
97
|
+
getAttribute(el: HE, key: string): string | null;
|
|
98
|
+
/**
|
|
99
|
+
* 检查元素是否拥有指定属性
|
|
100
|
+
* @param el - 元素节点
|
|
101
|
+
* @param key - 属性名
|
|
102
|
+
* @returns 是否存在该属性
|
|
103
|
+
*/
|
|
104
|
+
hasAttribute(el: HE, key: string): boolean;
|
|
105
|
+
/**
|
|
106
|
+
* 设置元素的行内样式
|
|
107
|
+
* @param el - 元素节点
|
|
108
|
+
* @param style - CSS 样式字符串
|
|
109
|
+
*/
|
|
110
|
+
setStyle(el: HE, style: string): void;
|
|
111
|
+
/**
|
|
112
|
+
* 获取元素的行内样式字符串
|
|
113
|
+
* @param el - 元素节点
|
|
114
|
+
* @returns CSS 样式字符串
|
|
115
|
+
*/
|
|
116
|
+
getStyle(el: HE): string;
|
|
117
|
+
/**
|
|
118
|
+
* 添加 CSS 类名
|
|
119
|
+
* @param el - 元素节点
|
|
120
|
+
* @param className - 类名
|
|
121
|
+
*/
|
|
122
|
+
addClass(el: HE, className: string): void;
|
|
123
|
+
/**
|
|
124
|
+
* 移除 CSS 类名
|
|
125
|
+
* @param el - 元素节点
|
|
126
|
+
* @param className - 类名
|
|
127
|
+
*/
|
|
128
|
+
removeClass(el: HE, className: string): void;
|
|
129
|
+
/**
|
|
130
|
+
* 检查元素是否包含指定类名
|
|
131
|
+
* @param el - 元素节点
|
|
132
|
+
* @param className - 类名
|
|
133
|
+
* @returns 是否包含该类名
|
|
134
|
+
*/
|
|
135
|
+
hasClass(el: HE, className: string): boolean;
|
|
136
|
+
/**
|
|
137
|
+
* 添加事件监听器
|
|
138
|
+
* @param el - 元素节点
|
|
139
|
+
* @param event - 事件名称
|
|
140
|
+
* @param handler - 事件处理函数
|
|
141
|
+
*/
|
|
142
|
+
addEventListener(el: HE, event: string, handler: (...args: unknown[]) => void): void;
|
|
143
|
+
/**
|
|
144
|
+
* 移除事件监听器
|
|
145
|
+
* @param el - 元素节点
|
|
146
|
+
* @param event - 事件名称
|
|
147
|
+
* @param handler - 事件处理函数
|
|
148
|
+
*/
|
|
149
|
+
removeEventListener(el: HE, event: string, handler: (...args: unknown[]) => void): void;
|
|
150
|
+
/**
|
|
151
|
+
* 查询匹配选择器的第一个元素
|
|
152
|
+
* @param selector - CSS 选择器
|
|
153
|
+
* @returns 匹配的元素,未找到时返回 null
|
|
154
|
+
*/
|
|
155
|
+
querySelector(selector: string): HE | null;
|
|
156
|
+
/**
|
|
157
|
+
* 查询匹配选择器的所有元素
|
|
158
|
+
* @param selector - CSS 选择器
|
|
159
|
+
* @returns 匹配的元素数组
|
|
160
|
+
*/
|
|
161
|
+
querySelectorAll(selector: string): HE[];
|
|
162
|
+
/**
|
|
163
|
+
* 注册平台就绪回调
|
|
164
|
+
* @param callback - 就绪时执行的回调函数
|
|
165
|
+
*/
|
|
166
|
+
onReady(callback: () => void): void;
|
|
167
|
+
/**
|
|
168
|
+
* 注册平台卸载回调
|
|
169
|
+
* @param callback - 卸载时执行的回调函数
|
|
170
|
+
*/
|
|
171
|
+
onUnmount(callback: () => void): void;
|
|
172
|
+
}
|
|
173
|
+
/**
|
|
174
|
+
* 平台配置
|
|
175
|
+
*
|
|
176
|
+
* @description
|
|
177
|
+
* 用于配置平台适配器的行为,如调试模式和自定义渲染器选项。
|
|
178
|
+
*/
|
|
179
|
+
interface PlatformConfig {
|
|
180
|
+
/** 是否启用调试模式 */
|
|
181
|
+
debug?: boolean;
|
|
182
|
+
/** 自定义渲染器选项 */
|
|
183
|
+
rendererOptions?: Record<string, unknown>;
|
|
184
|
+
}
|
|
185
|
+
/**
|
|
186
|
+
* 平台插件接口
|
|
187
|
+
*
|
|
188
|
+
* @description
|
|
189
|
+
* 允许扩展平台适配器的功能,插件可以在安装时修改适配器行为。
|
|
190
|
+
*
|
|
191
|
+
* @template HN - 宿主节点类型
|
|
192
|
+
* @template HE - 宿主元素类型
|
|
193
|
+
*
|
|
194
|
+
* @example
|
|
195
|
+
* ```typescript
|
|
196
|
+
* const analyticsPlugin: PlatformPlugin = {
|
|
197
|
+
* name: 'analytics',
|
|
198
|
+
* install(adapter) {
|
|
199
|
+
* const originalInsert = adapter.insert.bind(adapter);
|
|
200
|
+
* adapter.insert = (child, parent, anchor) => {
|
|
201
|
+
* console.log('节点插入', child);
|
|
202
|
+
* originalInsert(child, parent, anchor);
|
|
203
|
+
* };
|
|
204
|
+
* },
|
|
205
|
+
* uninstall() {
|
|
206
|
+
* console.log('分析插件已卸载');
|
|
207
|
+
* },
|
|
208
|
+
* };
|
|
209
|
+
* ```
|
|
210
|
+
*/
|
|
211
|
+
interface PlatformPlugin<HN = unknown, HE = unknown> {
|
|
212
|
+
/** 插件名称 */
|
|
213
|
+
name: string;
|
|
214
|
+
/** 安装插件到适配器 */
|
|
215
|
+
install(adapter: PlatformAdapter<HN, HE>): void;
|
|
216
|
+
/** 卸载插件(可选) */
|
|
217
|
+
uninstall?(): void;
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
/**
|
|
221
|
+
* 平台适配器注册表
|
|
222
|
+
*
|
|
223
|
+
* @description
|
|
224
|
+
* 管理所有已注册的平台适配器和插件,提供统一的注册、查询和插件管理能力。
|
|
225
|
+
* 采用单例模式,全局共享同一个注册表实例。
|
|
226
|
+
*/
|
|
227
|
+
|
|
228
|
+
/**
|
|
229
|
+
* 适配器注册表类
|
|
230
|
+
*
|
|
231
|
+
* @description
|
|
232
|
+
* 维护平台适配器的注册信息,支持适配器的注册、注销、查询,
|
|
233
|
+
* 以及平台级插件的管理。
|
|
234
|
+
*/
|
|
235
|
+
declare class AdapterRegistry {
|
|
236
|
+
/** 已注册的适配器映射(平台名称 -> 适配器实例) */
|
|
237
|
+
private adapters;
|
|
238
|
+
/** 平台插件映射(平台名称 -> 插件数组) */
|
|
239
|
+
private plugins;
|
|
240
|
+
/**
|
|
241
|
+
* 注册平台适配器
|
|
242
|
+
*
|
|
243
|
+
* @description
|
|
244
|
+
* 将适配器实例注册到注册表中,以适配器的 name 为键。
|
|
245
|
+
* 如果同名适配器已存在,将被覆盖。
|
|
246
|
+
*
|
|
247
|
+
* @param adapter - 平台适配器实例
|
|
248
|
+
* @throws {Error} 当 adapter.name 为空时抛出错误
|
|
249
|
+
*/
|
|
250
|
+
register(adapter: PlatformAdapter): void;
|
|
251
|
+
/**
|
|
252
|
+
* 注销平台适配器
|
|
253
|
+
*
|
|
254
|
+
* @description
|
|
255
|
+
* 从注册表中移除指定名称的适配器,同时清除该平台关联的所有插件。
|
|
256
|
+
*
|
|
257
|
+
* @param name - 平台名称
|
|
258
|
+
* @returns 是否成功注销(名称不存在时返回 false)
|
|
259
|
+
*/
|
|
260
|
+
unregister(name: string): boolean;
|
|
261
|
+
/**
|
|
262
|
+
* 获取指定名称的平台适配器
|
|
263
|
+
*
|
|
264
|
+
* @param name - 平台名称
|
|
265
|
+
* @returns 适配器实例,未找到时返回 undefined
|
|
266
|
+
*/
|
|
267
|
+
get(name: string): PlatformAdapter | undefined;
|
|
268
|
+
/**
|
|
269
|
+
* 检查指定名称的适配器是否已注册
|
|
270
|
+
*
|
|
271
|
+
* @param name - 平台名称
|
|
272
|
+
* @returns 是否已注册
|
|
273
|
+
*/
|
|
274
|
+
has(name: string): boolean;
|
|
275
|
+
/**
|
|
276
|
+
* 获取所有已注册的适配器名称
|
|
277
|
+
*
|
|
278
|
+
* @returns 平台名称数组
|
|
279
|
+
*/
|
|
280
|
+
getNames(): string[];
|
|
281
|
+
/**
|
|
282
|
+
* 为指定平台添加插件
|
|
283
|
+
*
|
|
284
|
+
* @description
|
|
285
|
+
* 将插件添加到目标平台的插件列表中。
|
|
286
|
+
* 如果目标平台不存在,会自动创建空的插件列表。
|
|
287
|
+
*
|
|
288
|
+
* @param platformName - 目标平台名称
|
|
289
|
+
* @param plugin - 平台插件实例
|
|
290
|
+
*/
|
|
291
|
+
addPlugin(platformName: string, plugin: PlatformPlugin): void;
|
|
292
|
+
/**
|
|
293
|
+
* 从指定平台移除插件
|
|
294
|
+
*
|
|
295
|
+
* @param platformName - 目标平台名称
|
|
296
|
+
* @param pluginName - 要移除的插件名称
|
|
297
|
+
* @returns 是否成功移除(插件不存在时返回 false)
|
|
298
|
+
*/
|
|
299
|
+
removePlugin(platformName: string, pluginName: string): boolean;
|
|
300
|
+
/**
|
|
301
|
+
* 获取指定平台的所有插件
|
|
302
|
+
*
|
|
303
|
+
* @param platformName - 目标平台名称
|
|
304
|
+
* @returns 插件数组,平台无插件时返回空数组
|
|
305
|
+
*/
|
|
306
|
+
getPlugins(platformName: string): PlatformPlugin[];
|
|
307
|
+
}
|
|
308
|
+
/** 全局适配器注册表单例 */
|
|
309
|
+
declare const adapterRegistry: AdapterRegistry;
|
|
310
|
+
|
|
311
|
+
/**
|
|
312
|
+
* 跨平台渲染器工厂
|
|
313
|
+
*
|
|
314
|
+
* @description
|
|
315
|
+
* 基于平台适配器创建渲染器实例,提供统一的 render/unmount API,
|
|
316
|
+
* 屏蔽底层平台差异。
|
|
317
|
+
*/
|
|
318
|
+
|
|
319
|
+
/**
|
|
320
|
+
* 平台渲染器接口
|
|
321
|
+
*
|
|
322
|
+
* @description
|
|
323
|
+
* 封装了平台适配器,提供高层的渲染和卸载 API。
|
|
324
|
+
*
|
|
325
|
+
* @template HN - 宿主节点类型
|
|
326
|
+
* @template HE - 宿主元素类型(extends HN)
|
|
327
|
+
*/
|
|
328
|
+
interface PlatformRenderer<HN, HE extends HN> {
|
|
329
|
+
/**
|
|
330
|
+
* 将 VNode 渲染到指定容器中
|
|
331
|
+
*
|
|
332
|
+
* @param vnode - 要渲染的虚拟节点
|
|
333
|
+
* @param container - 宿主容器节点
|
|
334
|
+
*/
|
|
335
|
+
render(vnode: VNode, container: HN): void;
|
|
336
|
+
/**
|
|
337
|
+
* 卸载指定容器中的内容
|
|
338
|
+
*
|
|
339
|
+
* @param container - 宿主容器节点
|
|
340
|
+
*/
|
|
341
|
+
unmount(container: HN): void;
|
|
342
|
+
/**
|
|
343
|
+
* 获取关联的平台适配器
|
|
344
|
+
*
|
|
345
|
+
* @returns 平台适配器实例
|
|
346
|
+
*/
|
|
347
|
+
getAdapter(): PlatformAdapter<HN, HE>;
|
|
348
|
+
}
|
|
349
|
+
/**
|
|
350
|
+
* 创建平台渲染器
|
|
351
|
+
*
|
|
352
|
+
* @description
|
|
353
|
+
* 工厂函数,基于给定的平台适配器和配置创建渲染器实例。
|
|
354
|
+
* 渲染器内部委托适配器完成实际的 DOM 操作。
|
|
355
|
+
*
|
|
356
|
+
* @template HN - 宿主节点类型
|
|
357
|
+
* @template HE - 宿主元素类型(extends HN)
|
|
358
|
+
* @param adapter - 平台适配器实例
|
|
359
|
+
* @param config - 平台配置(可选)
|
|
360
|
+
* @returns 平台渲染器实例
|
|
361
|
+
*
|
|
362
|
+
* @example
|
|
363
|
+
* ```typescript
|
|
364
|
+
* const renderer = createPlatformRenderer(myAdapter, { debug: true });
|
|
365
|
+
* renderer.render(vnode, container);
|
|
366
|
+
* ```
|
|
367
|
+
*/
|
|
368
|
+
declare function createPlatformRenderer<HN, HE extends HN>(adapter: PlatformAdapter<HN, HE>, config?: PlatformConfig): PlatformRenderer<HN, HE>;
|
|
369
|
+
|
|
370
|
+
export { type PlatformAdapter, type PlatformConfig, type PlatformPlugin, type PlatformRenderer, adapterRegistry, createPlatformRenderer };
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,370 @@
|
|
|
1
|
+
import { VNode } from '@lytjs/common-vnode';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* @lytjs/platform-adapter
|
|
5
|
+
* 平台适配器类型定义
|
|
6
|
+
*
|
|
7
|
+
* @description
|
|
8
|
+
* 定义跨平台渲染适配器的核心接口,所有平台实现必须遵循此契约。
|
|
9
|
+
* HN = Host Node(宿主节点),HE = Host Element(宿主元素)
|
|
10
|
+
*/
|
|
11
|
+
/**
|
|
12
|
+
* 平台适配器接口 - 所有平台必须实现此接口
|
|
13
|
+
*
|
|
14
|
+
* @description
|
|
15
|
+
* 提供跨平台的 DOM 操作抽象层,将底层平台差异封装为统一 API。
|
|
16
|
+
* 每个平台(Web、小程序、Node.js SSR 等)都需要提供自己的实现。
|
|
17
|
+
*
|
|
18
|
+
* @template HN - 宿主节点类型
|
|
19
|
+
* @template HE - 宿主元素类型(extends HN)
|
|
20
|
+
*
|
|
21
|
+
* @example
|
|
22
|
+
* ```typescript
|
|
23
|
+
* const webAdapter: PlatformAdapter<Node, Element> = {
|
|
24
|
+
* name: 'web',
|
|
25
|
+
* version: '1.0.0',
|
|
26
|
+
* createElement(tag) { return document.createElement(tag); },
|
|
27
|
+
* // ... 其他方法
|
|
28
|
+
* };
|
|
29
|
+
* ```
|
|
30
|
+
*/
|
|
31
|
+
interface PlatformAdapter<HN = unknown, HE = unknown> {
|
|
32
|
+
/** 平台名称(如 'web'、'miniapp'、'ssr') */
|
|
33
|
+
readonly name: string;
|
|
34
|
+
/** 平台版本号 */
|
|
35
|
+
readonly version: string;
|
|
36
|
+
/**
|
|
37
|
+
* 创建元素节点
|
|
38
|
+
* @param tag - 标签名
|
|
39
|
+
* @returns 创建的元素节点
|
|
40
|
+
*/
|
|
41
|
+
createElement(tag: string): HE;
|
|
42
|
+
/**
|
|
43
|
+
* 创建文本节点
|
|
44
|
+
* @param text - 文本内容
|
|
45
|
+
* @returns 创建的文本节点
|
|
46
|
+
*/
|
|
47
|
+
createText(text: string): HN;
|
|
48
|
+
/**
|
|
49
|
+
* 创建注释节点
|
|
50
|
+
* @param text - 注释内容
|
|
51
|
+
* @returns 创建的注释节点
|
|
52
|
+
*/
|
|
53
|
+
createComment(text: string): HN;
|
|
54
|
+
/**
|
|
55
|
+
* 插入子节点到父节点中
|
|
56
|
+
* @param child - 子节点
|
|
57
|
+
* @param parent - 父节点
|
|
58
|
+
* @param anchor - 参考锚点,插入到锚点之前
|
|
59
|
+
*/
|
|
60
|
+
insert(child: HN, parent: HN, anchor?: HN | null): void;
|
|
61
|
+
/**
|
|
62
|
+
* 移除子节点
|
|
63
|
+
* @param child - 要移除的节点
|
|
64
|
+
*/
|
|
65
|
+
remove(child: HN): void;
|
|
66
|
+
/**
|
|
67
|
+
* 设置元素节点的文本内容
|
|
68
|
+
* @param node - 元素节点
|
|
69
|
+
* @param text - 文本内容
|
|
70
|
+
*/
|
|
71
|
+
setElementText(node: HE, text: string): void;
|
|
72
|
+
/**
|
|
73
|
+
* 设置文本节点的内容
|
|
74
|
+
* @param node - 文本节点
|
|
75
|
+
* @param text - 文本内容
|
|
76
|
+
*/
|
|
77
|
+
setText(node: HN, text: string): void;
|
|
78
|
+
/**
|
|
79
|
+
* 设置元素属性
|
|
80
|
+
* @param el - 元素节点
|
|
81
|
+
* @param key - 属性名
|
|
82
|
+
* @param value - 属性值
|
|
83
|
+
*/
|
|
84
|
+
setAttribute(el: HE, key: string, value: string): void;
|
|
85
|
+
/**
|
|
86
|
+
* 移除元素属性
|
|
87
|
+
* @param el - 元素节点
|
|
88
|
+
* @param key - 属性名
|
|
89
|
+
*/
|
|
90
|
+
removeAttribute(el: HE, key: string): void;
|
|
91
|
+
/**
|
|
92
|
+
* 获取元素属性值
|
|
93
|
+
* @param el - 元素节点
|
|
94
|
+
* @param key - 属性名
|
|
95
|
+
* @returns 属性值,不存在时返回 null
|
|
96
|
+
*/
|
|
97
|
+
getAttribute(el: HE, key: string): string | null;
|
|
98
|
+
/**
|
|
99
|
+
* 检查元素是否拥有指定属性
|
|
100
|
+
* @param el - 元素节点
|
|
101
|
+
* @param key - 属性名
|
|
102
|
+
* @returns 是否存在该属性
|
|
103
|
+
*/
|
|
104
|
+
hasAttribute(el: HE, key: string): boolean;
|
|
105
|
+
/**
|
|
106
|
+
* 设置元素的行内样式
|
|
107
|
+
* @param el - 元素节点
|
|
108
|
+
* @param style - CSS 样式字符串
|
|
109
|
+
*/
|
|
110
|
+
setStyle(el: HE, style: string): void;
|
|
111
|
+
/**
|
|
112
|
+
* 获取元素的行内样式字符串
|
|
113
|
+
* @param el - 元素节点
|
|
114
|
+
* @returns CSS 样式字符串
|
|
115
|
+
*/
|
|
116
|
+
getStyle(el: HE): string;
|
|
117
|
+
/**
|
|
118
|
+
* 添加 CSS 类名
|
|
119
|
+
* @param el - 元素节点
|
|
120
|
+
* @param className - 类名
|
|
121
|
+
*/
|
|
122
|
+
addClass(el: HE, className: string): void;
|
|
123
|
+
/**
|
|
124
|
+
* 移除 CSS 类名
|
|
125
|
+
* @param el - 元素节点
|
|
126
|
+
* @param className - 类名
|
|
127
|
+
*/
|
|
128
|
+
removeClass(el: HE, className: string): void;
|
|
129
|
+
/**
|
|
130
|
+
* 检查元素是否包含指定类名
|
|
131
|
+
* @param el - 元素节点
|
|
132
|
+
* @param className - 类名
|
|
133
|
+
* @returns 是否包含该类名
|
|
134
|
+
*/
|
|
135
|
+
hasClass(el: HE, className: string): boolean;
|
|
136
|
+
/**
|
|
137
|
+
* 添加事件监听器
|
|
138
|
+
* @param el - 元素节点
|
|
139
|
+
* @param event - 事件名称
|
|
140
|
+
* @param handler - 事件处理函数
|
|
141
|
+
*/
|
|
142
|
+
addEventListener(el: HE, event: string, handler: (...args: unknown[]) => void): void;
|
|
143
|
+
/**
|
|
144
|
+
* 移除事件监听器
|
|
145
|
+
* @param el - 元素节点
|
|
146
|
+
* @param event - 事件名称
|
|
147
|
+
* @param handler - 事件处理函数
|
|
148
|
+
*/
|
|
149
|
+
removeEventListener(el: HE, event: string, handler: (...args: unknown[]) => void): void;
|
|
150
|
+
/**
|
|
151
|
+
* 查询匹配选择器的第一个元素
|
|
152
|
+
* @param selector - CSS 选择器
|
|
153
|
+
* @returns 匹配的元素,未找到时返回 null
|
|
154
|
+
*/
|
|
155
|
+
querySelector(selector: string): HE | null;
|
|
156
|
+
/**
|
|
157
|
+
* 查询匹配选择器的所有元素
|
|
158
|
+
* @param selector - CSS 选择器
|
|
159
|
+
* @returns 匹配的元素数组
|
|
160
|
+
*/
|
|
161
|
+
querySelectorAll(selector: string): HE[];
|
|
162
|
+
/**
|
|
163
|
+
* 注册平台就绪回调
|
|
164
|
+
* @param callback - 就绪时执行的回调函数
|
|
165
|
+
*/
|
|
166
|
+
onReady(callback: () => void): void;
|
|
167
|
+
/**
|
|
168
|
+
* 注册平台卸载回调
|
|
169
|
+
* @param callback - 卸载时执行的回调函数
|
|
170
|
+
*/
|
|
171
|
+
onUnmount(callback: () => void): void;
|
|
172
|
+
}
|
|
173
|
+
/**
|
|
174
|
+
* 平台配置
|
|
175
|
+
*
|
|
176
|
+
* @description
|
|
177
|
+
* 用于配置平台适配器的行为,如调试模式和自定义渲染器选项。
|
|
178
|
+
*/
|
|
179
|
+
interface PlatformConfig {
|
|
180
|
+
/** 是否启用调试模式 */
|
|
181
|
+
debug?: boolean;
|
|
182
|
+
/** 自定义渲染器选项 */
|
|
183
|
+
rendererOptions?: Record<string, unknown>;
|
|
184
|
+
}
|
|
185
|
+
/**
|
|
186
|
+
* 平台插件接口
|
|
187
|
+
*
|
|
188
|
+
* @description
|
|
189
|
+
* 允许扩展平台适配器的功能,插件可以在安装时修改适配器行为。
|
|
190
|
+
*
|
|
191
|
+
* @template HN - 宿主节点类型
|
|
192
|
+
* @template HE - 宿主元素类型
|
|
193
|
+
*
|
|
194
|
+
* @example
|
|
195
|
+
* ```typescript
|
|
196
|
+
* const analyticsPlugin: PlatformPlugin = {
|
|
197
|
+
* name: 'analytics',
|
|
198
|
+
* install(adapter) {
|
|
199
|
+
* const originalInsert = adapter.insert.bind(adapter);
|
|
200
|
+
* adapter.insert = (child, parent, anchor) => {
|
|
201
|
+
* console.log('节点插入', child);
|
|
202
|
+
* originalInsert(child, parent, anchor);
|
|
203
|
+
* };
|
|
204
|
+
* },
|
|
205
|
+
* uninstall() {
|
|
206
|
+
* console.log('分析插件已卸载');
|
|
207
|
+
* },
|
|
208
|
+
* };
|
|
209
|
+
* ```
|
|
210
|
+
*/
|
|
211
|
+
interface PlatformPlugin<HN = unknown, HE = unknown> {
|
|
212
|
+
/** 插件名称 */
|
|
213
|
+
name: string;
|
|
214
|
+
/** 安装插件到适配器 */
|
|
215
|
+
install(adapter: PlatformAdapter<HN, HE>): void;
|
|
216
|
+
/** 卸载插件(可选) */
|
|
217
|
+
uninstall?(): void;
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
/**
|
|
221
|
+
* 平台适配器注册表
|
|
222
|
+
*
|
|
223
|
+
* @description
|
|
224
|
+
* 管理所有已注册的平台适配器和插件,提供统一的注册、查询和插件管理能力。
|
|
225
|
+
* 采用单例模式,全局共享同一个注册表实例。
|
|
226
|
+
*/
|
|
227
|
+
|
|
228
|
+
/**
|
|
229
|
+
* 适配器注册表类
|
|
230
|
+
*
|
|
231
|
+
* @description
|
|
232
|
+
* 维护平台适配器的注册信息,支持适配器的注册、注销、查询,
|
|
233
|
+
* 以及平台级插件的管理。
|
|
234
|
+
*/
|
|
235
|
+
declare class AdapterRegistry {
|
|
236
|
+
/** 已注册的适配器映射(平台名称 -> 适配器实例) */
|
|
237
|
+
private adapters;
|
|
238
|
+
/** 平台插件映射(平台名称 -> 插件数组) */
|
|
239
|
+
private plugins;
|
|
240
|
+
/**
|
|
241
|
+
* 注册平台适配器
|
|
242
|
+
*
|
|
243
|
+
* @description
|
|
244
|
+
* 将适配器实例注册到注册表中,以适配器的 name 为键。
|
|
245
|
+
* 如果同名适配器已存在,将被覆盖。
|
|
246
|
+
*
|
|
247
|
+
* @param adapter - 平台适配器实例
|
|
248
|
+
* @throws {Error} 当 adapter.name 为空时抛出错误
|
|
249
|
+
*/
|
|
250
|
+
register(adapter: PlatformAdapter): void;
|
|
251
|
+
/**
|
|
252
|
+
* 注销平台适配器
|
|
253
|
+
*
|
|
254
|
+
* @description
|
|
255
|
+
* 从注册表中移除指定名称的适配器,同时清除该平台关联的所有插件。
|
|
256
|
+
*
|
|
257
|
+
* @param name - 平台名称
|
|
258
|
+
* @returns 是否成功注销(名称不存在时返回 false)
|
|
259
|
+
*/
|
|
260
|
+
unregister(name: string): boolean;
|
|
261
|
+
/**
|
|
262
|
+
* 获取指定名称的平台适配器
|
|
263
|
+
*
|
|
264
|
+
* @param name - 平台名称
|
|
265
|
+
* @returns 适配器实例,未找到时返回 undefined
|
|
266
|
+
*/
|
|
267
|
+
get(name: string): PlatformAdapter | undefined;
|
|
268
|
+
/**
|
|
269
|
+
* 检查指定名称的适配器是否已注册
|
|
270
|
+
*
|
|
271
|
+
* @param name - 平台名称
|
|
272
|
+
* @returns 是否已注册
|
|
273
|
+
*/
|
|
274
|
+
has(name: string): boolean;
|
|
275
|
+
/**
|
|
276
|
+
* 获取所有已注册的适配器名称
|
|
277
|
+
*
|
|
278
|
+
* @returns 平台名称数组
|
|
279
|
+
*/
|
|
280
|
+
getNames(): string[];
|
|
281
|
+
/**
|
|
282
|
+
* 为指定平台添加插件
|
|
283
|
+
*
|
|
284
|
+
* @description
|
|
285
|
+
* 将插件添加到目标平台的插件列表中。
|
|
286
|
+
* 如果目标平台不存在,会自动创建空的插件列表。
|
|
287
|
+
*
|
|
288
|
+
* @param platformName - 目标平台名称
|
|
289
|
+
* @param plugin - 平台插件实例
|
|
290
|
+
*/
|
|
291
|
+
addPlugin(platformName: string, plugin: PlatformPlugin): void;
|
|
292
|
+
/**
|
|
293
|
+
* 从指定平台移除插件
|
|
294
|
+
*
|
|
295
|
+
* @param platformName - 目标平台名称
|
|
296
|
+
* @param pluginName - 要移除的插件名称
|
|
297
|
+
* @returns 是否成功移除(插件不存在时返回 false)
|
|
298
|
+
*/
|
|
299
|
+
removePlugin(platformName: string, pluginName: string): boolean;
|
|
300
|
+
/**
|
|
301
|
+
* 获取指定平台的所有插件
|
|
302
|
+
*
|
|
303
|
+
* @param platformName - 目标平台名称
|
|
304
|
+
* @returns 插件数组,平台无插件时返回空数组
|
|
305
|
+
*/
|
|
306
|
+
getPlugins(platformName: string): PlatformPlugin[];
|
|
307
|
+
}
|
|
308
|
+
/** 全局适配器注册表单例 */
|
|
309
|
+
declare const adapterRegistry: AdapterRegistry;
|
|
310
|
+
|
|
311
|
+
/**
|
|
312
|
+
* 跨平台渲染器工厂
|
|
313
|
+
*
|
|
314
|
+
* @description
|
|
315
|
+
* 基于平台适配器创建渲染器实例,提供统一的 render/unmount API,
|
|
316
|
+
* 屏蔽底层平台差异。
|
|
317
|
+
*/
|
|
318
|
+
|
|
319
|
+
/**
|
|
320
|
+
* 平台渲染器接口
|
|
321
|
+
*
|
|
322
|
+
* @description
|
|
323
|
+
* 封装了平台适配器,提供高层的渲染和卸载 API。
|
|
324
|
+
*
|
|
325
|
+
* @template HN - 宿主节点类型
|
|
326
|
+
* @template HE - 宿主元素类型(extends HN)
|
|
327
|
+
*/
|
|
328
|
+
interface PlatformRenderer<HN, HE extends HN> {
|
|
329
|
+
/**
|
|
330
|
+
* 将 VNode 渲染到指定容器中
|
|
331
|
+
*
|
|
332
|
+
* @param vnode - 要渲染的虚拟节点
|
|
333
|
+
* @param container - 宿主容器节点
|
|
334
|
+
*/
|
|
335
|
+
render(vnode: VNode, container: HN): void;
|
|
336
|
+
/**
|
|
337
|
+
* 卸载指定容器中的内容
|
|
338
|
+
*
|
|
339
|
+
* @param container - 宿主容器节点
|
|
340
|
+
*/
|
|
341
|
+
unmount(container: HN): void;
|
|
342
|
+
/**
|
|
343
|
+
* 获取关联的平台适配器
|
|
344
|
+
*
|
|
345
|
+
* @returns 平台适配器实例
|
|
346
|
+
*/
|
|
347
|
+
getAdapter(): PlatformAdapter<HN, HE>;
|
|
348
|
+
}
|
|
349
|
+
/**
|
|
350
|
+
* 创建平台渲染器
|
|
351
|
+
*
|
|
352
|
+
* @description
|
|
353
|
+
* 工厂函数,基于给定的平台适配器和配置创建渲染器实例。
|
|
354
|
+
* 渲染器内部委托适配器完成实际的 DOM 操作。
|
|
355
|
+
*
|
|
356
|
+
* @template HN - 宿主节点类型
|
|
357
|
+
* @template HE - 宿主元素类型(extends HN)
|
|
358
|
+
* @param adapter - 平台适配器实例
|
|
359
|
+
* @param config - 平台配置(可选)
|
|
360
|
+
* @returns 平台渲染器实例
|
|
361
|
+
*
|
|
362
|
+
* @example
|
|
363
|
+
* ```typescript
|
|
364
|
+
* const renderer = createPlatformRenderer(myAdapter, { debug: true });
|
|
365
|
+
* renderer.render(vnode, container);
|
|
366
|
+
* ```
|
|
367
|
+
*/
|
|
368
|
+
declare function createPlatformRenderer<HN, HE extends HN>(adapter: PlatformAdapter<HN, HE>, config?: PlatformConfig): PlatformRenderer<HN, HE>;
|
|
369
|
+
|
|
370
|
+
export { type PlatformAdapter, type PlatformConfig, type PlatformPlugin, type PlatformRenderer, adapterRegistry, createPlatformRenderer };
|
package/dist/index.mjs
ADDED
|
@@ -0,0 +1,190 @@
|
|
|
1
|
+
import { isString, isFunction } from '@lytjs/common-is';
|
|
2
|
+
|
|
3
|
+
// src/adapter-registry.ts
|
|
4
|
+
var AdapterRegistry = class {
|
|
5
|
+
constructor() {
|
|
6
|
+
/** 已注册的适配器映射(平台名称 -> 适配器实例) */
|
|
7
|
+
this.adapters = /* @__PURE__ */ new Map();
|
|
8
|
+
/** 平台插件映射(平台名称 -> 插件数组) */
|
|
9
|
+
this.plugins = /* @__PURE__ */ new Map();
|
|
10
|
+
}
|
|
11
|
+
/**
|
|
12
|
+
* 注册平台适配器
|
|
13
|
+
*
|
|
14
|
+
* @description
|
|
15
|
+
* 将适配器实例注册到注册表中,以适配器的 name 为键。
|
|
16
|
+
* 如果同名适配器已存在,将被覆盖。
|
|
17
|
+
*
|
|
18
|
+
* @param adapter - 平台适配器实例
|
|
19
|
+
* @throws {Error} 当 adapter.name 为空时抛出错误
|
|
20
|
+
*/
|
|
21
|
+
register(adapter) {
|
|
22
|
+
if (!isString(adapter.name) || adapter.name.length === 0) {
|
|
23
|
+
throw new Error(
|
|
24
|
+
"[platform-adapter] \u9002\u914D\u5668\u540D\u79F0\u4E0D\u80FD\u4E3A\u7A7A"
|
|
25
|
+
);
|
|
26
|
+
}
|
|
27
|
+
this.adapters.set(adapter.name, adapter);
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* 注销平台适配器
|
|
31
|
+
*
|
|
32
|
+
* @description
|
|
33
|
+
* 从注册表中移除指定名称的适配器,同时清除该平台关联的所有插件。
|
|
34
|
+
*
|
|
35
|
+
* @param name - 平台名称
|
|
36
|
+
* @returns 是否成功注销(名称不存在时返回 false)
|
|
37
|
+
*/
|
|
38
|
+
unregister(name) {
|
|
39
|
+
const removed = this.adapters.delete(name);
|
|
40
|
+
if (removed) {
|
|
41
|
+
this.plugins.delete(name);
|
|
42
|
+
}
|
|
43
|
+
return removed;
|
|
44
|
+
}
|
|
45
|
+
/**
|
|
46
|
+
* 获取指定名称的平台适配器
|
|
47
|
+
*
|
|
48
|
+
* @param name - 平台名称
|
|
49
|
+
* @returns 适配器实例,未找到时返回 undefined
|
|
50
|
+
*/
|
|
51
|
+
get(name) {
|
|
52
|
+
return this.adapters.get(name);
|
|
53
|
+
}
|
|
54
|
+
/**
|
|
55
|
+
* 检查指定名称的适配器是否已注册
|
|
56
|
+
*
|
|
57
|
+
* @param name - 平台名称
|
|
58
|
+
* @returns 是否已注册
|
|
59
|
+
*/
|
|
60
|
+
has(name) {
|
|
61
|
+
return this.adapters.has(name);
|
|
62
|
+
}
|
|
63
|
+
/**
|
|
64
|
+
* 获取所有已注册的适配器名称
|
|
65
|
+
*
|
|
66
|
+
* @returns 平台名称数组
|
|
67
|
+
*/
|
|
68
|
+
getNames() {
|
|
69
|
+
return Array.from(this.adapters.keys());
|
|
70
|
+
}
|
|
71
|
+
/**
|
|
72
|
+
* 为指定平台添加插件
|
|
73
|
+
*
|
|
74
|
+
* @description
|
|
75
|
+
* 将插件添加到目标平台的插件列表中。
|
|
76
|
+
* 如果目标平台不存在,会自动创建空的插件列表。
|
|
77
|
+
*
|
|
78
|
+
* @param platformName - 目标平台名称
|
|
79
|
+
* @param plugin - 平台插件实例
|
|
80
|
+
*/
|
|
81
|
+
addPlugin(platformName, plugin) {
|
|
82
|
+
const existing = this.plugins.get(platformName);
|
|
83
|
+
if (existing) {
|
|
84
|
+
existing.push(plugin);
|
|
85
|
+
} else {
|
|
86
|
+
this.plugins.set(platformName, [plugin]);
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
/**
|
|
90
|
+
* 从指定平台移除插件
|
|
91
|
+
*
|
|
92
|
+
* @param platformName - 目标平台名称
|
|
93
|
+
* @param pluginName - 要移除的插件名称
|
|
94
|
+
* @returns 是否成功移除(插件不存在时返回 false)
|
|
95
|
+
*/
|
|
96
|
+
removePlugin(platformName, pluginName) {
|
|
97
|
+
const list = this.plugins.get(platformName);
|
|
98
|
+
if (!list) return false;
|
|
99
|
+
const index = list.findIndex((p) => p.name === pluginName);
|
|
100
|
+
if (index === -1) return false;
|
|
101
|
+
list.splice(index, 1);
|
|
102
|
+
return true;
|
|
103
|
+
}
|
|
104
|
+
/**
|
|
105
|
+
* 获取指定平台的所有插件
|
|
106
|
+
*
|
|
107
|
+
* @param platformName - 目标平台名称
|
|
108
|
+
* @returns 插件数组,平台无插件时返回空数组
|
|
109
|
+
*/
|
|
110
|
+
getPlugins(platformName) {
|
|
111
|
+
return this.plugins.get(platformName) ?? [];
|
|
112
|
+
}
|
|
113
|
+
};
|
|
114
|
+
var adapterRegistry = new AdapterRegistry();
|
|
115
|
+
function createPlatformRenderer(adapter, config) {
|
|
116
|
+
let currentChild = null;
|
|
117
|
+
const renderer = {
|
|
118
|
+
/**
|
|
119
|
+
* 将 VNode 渲染到容器中
|
|
120
|
+
*
|
|
121
|
+
* @description
|
|
122
|
+
* 根据 vnode 类型创建对应的宿主节点,并插入到容器中。
|
|
123
|
+
* 如果容器中已有内容,会先卸载再重新渲染。
|
|
124
|
+
*/
|
|
125
|
+
render(vnode, container) {
|
|
126
|
+
if (currentChild !== null) {
|
|
127
|
+
this.unmount(container);
|
|
128
|
+
}
|
|
129
|
+
const node = createHostNodeFromVNode(adapter, vnode);
|
|
130
|
+
if (node !== null) {
|
|
131
|
+
adapter.insert(node, container, null);
|
|
132
|
+
currentChild = node;
|
|
133
|
+
}
|
|
134
|
+
if (config?.debug) {
|
|
135
|
+
console.log(`[platform-adapter:${adapter.name}] \u6E32\u67D3\u5B8C\u6210`, vnode);
|
|
136
|
+
}
|
|
137
|
+
},
|
|
138
|
+
/**
|
|
139
|
+
* 卸载容器中的内容
|
|
140
|
+
*/
|
|
141
|
+
unmount(_container) {
|
|
142
|
+
if (currentChild !== null) {
|
|
143
|
+
adapter.remove(currentChild);
|
|
144
|
+
currentChild = null;
|
|
145
|
+
}
|
|
146
|
+
if (config?.debug) {
|
|
147
|
+
console.log(`[platform-adapter:${adapter.name}] \u5378\u8F7D\u5B8C\u6210`);
|
|
148
|
+
}
|
|
149
|
+
},
|
|
150
|
+
/**
|
|
151
|
+
* 获取关联的平台适配器
|
|
152
|
+
*/
|
|
153
|
+
getAdapter() {
|
|
154
|
+
return adapter;
|
|
155
|
+
}
|
|
156
|
+
};
|
|
157
|
+
return renderer;
|
|
158
|
+
}
|
|
159
|
+
function createHostNodeFromVNode(adapter, vnode) {
|
|
160
|
+
const { type, children } = vnode;
|
|
161
|
+
if (isString(type)) {
|
|
162
|
+
const el = adapter.createElement(type);
|
|
163
|
+
if (vnode.props) {
|
|
164
|
+
for (const [key, value] of Object.entries(vnode.props)) {
|
|
165
|
+
if (key === "style" && isString(value)) {
|
|
166
|
+
adapter.setStyle(el, value);
|
|
167
|
+
} else if (key === "class" && isString(value)) {
|
|
168
|
+
adapter.addClass(el, value);
|
|
169
|
+
} else if (isString(value)) {
|
|
170
|
+
adapter.setAttribute(el, key, value);
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
if (children && isString(children)) {
|
|
175
|
+
adapter.setElementText(el, children);
|
|
176
|
+
}
|
|
177
|
+
return el;
|
|
178
|
+
}
|
|
179
|
+
if (isString(children)) {
|
|
180
|
+
return adapter.createText(children);
|
|
181
|
+
}
|
|
182
|
+
if (isFunction(type) === false && type !== null && !isString(type)) {
|
|
183
|
+
return adapter.createComment(String(children ?? ""));
|
|
184
|
+
}
|
|
185
|
+
return null;
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
export { adapterRegistry, createPlatformRenderer };
|
|
189
|
+
//# sourceMappingURL=index.mjs.map
|
|
190
|
+
//# sourceMappingURL=index.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/adapter-registry.ts","../src/create-renderer.ts"],"names":["isString"],"mappings":";;;AAkBA,IAAM,kBAAN,MAAsB;AAAA,EAAtB,WAAA,GAAA;AAEE;AAAA,IAAA,IAAA,CAAQ,QAAA,uBAAe,GAAA,EAA6B;AAEpD;AAAA,IAAA,IAAA,CAAQ,OAAA,uBAAc,GAAA,EAA8B;AAAA,EAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAYpD,SAAS,OAAA,EAAgC;AACvC,IAAA,IAAI,CAAC,SAAS,OAAA,CAAQ,IAAI,KAAK,OAAA,CAAQ,IAAA,CAAK,WAAW,CAAA,EAAG;AACxD,MAAA,MAAM,IAAI,KAAA;AAAA,QACR;AAAA,OACF;AAAA,IACF;AACA,IAAA,IAAA,CAAK,QAAA,CAAS,GAAA,CAAI,OAAA,CAAQ,IAAA,EAAM,OAAO,CAAA;AAAA,EACzC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAWA,WAAW,IAAA,EAAuB;AAChC,IAAA,MAAM,OAAA,GAAU,IAAA,CAAK,QAAA,CAAS,MAAA,CAAO,IAAI,CAAA;AACzC,IAAA,IAAI,OAAA,EAAS;AACX,MAAA,IAAA,CAAK,OAAA,CAAQ,OAAO,IAAI,CAAA;AAAA,IAC1B;AACA,IAAA,OAAO,OAAA;AAAA,EACT;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQA,IAAI,IAAA,EAA2C;AAC7C,IAAA,OAAO,IAAA,CAAK,QAAA,CAAS,GAAA,CAAI,IAAI,CAAA;AAAA,EAC/B;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQA,IAAI,IAAA,EAAuB;AACzB,IAAA,OAAO,IAAA,CAAK,QAAA,CAAS,GAAA,CAAI,IAAI,CAAA;AAAA,EAC/B;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,QAAA,GAAqB;AACnB,IAAA,OAAO,KAAA,CAAM,IAAA,CAAK,IAAA,CAAK,QAAA,CAAS,MAAM,CAAA;AAAA,EACxC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAYA,SAAA,CAAU,cAAsB,MAAA,EAA8B;AAC5D,IAAA,MAAM,QAAA,GAAW,IAAA,CAAK,OAAA,CAAQ,GAAA,CAAI,YAAY,CAAA;AAC9C,IAAA,IAAI,QAAA,EAAU;AACZ,MAAA,QAAA,CAAS,KAAK,MAAM,CAAA;AAAA,IACtB,CAAA,MAAO;AACL,MAAA,IAAA,CAAK,OAAA,CAAQ,GAAA,CAAI,YAAA,EAAc,CAAC,MAAM,CAAC,CAAA;AAAA,IACzC;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EASA,YAAA,CAAa,cAAsB,UAAA,EAA6B;AAC9D,IAAA,MAAM,IAAA,GAAO,IAAA,CAAK,OAAA,CAAQ,GAAA,CAAI,YAAY,CAAA;AAC1C,IAAA,IAAI,CAAC,MAAM,OAAO,KAAA;AAElB,IAAA,MAAM,QAAQ,IAAA,CAAK,SAAA,CAAU,CAAC,CAAA,KAAM,CAAA,CAAE,SAAS,UAAU,CAAA;AACzD,IAAA,IAAI,KAAA,KAAU,IAAI,OAAO,KAAA;AAEzB,IAAA,IAAA,CAAK,MAAA,CAAO,OAAO,CAAC,CAAA;AACpB,IAAA,OAAO,IAAA;AAAA,EACT;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQA,WAAW,YAAA,EAAwC;AACjD,IAAA,OAAO,IAAA,CAAK,OAAA,CAAQ,GAAA,CAAI,YAAY,KAAK,EAAC;AAAA,EAC5C;AACF,CAAA;AAGO,IAAM,eAAA,GAAkB,IAAI,eAAA;AC1E5B,SAAS,sBAAA,CACd,SACA,MAAA,EAC0B;AAE1B,EAAA,IAAI,YAAA,GAA0B,IAAA;AAE9B,EAAA,MAAM,QAAA,GAAqC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,IAQzC,MAAA,CAAO,OAAc,SAAA,EAAqB;AAExC,MAAA,IAAI,iBAAiB,IAAA,EAAM;AACzB,QAAA,IAAA,CAAK,QAAQ,SAAS,CAAA;AAAA,MACxB;AAEA,MAAA,MAAM,IAAA,GAAO,uBAAA,CAAwB,OAAA,EAAS,KAAK,CAAA;AACnD,MAAA,IAAI,SAAS,IAAA,EAAM;AACjB,QAAA,OAAA,CAAQ,MAAA,CAAO,IAAA,EAAM,SAAA,EAAW,IAAI,CAAA;AACpC,QAAA,YAAA,GAAe,IAAA;AAAA,MACjB;AAEA,MAAA,IAAI,QAAQ,KAAA,EAAO;AAEjB,QAAA,OAAA,CAAQ,GAAA,CAAI,CAAA,kBAAA,EAAqB,OAAA,CAAQ,IAAI,8BAAU,KAAK,CAAA;AAAA,MAC9D;AAAA,IACF,CAAA;AAAA;AAAA;AAAA;AAAA,IAKA,QAAQ,UAAA,EAAsB;AAC5B,MAAA,IAAI,iBAAiB,IAAA,EAAM;AACzB,QAAA,OAAA,CAAQ,OAAO,YAAY,CAAA;AAC3B,QAAA,YAAA,GAAe,IAAA;AAAA,MACjB;AAEA,MAAA,IAAI,QAAQ,KAAA,EAAO;AAEjB,QAAA,OAAA,CAAQ,GAAA,CAAI,CAAA,kBAAA,EAAqB,OAAA,CAAQ,IAAI,CAAA,0BAAA,CAAQ,CAAA;AAAA,MACvD;AAAA,IACF,CAAA;AAAA;AAAA;AAAA;AAAA,IAKA,UAAA,GAAsC;AACpC,MAAA,OAAO,OAAA;AAAA,IACT;AAAA,GACF;AAEA,EAAA,OAAO,QAAA;AACT;AAaA,SAAS,uBAAA,CACP,SACA,KAAA,EACW;AACX,EAAA,MAAM,EAAE,IAAA,EAAM,QAAA,EAAS,GAAI,KAAA;AAG3B,EAAA,IAAIA,QAAAA,CAAS,IAAI,CAAA,EAAG;AAClB,IAAA,MAAM,EAAA,GAAK,OAAA,CAAQ,aAAA,CAAc,IAAI,CAAA;AAGrC,IAAA,IAAI,MAAM,KAAA,EAAO;AACf,MAAA,KAAA,MAAW,CAAC,KAAK,KAAK,CAAA,IAAK,OAAO,OAAA,CAAQ,KAAA,CAAM,KAAK,CAAA,EAAG;AACtD,QAAA,IAAI,GAAA,KAAQ,OAAA,IAAWA,QAAAA,CAAS,KAAK,CAAA,EAAG;AACtC,UAAA,OAAA,CAAQ,QAAA,CAAS,IAAI,KAAK,CAAA;AAAA,QAC5B,CAAA,MAAA,IAAW,GAAA,KAAQ,OAAA,IAAWA,QAAAA,CAAS,KAAK,CAAA,EAAG;AAC7C,UAAA,OAAA,CAAQ,QAAA,CAAS,IAAI,KAAK,CAAA;AAAA,QAC5B,CAAA,MAAA,IAAWA,QAAAA,CAAS,KAAK,CAAA,EAAG;AAC1B,UAAA,OAAA,CAAQ,YAAA,CAAa,EAAA,EAAI,GAAA,EAAK,KAAK,CAAA;AAAA,QACrC;AAAA,MACF;AAAA,IACF;AAGA,IAAA,IAAI,QAAA,IAAYA,QAAAA,CAAS,QAAQ,CAAA,EAAG;AAClC,MAAA,OAAA,CAAQ,cAAA,CAAe,IAAI,QAAQ,CAAA;AAAA,IACrC;AAEA,IAAA,OAAO,EAAA;AAAA,EACT;AAGA,EAAA,IAAIA,QAAAA,CAAS,QAAQ,CAAA,EAAG;AACtB,IAAA,OAAO,OAAA,CAAQ,WAAW,QAAQ,CAAA;AAAA,EACpC;AAGA,EAAA,IAAI,UAAA,CAAW,IAAI,CAAA,KAAM,KAAA,IAAS,SAAS,IAAA,IAAQ,CAACA,QAAAA,CAAS,IAAI,CAAA,EAAG;AAElE,IAAA,OAAO,OAAA,CAAQ,aAAA,CAAc,MAAA,CAAO,QAAA,IAAY,EAAE,CAAC,CAAA;AAAA,EACrD;AAEA,EAAA,OAAO,IAAA;AACT","file":"index.mjs","sourcesContent":["/**\r\n * 平台适配器注册表\r\n *\r\n * @description\r\n * 管理所有已注册的平台适配器和插件,提供统一的注册、查询和插件管理能力。\r\n * 采用单例模式,全局共享同一个注册表实例。\r\n */\r\n\r\nimport { isString } from '@lytjs/common-is';\r\nimport type { PlatformAdapter, PlatformPlugin } from './types';\r\n\r\n/**\r\n * 适配器注册表类\r\n *\r\n * @description\r\n * 维护平台适配器的注册信息,支持适配器的注册、注销、查询,\r\n * 以及平台级插件的管理。\r\n */\r\nclass AdapterRegistry {\r\n /** 已注册的适配器映射(平台名称 -> 适配器实例) */\r\n private adapters = new Map<string, PlatformAdapter>();\r\n /** 平台插件映射(平台名称 -> 插件数组) */\r\n private plugins = new Map<string, PlatformPlugin[]>();\r\n\r\n /**\r\n * 注册平台适配器\r\n *\r\n * @description\r\n * 将适配器实例注册到注册表中,以适配器的 name 为键。\r\n * 如果同名适配器已存在,将被覆盖。\r\n *\r\n * @param adapter - 平台适配器实例\r\n * @throws {Error} 当 adapter.name 为空时抛出错误\r\n */\r\n register(adapter: PlatformAdapter): void {\r\n if (!isString(adapter.name) || adapter.name.length === 0) {\r\n throw new Error(\r\n '[platform-adapter] 适配器名称不能为空',\r\n );\r\n }\r\n this.adapters.set(adapter.name, adapter);\r\n }\r\n\r\n /**\r\n * 注销平台适配器\r\n *\r\n * @description\r\n * 从注册表中移除指定名称的适配器,同时清除该平台关联的所有插件。\r\n *\r\n * @param name - 平台名称\r\n * @returns 是否成功注销(名称不存在时返回 false)\r\n */\r\n unregister(name: string): boolean {\r\n const removed = this.adapters.delete(name);\r\n if (removed) {\r\n this.plugins.delete(name);\r\n }\r\n return removed;\r\n }\r\n\r\n /**\r\n * 获取指定名称的平台适配器\r\n *\r\n * @param name - 平台名称\r\n * @returns 适配器实例,未找到时返回 undefined\r\n */\r\n get(name: string): PlatformAdapter | undefined {\r\n return this.adapters.get(name);\r\n }\r\n\r\n /**\r\n * 检查指定名称的适配器是否已注册\r\n *\r\n * @param name - 平台名称\r\n * @returns 是否已注册\r\n */\r\n has(name: string): boolean {\r\n return this.adapters.has(name);\r\n }\r\n\r\n /**\r\n * 获取所有已注册的适配器名称\r\n *\r\n * @returns 平台名称数组\r\n */\r\n getNames(): string[] {\r\n return Array.from(this.adapters.keys());\r\n }\r\n\r\n /**\r\n * 为指定平台添加插件\r\n *\r\n * @description\r\n * 将插件添加到目标平台的插件列表中。\r\n * 如果目标平台不存在,会自动创建空的插件列表。\r\n *\r\n * @param platformName - 目标平台名称\r\n * @param plugin - 平台插件实例\r\n */\r\n addPlugin(platformName: string, plugin: PlatformPlugin): void {\r\n const existing = this.plugins.get(platformName);\r\n if (existing) {\r\n existing.push(plugin);\r\n } else {\r\n this.plugins.set(platformName, [plugin]);\r\n }\r\n }\r\n\r\n /**\r\n * 从指定平台移除插件\r\n *\r\n * @param platformName - 目标平台名称\r\n * @param pluginName - 要移除的插件名称\r\n * @returns 是否成功移除(插件不存在时返回 false)\r\n */\r\n removePlugin(platformName: string, pluginName: string): boolean {\r\n const list = this.plugins.get(platformName);\r\n if (!list) return false;\r\n\r\n const index = list.findIndex((p) => p.name === pluginName);\r\n if (index === -1) return false;\r\n\r\n list.splice(index, 1);\r\n return true;\r\n }\r\n\r\n /**\r\n * 获取指定平台的所有插件\r\n *\r\n * @param platformName - 目标平台名称\r\n * @returns 插件数组,平台无插件时返回空数组\r\n */\r\n getPlugins(platformName: string): PlatformPlugin[] {\r\n return this.plugins.get(platformName) ?? [];\r\n }\r\n}\r\n\r\n/** 全局适配器注册表单例 */\r\nexport const adapterRegistry = new AdapterRegistry();\r\n","/**\r\n * 跨平台渲染器工厂\r\n *\r\n * @description\r\n * 基于平台适配器创建渲染器实例,提供统一的 render/unmount API,\r\n * 屏蔽底层平台差异。\r\n */\r\n\r\nimport { isFunction, isString } from '@lytjs/common-is';\r\nimport type { VNode } from '@lytjs/common-vnode';\r\nimport type { PlatformAdapter, PlatformConfig } from './types';\r\n\r\n/**\r\n * 平台渲染器接口\r\n *\r\n * @description\r\n * 封装了平台适配器,提供高层的渲染和卸载 API。\r\n *\r\n * @template HN - 宿主节点类型\r\n * @template HE - 宿主元素类型(extends HN)\r\n */\r\nexport interface PlatformRenderer<HN, HE extends HN> {\r\n /**\r\n * 将 VNode 渲染到指定容器中\r\n *\r\n * @param vnode - 要渲染的虚拟节点\r\n * @param container - 宿主容器节点\r\n */\r\n render(vnode: VNode, container: HN): void;\r\n\r\n /**\r\n * 卸载指定容器中的内容\r\n *\r\n * @param container - 宿主容器节点\r\n */\r\n unmount(container: HN): void;\r\n\r\n /**\r\n * 获取关联的平台适配器\r\n *\r\n * @returns 平台适配器实例\r\n */\r\n getAdapter(): PlatformAdapter<HN, HE>;\r\n}\r\n\r\n/**\r\n * 创建平台渲染器\r\n *\r\n * @description\r\n * 工厂函数,基于给定的平台适配器和配置创建渲染器实例。\r\n * 渲染器内部委托适配器完成实际的 DOM 操作。\r\n *\r\n * @template HN - 宿主节点类型\r\n * @template HE - 宿主元素类型(extends HN)\r\n * @param adapter - 平台适配器实例\r\n * @param config - 平台配置(可选)\r\n * @returns 平台渲染器实例\r\n *\r\n * @example\r\n * ```typescript\r\n * const renderer = createPlatformRenderer(myAdapter, { debug: true });\r\n * renderer.render(vnode, container);\r\n * ```\r\n */\r\nexport function createPlatformRenderer<HN, HE extends HN>(\r\n adapter: PlatformAdapter<HN, HE>,\r\n config?: PlatformConfig,\r\n): PlatformRenderer<HN, HE> {\r\n // 当前容器中已渲染的子节点引用\r\n let currentChild: HN | null = null;\r\n\r\n const renderer: PlatformRenderer<HN, HE> = {\r\n /**\r\n * 将 VNode 渲染到容器中\r\n *\r\n * @description\r\n * 根据 vnode 类型创建对应的宿主节点,并插入到容器中。\r\n * 如果容器中已有内容,会先卸载再重新渲染。\r\n */\r\n render(vnode: VNode, container: HN): void {\r\n // 先卸载已有内容\r\n if (currentChild !== null) {\r\n this.unmount(container);\r\n }\r\n\r\n const node = createHostNodeFromVNode(adapter, vnode);\r\n if (node !== null) {\r\n adapter.insert(node, container, null);\r\n currentChild = node;\r\n }\r\n\r\n if (config?.debug) {\r\n // eslint-disable-next-line no-console\r\n console.log(`[platform-adapter:${adapter.name}] 渲染完成`, vnode);\r\n }\r\n },\r\n\r\n /**\r\n * 卸载容器中的内容\r\n */\r\n unmount(_container: HN): void {\r\n if (currentChild !== null) {\r\n adapter.remove(currentChild);\r\n currentChild = null;\r\n }\r\n\r\n if (config?.debug) {\r\n // eslint-disable-next-line no-console\r\n console.log(`[platform-adapter:${adapter.name}] 卸载完成`);\r\n }\r\n },\r\n\r\n /**\r\n * 获取关联的平台适配器\r\n */\r\n getAdapter(): PlatformAdapter<HN, HE> {\r\n return adapter;\r\n },\r\n };\r\n\r\n return renderer;\r\n}\r\n\r\n/**\r\n * 根据 VNode 类型创建宿主节点\r\n *\r\n * @description\r\n * 将 VNode 映射为平台适配器可操作的宿主节点。\r\n * 支持元素节点、文本节点和注释节点。\r\n *\r\n * @param adapter - 平台适配器\r\n * @param vnode - 虚拟节点\r\n * @returns 宿主节点,无法识别的类型返回 null\r\n */\r\nfunction createHostNodeFromVNode<HN, HE extends HN>(\r\n adapter: PlatformAdapter<HN, HE>,\r\n vnode: VNode,\r\n): HN | null {\r\n const { type, children } = vnode;\r\n\r\n // 元素节点\r\n if (isString(type)) {\r\n const el = adapter.createElement(type);\r\n\r\n // 设置属性\r\n if (vnode.props) {\r\n for (const [key, value] of Object.entries(vnode.props)) {\r\n if (key === 'style' && isString(value)) {\r\n adapter.setStyle(el, value);\r\n } else if (key === 'class' && isString(value)) {\r\n adapter.addClass(el, value);\r\n } else if (isString(value)) {\r\n adapter.setAttribute(el, key, value);\r\n }\r\n }\r\n }\r\n\r\n // 递归处理子节点\r\n if (children && isString(children)) {\r\n adapter.setElementText(el, children);\r\n }\r\n\r\n return el as unknown as HN;\r\n }\r\n\r\n // 文本节点\r\n if (isString(children)) {\r\n return adapter.createText(children);\r\n }\r\n\r\n // 注释节点\r\n if (isFunction(type) === false && type !== null && !isString(type)) {\r\n // 非 string、非 function、非 null 的 type 可能是 Comment Symbol\r\n return adapter.createComment(String(children ?? ''));\r\n }\r\n\r\n return null;\r\n}\r\n"]}
|
package/package.json
ADDED
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@lytjs/platform-adapter",
|
|
3
|
+
"version": "6.0.0",
|
|
4
|
+
"description": "LytJS 跨平台渲染适配器",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"main": "./dist/index.cjs",
|
|
7
|
+
"module": "./dist/index.mjs",
|
|
8
|
+
"types": "./dist/index.d.ts",
|
|
9
|
+
"exports": {
|
|
10
|
+
".": {
|
|
11
|
+
"types": "./dist/index.d.ts",
|
|
12
|
+
"import": "./dist/index.mjs",
|
|
13
|
+
"require": "./dist/index.cjs"
|
|
14
|
+
},
|
|
15
|
+
"./package.json": "./package.json"
|
|
16
|
+
},
|
|
17
|
+
"files": [
|
|
18
|
+
"dist"
|
|
19
|
+
],
|
|
20
|
+
"sideEffects": false,
|
|
21
|
+
"scripts": {
|
|
22
|
+
"build": "tsup",
|
|
23
|
+
"dev": "tsup --watch",
|
|
24
|
+
"test": "vitest run",
|
|
25
|
+
"test:watch": "vitest",
|
|
26
|
+
"type-check": "tsc --noEmit",
|
|
27
|
+
"lint": "eslint \"src/**/*.ts\" \"tests/**/*.ts\"",
|
|
28
|
+
"clean": "rm -rf dist"
|
|
29
|
+
},
|
|
30
|
+
"dependencies": {
|
|
31
|
+
"@lytjs/common-is": "^6.0.0",
|
|
32
|
+
"@lytjs/common-constants": "^6.0.0",
|
|
33
|
+
"@lytjs/vdom": "^6.0.0",
|
|
34
|
+
"@lytjs/common-vnode": "^6.0.0"
|
|
35
|
+
},
|
|
36
|
+
"devDependencies": {
|
|
37
|
+
"tsup": "^8.0.0",
|
|
38
|
+
"typescript": "^5.4.0",
|
|
39
|
+
"vitest": "^3.0.0"
|
|
40
|
+
},
|
|
41
|
+
"license": "MIT",
|
|
42
|
+
"repository": {
|
|
43
|
+
"type": "git",
|
|
44
|
+
"url": "https://gitee.com/lytjs/lytjs.git",
|
|
45
|
+
"directory": "packages/ecosystem/packages/platform-adapter"
|
|
46
|
+
},
|
|
47
|
+
"keywords": [
|
|
48
|
+
"lytjs",
|
|
49
|
+
"platform-adapter",
|
|
50
|
+
"cross-platform",
|
|
51
|
+
"renderer"
|
|
52
|
+
]
|
|
53
|
+
}
|