@spcsn/taro-runtime 0.1.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.
Files changed (158) hide show
  1. package/LICENSE +174 -0
  2. package/README.md +49 -0
  3. package/dist/bom/URL.d.ts +51 -0
  4. package/dist/bom/URL.js +188 -0
  5. package/dist/bom/URL.js.map +1 -0
  6. package/dist/bom/URLSearchParams.d.ts +1 -0
  7. package/dist/bom/URLSearchParams.js +103 -0
  8. package/dist/bom/URLSearchParams.js.map +1 -0
  9. package/dist/bom/document.d.ts +3 -0
  10. package/dist/bom/document.js +93 -0
  11. package/dist/bom/document.js.map +1 -0
  12. package/dist/bom/getComputedStyle.d.ts +4 -0
  13. package/dist/bom/getComputedStyle.js +9 -0
  14. package/dist/bom/getComputedStyle.js.map +1 -0
  15. package/dist/bom/history.d.ts +30 -0
  16. package/dist/bom/history.js +108 -0
  17. package/dist/bom/history.js.map +1 -0
  18. package/dist/bom/location.d.ts +37 -0
  19. package/dist/bom/location.js +200 -0
  20. package/dist/bom/location.js.map +1 -0
  21. package/dist/bom/navigator.d.ts +1 -0
  22. package/dist/bom/navigator.js +22 -0
  23. package/dist/bom/navigator.js.map +1 -0
  24. package/dist/bom/raf.d.ts +4 -0
  25. package/dist/bom/raf.js +28 -0
  26. package/dist/bom/raf.js.map +1 -0
  27. package/dist/bom/window.d.ts +23 -0
  28. package/dist/bom/window.js +74 -0
  29. package/dist/bom/window.js.map +1 -0
  30. package/dist/constants/index.d.ts +57 -0
  31. package/dist/constants/index.js +63 -0
  32. package/dist/constants/index.js.map +1 -0
  33. package/dist/current.d.ts +19 -0
  34. package/dist/current.js +11 -0
  35. package/dist/current.js.map +1 -0
  36. package/dist/dom/anchor-element.d.ts +13 -0
  37. package/dist/dom/anchor-element.js +42 -0
  38. package/dist/dom/anchor-element.js.map +1 -0
  39. package/dist/dom/class-list.d.ts +16 -0
  40. package/dist/dom/class-list.js +79 -0
  41. package/dist/dom/class-list.js.map +1 -0
  42. package/dist/dom/document.d.ts +21 -0
  43. package/dist/dom/document.js +74 -0
  44. package/dist/dom/document.js.map +1 -0
  45. package/dist/dom/element.d.ts +39 -0
  46. package/dist/dom/element.js +261 -0
  47. package/dist/dom/element.js.map +1 -0
  48. package/dist/dom/event-source.d.ts +7 -0
  49. package/dist/dom/event-source.js +18 -0
  50. package/dist/dom/event-source.js.map +1 -0
  51. package/dist/dom/event-target.d.ts +8 -0
  52. package/dist/dom/event-target.js +72 -0
  53. package/dist/dom/event-target.js.map +1 -0
  54. package/dist/dom/event.d.ts +24 -0
  55. package/dist/dom/event.js +124 -0
  56. package/dist/dom/event.js.map +1 -0
  57. package/dist/dom/form.d.ts +9 -0
  58. package/dist/dom/form.js +30 -0
  59. package/dist/dom/form.js.map +1 -0
  60. package/dist/dom/node.d.ts +76 -0
  61. package/dist/dom/node.js +213 -0
  62. package/dist/dom/node.js.map +1 -0
  63. package/dist/dom/node_types.d.ts +10 -0
  64. package/dist/dom/root.d.ts +16 -0
  65. package/dist/dom/root.js +127 -0
  66. package/dist/dom/root.js.map +1 -0
  67. package/dist/dom/style.d.ts +14 -0
  68. package/dist/dom/style.js +138 -0
  69. package/dist/dom/style.js.map +1 -0
  70. package/dist/dom/style_properties.d.ts +3 -0
  71. package/dist/dom/style_properties.js +374 -0
  72. package/dist/dom/style_properties.js.map +1 -0
  73. package/dist/dom/svg.d.ts +3 -0
  74. package/dist/dom/svg.js +7 -0
  75. package/dist/dom/svg.js.map +1 -0
  76. package/dist/dom/text.d.ts +14 -0
  77. package/dist/dom/text.js +43 -0
  78. package/dist/dom/text.js.map +1 -0
  79. package/dist/dom/transfer.d.ts +7 -0
  80. package/dist/dom/transfer.js +16 -0
  81. package/dist/dom/transfer.js.map +1 -0
  82. package/dist/dom/tree.d.ts +4 -0
  83. package/dist/dom/tree.js +31 -0
  84. package/dist/dom/tree.js.map +1 -0
  85. package/dist/dom-external/element.d.ts +3 -0
  86. package/dist/dom-external/index.d.ts +1 -0
  87. package/dist/dom-external/mutation-observer/implements.d.ts +52 -0
  88. package/dist/dom-external/mutation-observer/implements.js +101 -0
  89. package/dist/dom-external/mutation-observer/implements.js.map +1 -0
  90. package/dist/dom-external/mutation-observer/index.d.ts +13 -0
  91. package/dist/dom-external/mutation-observer/index.js +32 -0
  92. package/dist/dom-external/mutation-observer/index.js.map +1 -0
  93. package/dist/dom-external/mutation-observer/record.d.ts +24 -0
  94. package/dist/dom-external/node.d.ts +5 -0
  95. package/dist/dsl/common.d.ts +14 -0
  96. package/dist/dsl/common.js +278 -0
  97. package/dist/dsl/common.js.map +1 -0
  98. package/dist/dsl/instance.d.ts +92 -0
  99. package/dist/emitter/emitter.d.ts +4 -0
  100. package/dist/emitter/emitter.js +7 -0
  101. package/dist/emitter/emitter.js.map +1 -0
  102. package/dist/env.d.ts +7 -0
  103. package/dist/env.js +10 -0
  104. package/dist/env.js.map +1 -0
  105. package/dist/hydrate.d.ts +10 -0
  106. package/dist/hydrate.js +62 -0
  107. package/dist/hydrate.js.map +1 -0
  108. package/dist/index.cjs.d.ts +35 -0
  109. package/dist/index.cjs.js +3776 -0
  110. package/dist/index.cjs.js.map +1 -0
  111. package/dist/index.d.ts +35 -0
  112. package/dist/index.js +34 -0
  113. package/dist/interface/animate.d.ts +81 -0
  114. package/dist/interface/element.d.ts +4 -0
  115. package/dist/interface/event-target.d.ts +11 -0
  116. package/dist/interface/event.d.ts +15 -0
  117. package/dist/interface/hydrate.d.ts +30 -0
  118. package/dist/interface/index.d.ts +8 -0
  119. package/dist/interface/node.d.ts +7 -0
  120. package/dist/interface/options.d.ts +5 -0
  121. package/dist/interface/utils.d.ts +2 -0
  122. package/dist/next-tick.d.ts +2 -0
  123. package/dist/next-tick.js +35 -0
  124. package/dist/next-tick.js.map +1 -0
  125. package/dist/options.d.ts +2 -0
  126. package/dist/options.js +9 -0
  127. package/dist/options.js.map +1 -0
  128. package/dist/perf.d.ts +9 -0
  129. package/dist/perf.js +36 -0
  130. package/dist/perf.js.map +1 -0
  131. package/dist/polyfill/array.d.ts +2 -0
  132. package/dist/polyfill/array.js +36 -0
  133. package/dist/polyfill/array.js.map +1 -0
  134. package/dist/polyfill/index.d.ts +2 -0
  135. package/dist/polyfill/index.js +20 -0
  136. package/dist/polyfill/index.js.map +1 -0
  137. package/dist/polyfill/intersection-observer.d.ts +1 -0
  138. package/dist/polyfill/intersection-observer.js +494 -0
  139. package/dist/polyfill/intersection-observer.js.map +1 -0
  140. package/dist/polyfill/object.d.ts +3 -0
  141. package/dist/polyfill/object.js +63 -0
  142. package/dist/polyfill/object.js.map +1 -0
  143. package/dist/runtime.esm.d.ts +35 -0
  144. package/dist/runtime.esm.js +3644 -0
  145. package/dist/runtime.esm.js.map +1 -0
  146. package/dist/utils/cache.d.ts +12 -0
  147. package/dist/utils/cache.js +26 -0
  148. package/dist/utils/cache.js.map +1 -0
  149. package/dist/utils/index.d.ts +25 -0
  150. package/dist/utils/index.js +82 -0
  151. package/dist/utils/index.js.map +1 -0
  152. package/dist/utils/lodash.d.ts +2 -0
  153. package/dist/utils/lodash.js +33 -0
  154. package/dist/utils/lodash.js.map +1 -0
  155. package/dist/utils/router.d.ts +7 -0
  156. package/dist/utils/router.js +19 -0
  157. package/dist/utils/router.js.map +1 -0
  158. package/package.json +45 -0
@@ -0,0 +1,76 @@
1
+ import { TaroEventTarget } from './event-target';
2
+ import { NodeType } from './node_types';
3
+ import type { TFunc, UpdatePayload } from '../interface';
4
+ import type { TaroDocument } from './document';
5
+ import type { TaroElement } from './element';
6
+ import type { TaroRootElement } from './root';
7
+ interface RemoveChildOptions {
8
+ cleanRef?: boolean;
9
+ doUpdate?: boolean;
10
+ }
11
+ export declare class TaroNode extends TaroEventTarget {
12
+ uid: string;
13
+ sid: string;
14
+ nodeType: NodeType;
15
+ nodeName: string;
16
+ parentNode: TaroNode | null;
17
+ childNodes: TaroNode[];
18
+ constructor();
19
+ private hydrate;
20
+ private updateChildNodes;
21
+ private updateSingleChild;
22
+ get _root(): TaroRootElement | null;
23
+ protected findIndex(refChild: TaroNode): number;
24
+ get _path(): string;
25
+ get nextSibling(): TaroNode | null;
26
+ get previousSibling(): TaroNode | null;
27
+ get parentElement(): TaroElement | null;
28
+ get firstChild(): TaroNode | null;
29
+ get lastChild(): TaroNode | null;
30
+ /**
31
+ * @textContent 目前只能置空子元素
32
+ * @TODO 等待完整 innerHTML 实现
33
+ */
34
+ set textContent(text: string);
35
+ /**
36
+ * @doc https://developer.mozilla.org/zh-CN/docs/Web/API/Node/insertBefore
37
+ * @scenario
38
+ * [A,B,C]
39
+ * 1. insert D before C, D has no parent
40
+ * 2. insert D before C, D has the same parent of C
41
+ * 3. insert D before C, D has the different parent of C
42
+ */
43
+ insertBefore<T extends TaroNode>(newChild: T, refChild?: TaroNode | null, isReplace?: boolean): T;
44
+ /**
45
+ * @doc https://developer.mozilla.org/zh-CN/docs/Web/API/Node/appendChild
46
+ * @scenario
47
+ * [A,B,C]
48
+ * 1. append C, C has no parent
49
+ * 2. append C, C has the same parent of B
50
+ * 3. append C, C has the different parent of B
51
+ */
52
+ appendChild(newChild: TaroNode): TaroNode;
53
+ /**
54
+ * @doc https://developer.mozilla.org/zh-CN/docs/Web/API/Node/replaceChild
55
+ * @scenario
56
+ * [A,B,C]
57
+ * 1. replace B with C, C has no parent
58
+ * 2. replace B with C, C has no parent, C has the same parent of B
59
+ * 3. replace B with C, C has no parent, C has the different parent of B
60
+ */
61
+ replaceChild(newChild: TaroNode, oldChild: TaroNode): TaroNode | undefined;
62
+ /**
63
+ * @doc https://developer.mozilla.org/zh-CN/docs/Web/API/Node/removeChild
64
+ * @scenario
65
+ * [A,B,C]
66
+ * 1. remove A or B
67
+ * 2. remove C
68
+ */
69
+ removeChild<T extends TaroNode>(child: T, options?: RemoveChildOptions): T;
70
+ remove(options?: RemoveChildOptions): void;
71
+ hasChildNodes(): boolean;
72
+ enqueueUpdate(payload: UpdatePayload): void;
73
+ get ownerDocument(): TaroDocument;
74
+ static extend(methodName: string, options: TFunc | Record<string, any>): void;
75
+ }
76
+ export {};
@@ -0,0 +1,213 @@
1
+ import "../constants/index.js";
2
+ import { MutationObserver } from "../dom-external/mutation-observer/index.js";
3
+ import env from "../env.js";
4
+ import { extend, incrementId, isComment } from "../utils/index.js";
5
+ import { eventSource } from "./event-source.js";
6
+ import { hydrate } from "../hydrate.js";
7
+ import { TaroEventTarget } from "./event-target.js";
8
+ import { Shortcuts, ensure, hooks } from "@spcsn/taro-shared";
9
+ //#region src/dom/node.ts
10
+ const CHILDNODES = Shortcuts.Childnodes;
11
+ const nodeId = incrementId();
12
+ var TaroNode = class TaroNode extends TaroEventTarget {
13
+ constructor() {
14
+ super();
15
+ this.parentNode = null;
16
+ this.childNodes = [];
17
+ this.hydrate = (node) => () => hydrate(node);
18
+ this.uid = "_" + nodeId();
19
+ this.sid = this.uid;
20
+ eventSource.set(this.sid, this);
21
+ }
22
+ updateChildNodes(isClean) {
23
+ const cleanChildNodes = () => [];
24
+ const rerenderChildNodes = () => {
25
+ return this.childNodes.filter((node) => !isComment(node)).map(hydrate);
26
+ };
27
+ this.enqueueUpdate({
28
+ path: `${this._path}.${CHILDNODES}`,
29
+ value: isClean ? cleanChildNodes : rerenderChildNodes
30
+ });
31
+ }
32
+ updateSingleChild(index) {
33
+ this.childNodes.forEach((child, childIndex) => {
34
+ if (isComment(child)) return;
35
+ if (index && childIndex < index) return;
36
+ this.enqueueUpdate({
37
+ path: child._path,
38
+ value: this.hydrate(child)
39
+ });
40
+ });
41
+ }
42
+ get _root() {
43
+ return this.parentNode?._root || null;
44
+ }
45
+ findIndex(refChild) {
46
+ const index = this.childNodes.indexOf(refChild);
47
+ ensure(index !== -1, "The node to be replaced is not a child of this node.");
48
+ return index;
49
+ }
50
+ get _path() {
51
+ const parentNode = this.parentNode;
52
+ if (parentNode) {
53
+ const indexOfNode = parentNode.childNodes.filter((node) => !isComment(node)).indexOf(this);
54
+ const index = hooks.call("getPathIndex", indexOfNode);
55
+ return `${parentNode._path}.${CHILDNODES}.${index}`;
56
+ }
57
+ return "";
58
+ }
59
+ get nextSibling() {
60
+ const parentNode = this.parentNode;
61
+ return parentNode?.childNodes[parentNode.findIndex(this) + 1] || null;
62
+ }
63
+ get previousSibling() {
64
+ const parentNode = this.parentNode;
65
+ return parentNode?.childNodes[parentNode.findIndex(this) - 1] || null;
66
+ }
67
+ get parentElement() {
68
+ const parentNode = this.parentNode;
69
+ if (parentNode?.nodeType === 1) return parentNode;
70
+ return null;
71
+ }
72
+ get firstChild() {
73
+ return this.childNodes[0] || null;
74
+ }
75
+ get lastChild() {
76
+ const childNodes = this.childNodes;
77
+ return childNodes[childNodes.length - 1] || null;
78
+ }
79
+ /**
80
+ * @textContent 目前只能置空子元素
81
+ * @TODO 等待完整 innerHTML 实现
82
+ */
83
+ set textContent(text) {
84
+ const removedNodes = this.childNodes.slice();
85
+ const addedNodes = [];
86
+ while (this.firstChild) this.removeChild(this.firstChild, { doUpdate: false });
87
+ if (text === "") this.updateChildNodes(true);
88
+ else {
89
+ const newText = env.document.createTextNode(text);
90
+ addedNodes.push(newText);
91
+ this.appendChild(newText);
92
+ this.updateChildNodes();
93
+ }
94
+ MutationObserver.record({
95
+ type: "childList",
96
+ target: this,
97
+ removedNodes,
98
+ addedNodes
99
+ });
100
+ }
101
+ /**
102
+ * @doc https://developer.mozilla.org/zh-CN/docs/Web/API/Node/insertBefore
103
+ * @scenario
104
+ * [A,B,C]
105
+ * 1. insert D before C, D has no parent
106
+ * 2. insert D before C, D has the same parent of C
107
+ * 3. insert D before C, D has the different parent of C
108
+ */
109
+ insertBefore(newChild, refChild, isReplace) {
110
+ if (newChild.nodeName === "document-fragment") {
111
+ newChild.childNodes.reduceRight((previousValue, currentValue) => {
112
+ this.insertBefore(currentValue, previousValue);
113
+ return currentValue;
114
+ }, refChild);
115
+ return newChild;
116
+ }
117
+ newChild.remove({ cleanRef: false });
118
+ let index = 0;
119
+ newChild.parentNode = this;
120
+ if (refChild) {
121
+ index = this.findIndex(refChild);
122
+ this.childNodes.splice(index, 0, newChild);
123
+ } else this.childNodes.push(newChild);
124
+ const childNodesLength = this.childNodes.length;
125
+ if (this._root) if (!refChild) if (childNodesLength === 1) this.updateChildNodes();
126
+ else this.enqueueUpdate({
127
+ path: newChild._path,
128
+ value: this.hydrate(newChild)
129
+ });
130
+ else if (isReplace) this.enqueueUpdate({
131
+ path: newChild._path,
132
+ value: this.hydrate(newChild)
133
+ });
134
+ else if (childNodesLength * 2 / 3 > index) this.updateChildNodes();
135
+ else this.updateSingleChild(index);
136
+ MutationObserver.record({
137
+ type: "childList",
138
+ target: this,
139
+ addedNodes: [newChild],
140
+ removedNodes: isReplace ? [refChild] : [],
141
+ nextSibling: isReplace ? refChild.nextSibling : refChild || null,
142
+ previousSibling: newChild.previousSibling
143
+ });
144
+ return newChild;
145
+ }
146
+ /**
147
+ * @doc https://developer.mozilla.org/zh-CN/docs/Web/API/Node/appendChild
148
+ * @scenario
149
+ * [A,B,C]
150
+ * 1. append C, C has no parent
151
+ * 2. append C, C has the same parent of B
152
+ * 3. append C, C has the different parent of B
153
+ */
154
+ appendChild(newChild) {
155
+ return this.insertBefore(newChild);
156
+ }
157
+ /**
158
+ * @doc https://developer.mozilla.org/zh-CN/docs/Web/API/Node/replaceChild
159
+ * @scenario
160
+ * [A,B,C]
161
+ * 1. replace B with C, C has no parent
162
+ * 2. replace B with C, C has no parent, C has the same parent of B
163
+ * 3. replace B with C, C has no parent, C has the different parent of B
164
+ */
165
+ replaceChild(newChild, oldChild) {
166
+ if (oldChild.parentNode !== this) return;
167
+ this.insertBefore(newChild, oldChild, true);
168
+ oldChild.remove({ doUpdate: false });
169
+ return oldChild;
170
+ }
171
+ /**
172
+ * @doc https://developer.mozilla.org/zh-CN/docs/Web/API/Node/removeChild
173
+ * @scenario
174
+ * [A,B,C]
175
+ * 1. remove A or B
176
+ * 2. remove C
177
+ */
178
+ removeChild(child, options = {}) {
179
+ const { cleanRef, doUpdate } = options;
180
+ if (cleanRef !== false && doUpdate !== false) MutationObserver.record({
181
+ type: "childList",
182
+ target: this,
183
+ removedNodes: [child],
184
+ nextSibling: child.nextSibling,
185
+ previousSibling: child.previousSibling
186
+ });
187
+ const index = this.findIndex(child);
188
+ this.childNodes.splice(index, 1);
189
+ child.parentNode = null;
190
+ if (cleanRef !== false) eventSource.removeNodeTree(child);
191
+ if (this._root && doUpdate !== false) this.updateChildNodes();
192
+ return child;
193
+ }
194
+ remove(options) {
195
+ this.parentNode?.removeChild(this, options);
196
+ }
197
+ hasChildNodes() {
198
+ return this.childNodes.length > 0;
199
+ }
200
+ enqueueUpdate(payload) {
201
+ this._root?.enqueueUpdate(payload);
202
+ }
203
+ get ownerDocument() {
204
+ return env.document;
205
+ }
206
+ static extend(methodName, options) {
207
+ extend(TaroNode, methodName, options);
208
+ }
209
+ };
210
+ //#endregion
211
+ export { TaroNode };
212
+
213
+ //# sourceMappingURL=node.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"node.js","names":[],"sources":["../../src/dom/node.ts"],"sourcesContent":["import { ensure, hooks, Shortcuts } from '@spcsn/taro-shared';\n\nimport { DOCUMENT_FRAGMENT } from '../constants';\nimport { MutationObserver, MutationRecordType } from '../dom-external/mutation-observer';\nimport env from '../env';\nimport { hydrate } from '../hydrate';\nimport { extend, incrementId, isComment } from '../utils';\nimport { eventSource } from './event-source';\nimport { TaroEventTarget } from './event-target';\nimport { NodeType } from './node_types';\n\nimport type { TFunc, UpdatePayload } from '../interface';\nimport type { TaroDocument } from './document';\nimport type { TaroElement } from './element';\nimport type { TaroRootElement } from './root';\n\ninterface RemoveChildOptions {\n cleanRef?: boolean;\n doUpdate?: boolean;\n}\n\nconst CHILDNODES = Shortcuts.Childnodes;\nconst nodeId = incrementId();\n\nexport class TaroNode extends TaroEventTarget {\n public uid: string;\n public sid: string;\n public nodeType: NodeType;\n public nodeName: string;\n public parentNode: TaroNode | null = null;\n public childNodes: TaroNode[] = [];\n\n public constructor() {\n super();\n this.uid = '_' + nodeId(); // dom 节点 id,开发者可修改\n this.sid = this.uid; // dom 节点全局唯一 id,不可被修改\n eventSource.set(this.sid, this);\n }\n\n private hydrate = (node: TaroNode) => () => hydrate(node as TaroElement);\n\n private updateChildNodes(isClean?: boolean) {\n const cleanChildNodes = () => [];\n const rerenderChildNodes = () => {\n const childNodes = this.childNodes.filter((node) => !isComment(node));\n return childNodes.map(hydrate);\n };\n\n this.enqueueUpdate({\n path: `${this._path}.${CHILDNODES}`,\n value: isClean ? cleanChildNodes : rerenderChildNodes,\n });\n }\n\n private updateSingleChild(index: number) {\n this.childNodes.forEach((child, childIndex) => {\n if (isComment(child)) return;\n\n if (index && childIndex < index) return;\n\n this.enqueueUpdate({\n path: child._path,\n value: this.hydrate(child),\n });\n });\n }\n\n public get _root(): TaroRootElement | null {\n return this.parentNode?._root || null;\n }\n\n protected findIndex(refChild: TaroNode): number {\n const index = this.childNodes.indexOf(refChild);\n\n ensure(index !== -1, 'The node to be replaced is not a child of this node.');\n\n return index;\n }\n\n public get _path(): string {\n const parentNode = this.parentNode;\n\n if (parentNode) {\n // 计算路径时,先过滤掉 comment 节点\n const list = parentNode.childNodes.filter((node) => !isComment(node));\n const indexOfNode = list.indexOf(this);\n const index = hooks.call('getPathIndex', indexOfNode);\n\n return `${parentNode._path}.${CHILDNODES}.${index}`;\n }\n\n return '';\n }\n\n public get nextSibling(): TaroNode | null {\n const parentNode = this.parentNode;\n return parentNode?.childNodes[parentNode.findIndex(this) + 1] || null;\n }\n\n public get previousSibling(): TaroNode | null {\n const parentNode = this.parentNode;\n return parentNode?.childNodes[parentNode.findIndex(this) - 1] || null;\n }\n\n public get parentElement(): TaroElement | null {\n const parentNode = this.parentNode;\n if (parentNode?.nodeType === NodeType.ELEMENT_NODE) {\n return parentNode as TaroElement;\n }\n return null;\n }\n\n public get firstChild(): TaroNode | null {\n return this.childNodes[0] || null;\n }\n\n public get lastChild(): TaroNode | null {\n const childNodes = this.childNodes;\n return childNodes[childNodes.length - 1] || null;\n }\n\n /**\n * @textContent 目前只能置空子元素\n * @TODO 等待完整 innerHTML 实现\n */\n // eslint-disable-next-line accessor-pairs\n public set textContent(text: string) {\n const removedNodes = this.childNodes.slice();\n const addedNodes: TaroNode[] = [];\n\n // Handle old children' data structure & ref\n while (this.firstChild) {\n this.removeChild(this.firstChild, { doUpdate: false });\n }\n\n if (text === '') {\n this.updateChildNodes(true);\n } else {\n const newText = env.document.createTextNode(text);\n addedNodes.push(newText);\n this.appendChild(newText);\n this.updateChildNodes();\n }\n\n // @Todo: appendChild 会多触发一次\n MutationObserver.record({\n type: MutationRecordType.CHILD_LIST,\n target: this,\n removedNodes,\n addedNodes,\n });\n }\n\n /**\n * @doc https://developer.mozilla.org/zh-CN/docs/Web/API/Node/insertBefore\n * @scenario\n * [A,B,C]\n * 1. insert D before C, D has no parent\n * 2. insert D before C, D has the same parent of C\n * 3. insert D before C, D has the different parent of C\n */\n public insertBefore<T extends TaroNode>(newChild: T, refChild?: TaroNode | null, isReplace?: boolean): T {\n if (newChild.nodeName === DOCUMENT_FRAGMENT) {\n newChild.childNodes.reduceRight((previousValue, currentValue) => {\n this.insertBefore(currentValue, previousValue);\n return currentValue;\n }, refChild);\n return newChild;\n }\n\n // Parent release newChild\n // - cleanRef: false (No need to clean eventSource, because newChild is about to be inserted)\n // - update: true (Need to update parent.childNodes, because parent.childNodes is reordered)\n newChild.remove({ cleanRef: false });\n\n let index = 0;\n // Data structure\n newChild.parentNode = this;\n if (refChild) {\n // insertBefore & replaceChild\n index = this.findIndex(refChild);\n this.childNodes.splice(index, 0, newChild);\n } else {\n // appendChild\n this.childNodes.push(newChild);\n }\n\n const childNodesLength = this.childNodes.length;\n // Serialization\n if (this._root) {\n if (!refChild) {\n // appendChild\n const isOnlyChild = childNodesLength === 1;\n if (isOnlyChild) {\n this.updateChildNodes();\n } else {\n this.enqueueUpdate({\n path: newChild._path,\n value: this.hydrate(newChild),\n });\n }\n } else if (isReplace) {\n // replaceChild\n this.enqueueUpdate({\n path: newChild._path,\n value: this.hydrate(newChild),\n });\n } else {\n // insertBefore 有两种更新模式\n // 比方说有 A B C 三个节点,现在要在 C 前插入 D\n // 1. 插入 D,然后更新整个父节点的 childNodes 数组\n // setData({ cn: [A, B, D, C] })\n // 2. 插入 D,然后更新 D 以及 D 之后每个节点的数据\n // setData ({\n // cn.[2]: D,\n // cn.[3]: C,\n // })\n // 由于微信解析 ’cn.[2]‘ 这些路径的时候也需要消耗时间,\n // 所以根据 insertBefore 插入的位置来做不同的处理\n const mark = (childNodesLength * 2) / 3;\n if (mark > index) {\n // 如果 insertBefore 的位置在 childNodes 的 2/3 前,则为了避免解析路径消耗过多的时间,采用第一种方式\n this.updateChildNodes();\n } else {\n // 如果 insertBefore 的位置在 childNodes 的 2/3 之后,则采用第二种方式,避免 childNodes 的全量更新\n this.updateSingleChild(index);\n }\n }\n }\n\n MutationObserver.record({\n type: MutationRecordType.CHILD_LIST,\n target: this,\n addedNodes: [newChild],\n removedNodes: isReplace ? [refChild as TaroNode] /** replaceChild */ : [],\n nextSibling: isReplace\n ? (refChild as TaroNode).nextSibling /** replaceChild */\n : refChild || null /** insertBefore & appendChild */,\n previousSibling: newChild.previousSibling,\n });\n\n return newChild;\n }\n\n /**\n * @doc https://developer.mozilla.org/zh-CN/docs/Web/API/Node/appendChild\n * @scenario\n * [A,B,C]\n * 1. append C, C has no parent\n * 2. append C, C has the same parent of B\n * 3. append C, C has the different parent of B\n */\n public appendChild(newChild: TaroNode) {\n return this.insertBefore(newChild);\n }\n\n /**\n * @doc https://developer.mozilla.org/zh-CN/docs/Web/API/Node/replaceChild\n * @scenario\n * [A,B,C]\n * 1. replace B with C, C has no parent\n * 2. replace B with C, C has no parent, C has the same parent of B\n * 3. replace B with C, C has no parent, C has the different parent of B\n */\n public replaceChild(newChild: TaroNode, oldChild: TaroNode) {\n if (oldChild.parentNode !== this) return;\n\n // Insert the newChild\n this.insertBefore(newChild, oldChild, true);\n\n // Destroy the oldChild\n // - cleanRef: true (Need to clean eventSource, because the oldChild was detached from the DOM tree)\n // - update: false (No need to update parent.childNodes, because replace will not cause the parent.childNodes being reordered)\n oldChild.remove({ doUpdate: false });\n\n return oldChild;\n }\n\n /**\n * @doc https://developer.mozilla.org/zh-CN/docs/Web/API/Node/removeChild\n * @scenario\n * [A,B,C]\n * 1. remove A or B\n * 2. remove C\n */\n public removeChild<T extends TaroNode>(child: T, options: RemoveChildOptions = {}): T {\n const { cleanRef, doUpdate } = options;\n\n if (cleanRef !== false && doUpdate !== false) {\n // appendChild/replaceChild/insertBefore 不应该触发\n // @Todo: 但其实如果 newChild 的父节点是另一颗子树的节点,应该是要触发的\n MutationObserver.record({\n type: MutationRecordType.CHILD_LIST,\n target: this,\n removedNodes: [child],\n nextSibling: child.nextSibling,\n previousSibling: child.previousSibling,\n });\n }\n\n // Data Structure\n const index = this.findIndex(child);\n this.childNodes.splice(index, 1);\n child.parentNode = null;\n\n // Set eventSource\n if (cleanRef !== false) {\n eventSource.removeNodeTree(child);\n }\n\n // Serialization\n if (this._root && doUpdate !== false) {\n this.updateChildNodes();\n }\n\n return child;\n }\n\n public remove(options?: RemoveChildOptions) {\n this.parentNode?.removeChild(this, options);\n }\n\n public hasChildNodes() {\n return this.childNodes.length > 0;\n }\n\n public enqueueUpdate(payload: UpdatePayload) {\n this._root?.enqueueUpdate(payload);\n }\n\n public get ownerDocument(): TaroDocument {\n return env.document;\n }\n\n static extend(methodName: string, options: TFunc | Record<string, any>) {\n extend(TaroNode, methodName, options);\n }\n}\n"],"mappings":"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"}
@@ -0,0 +1,10 @@
1
+ export declare const enum NodeType {
2
+ ELEMENT_NODE = 1,
3
+ ATTRIBUTE_NODE = 2,
4
+ TEXT_NODE = 3,
5
+ CDATA_SECTION_NODE = 4,
6
+ ENTITY_REFERENCE_NODE = 5,
7
+ COMMENT_NODE = 6,
8
+ PROCESSING_INSTRUCTION_NODE = 7,
9
+ DOCUMENT_NODE = 9
10
+ }
@@ -0,0 +1,16 @@
1
+ import { TaroElement } from './element';
2
+ import type { MpInstance, TFunc, UpdatePayload } from '../interface';
3
+ export declare class TaroRootElement extends TaroElement {
4
+ private updatePayloads;
5
+ private updateCallbacks;
6
+ pendingUpdate: boolean;
7
+ ctx: null | MpInstance;
8
+ constructor();
9
+ get _path(): string;
10
+ get _root(): TaroRootElement;
11
+ scheduleTask(fn: TFunc): void;
12
+ enqueueUpdate(payload: UpdatePayload): void;
13
+ performUpdate(initRender?: boolean, prerender?: TFunc): void;
14
+ enqueueUpdateCallback(cb: TFunc, ctx?: Record<string, any>): void;
15
+ flushUpdateCallback(): void;
16
+ }
@@ -0,0 +1,127 @@
1
+ import { ROOT_STR, SET_DATA } from "../constants/index.js";
2
+ import { customWrapperCache, isComment } from "../utils/index.js";
3
+ import { TaroElement } from "./element.js";
4
+ import { options } from "../options.js";
5
+ import { perf } from "../perf.js";
6
+ import { Shortcuts, hooks, isArray, isFunction, isUndefined } from "@spcsn/taro-shared";
7
+ //#region src/dom/root.ts
8
+ function findCustomWrapper(root, dataPathArr) {
9
+ const list = dataPathArr.slice(1);
10
+ let currentData = root;
11
+ let customWrapper;
12
+ let splitedPath = "";
13
+ list.some((item, i) => {
14
+ const key = item.replace(/^\[(.+)\]$/, "$1").replace(/\bcn\b/g, "childNodes");
15
+ currentData = currentData[key];
16
+ if (isArray(currentData)) currentData = currentData.filter((el) => !isComment(el));
17
+ if (isUndefined(currentData)) return true;
18
+ if (currentData.nodeName === "custom-wrapper") {
19
+ const res = customWrapperCache.get(currentData.sid);
20
+ if (res) {
21
+ customWrapper = res;
22
+ splitedPath = dataPathArr.slice(i + 2).join(".");
23
+ }
24
+ }
25
+ });
26
+ if (customWrapper) return {
27
+ customWrapper,
28
+ splitedPath
29
+ };
30
+ }
31
+ var TaroRootElement = class extends TaroElement {
32
+ constructor() {
33
+ super();
34
+ this.updatePayloads = [];
35
+ this.updateCallbacks = [];
36
+ this.pendingUpdate = false;
37
+ this.ctx = null;
38
+ this.nodeName = ROOT_STR;
39
+ this.tagName = ROOT_STR.toUpperCase();
40
+ }
41
+ get _path() {
42
+ return ROOT_STR;
43
+ }
44
+ get _root() {
45
+ return this;
46
+ }
47
+ scheduleTask(fn) {
48
+ setTimeout(fn);
49
+ }
50
+ enqueueUpdate(payload) {
51
+ this.updatePayloads.push(payload);
52
+ if (!this.pendingUpdate && this.ctx) this.performUpdate();
53
+ }
54
+ performUpdate(initRender = false, prerender) {
55
+ this.pendingUpdate = true;
56
+ const ctx = hooks.call("proxyToRaw", this.ctx);
57
+ this.scheduleTask(() => {
58
+ const setDataMark = `${SET_DATA} 开始时间戳 ${Date.now()}`;
59
+ perf.start(setDataMark);
60
+ const data = Object.create(null);
61
+ const resetPaths = new Set(initRender ? ["root.cn.[0]", "root.cn[0]"] : []);
62
+ while (this.updatePayloads.length > 0) {
63
+ const { path, value } = this.updatePayloads.shift();
64
+ if (path.endsWith(Shortcuts.Childnodes)) resetPaths.add(path);
65
+ data[path] = value;
66
+ }
67
+ for (const path in data) {
68
+ resetPaths.forEach((p) => {
69
+ if (path.includes(p) && path !== p) delete data[path];
70
+ });
71
+ const value = data[path];
72
+ if (isFunction(value)) data[path] = value();
73
+ }
74
+ if (isFunction(prerender)) return prerender(data);
75
+ this.pendingUpdate = false;
76
+ let normalUpdate = {};
77
+ const customWrapperMap = /* @__PURE__ */ new Map();
78
+ if (initRender) normalUpdate = data;
79
+ else for (const p in data) {
80
+ const dataPathArr = p.split(".");
81
+ const found = findCustomWrapper(this, dataPathArr);
82
+ if (found) {
83
+ const { customWrapper, splitedPath } = found;
84
+ customWrapperMap.set(customWrapper, {
85
+ ...customWrapperMap.get(customWrapper) || {},
86
+ [`i.${splitedPath}`]: data[p]
87
+ });
88
+ } else normalUpdate[p] = data[p];
89
+ }
90
+ const customWrapperCount = customWrapperMap.size;
91
+ const isNeedNormalUpdate = Object.keys(normalUpdate).length > 0;
92
+ const updateArrLen = customWrapperCount + (isNeedNormalUpdate ? 1 : 0);
93
+ let executeTime = 0;
94
+ const cb = () => {
95
+ if (++executeTime === updateArrLen) {
96
+ perf.stop(setDataMark);
97
+ this.flushUpdateCallback();
98
+ initRender && perf.stop("页面初始化");
99
+ }
100
+ };
101
+ if (customWrapperCount) customWrapperMap.forEach((data, ctx) => {
102
+ if (options.debug) console.log("custom wrapper setData: ", data);
103
+ ctx.setData(data, cb);
104
+ });
105
+ if (isNeedNormalUpdate) {
106
+ if (options.debug) console.log("page setData:", normalUpdate);
107
+ ctx.setData(normalUpdate, cb);
108
+ }
109
+ });
110
+ }
111
+ enqueueUpdateCallback(cb, ctx) {
112
+ this.updateCallbacks.push(() => {
113
+ ctx ? cb.call(ctx) : cb();
114
+ });
115
+ }
116
+ flushUpdateCallback() {
117
+ const updateCallbacks = this.updateCallbacks;
118
+ if (!updateCallbacks.length) return;
119
+ const copies = updateCallbacks.slice(0);
120
+ this.updateCallbacks.length = 0;
121
+ for (let i = 0; i < copies.length; i++) copies[i]();
122
+ }
123
+ };
124
+ //#endregion
125
+ export { TaroRootElement };
126
+
127
+ //# sourceMappingURL=root.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"root.js","names":[],"sources":["../../src/dom/root.ts"],"sourcesContent":["import { hooks, isArray, isFunction, isUndefined, Shortcuts } from '@spcsn/taro-shared';\n\nimport { CUSTOM_WRAPPER, PAGE_INIT, ROOT_STR, SET_DATA } from '../constants';\nimport { options } from '../options';\nimport { perf } from '../perf';\nimport { customWrapperCache, isComment } from '../utils';\nimport { TaroElement } from './element';\n\nimport type { HydratedData, MpInstance, TFunc, UpdatePayload, UpdatePayloadValue } from '../interface';\n\nfunction findCustomWrapper(root: TaroRootElement, dataPathArr: string[]) {\n // ['root', 'cn', '[0]'] remove 'root' => ['cn', '[0]']\n const list = dataPathArr.slice(1);\n let currentData: any = root;\n let customWrapper: Record<string, any> | undefined;\n let splitedPath = '';\n\n list.some((item, i) => {\n const key = item\n // '[0]' => '0'\n .replace(/^\\[(.+)\\]$/, '$1')\n // 'cn' => 'childNodes'\n .replace(/\\bcn\\b/g, 'childNodes');\n\n currentData = currentData[key];\n\n if (isArray(currentData)) {\n currentData = currentData.filter((el) => !isComment(el));\n }\n\n if (isUndefined(currentData)) return true;\n\n if (currentData.nodeName === CUSTOM_WRAPPER) {\n const res = customWrapperCache.get(currentData.sid);\n if (res) {\n customWrapper = res;\n splitedPath = dataPathArr.slice(i + 2).join('.');\n }\n }\n });\n\n if (customWrapper) {\n return {\n customWrapper,\n splitedPath,\n };\n }\n}\n\nexport class TaroRootElement extends TaroElement {\n private updatePayloads: UpdatePayload[] = [];\n\n private updateCallbacks: TFunc[] = [];\n\n public pendingUpdate = false;\n\n public ctx: null | MpInstance = null;\n\n public constructor() {\n super();\n this.nodeName = ROOT_STR;\n this.tagName = ROOT_STR.toUpperCase();\n }\n\n public get _path(): string {\n return ROOT_STR;\n }\n\n public get _root(): TaroRootElement {\n return this;\n }\n\n public scheduleTask(fn: TFunc) {\n // 这里若使用微任务可略微提前setData的执行时机,但在部分场景下可能会出现连续setData两次,造成更大的性能问题\n setTimeout(fn);\n }\n\n public enqueueUpdate(payload: UpdatePayload): void {\n this.updatePayloads.push(payload);\n\n if (!this.pendingUpdate && this.ctx) {\n this.performUpdate();\n }\n }\n\n public performUpdate(initRender = false, prerender?: TFunc) {\n this.pendingUpdate = true;\n\n const ctx = hooks.call('proxyToRaw', this.ctx)!;\n\n this.scheduleTask(() => {\n const setDataMark = `${SET_DATA} 开始时间戳 ${Date.now()}`;\n perf.start(setDataMark);\n const data: Record<string, UpdatePayloadValue | ReturnType<HydratedData>> = Object.create(null);\n const resetPaths = new Set<string>(initRender ? ['root.cn.[0]', 'root.cn[0]'] : []);\n\n while (this.updatePayloads.length > 0) {\n const { path, value } = this.updatePayloads.shift()!;\n if (path.endsWith(Shortcuts.Childnodes)) {\n resetPaths.add(path);\n }\n data[path] = value;\n }\n\n for (const path in data) {\n resetPaths.forEach((p) => {\n // 已经重置了数组,就不需要分别再设置了\n if (path.includes(p) && path !== p) {\n delete data[path];\n }\n });\n\n const value = data[path];\n if (isFunction(value)) {\n data[path] = value();\n }\n }\n\n // 预渲染\n if (isFunction(prerender)) return prerender(data);\n\n // 正常渲染\n this.pendingUpdate = false;\n let normalUpdate = {};\n const customWrapperMap: Map<Record<any, any>, Record<string, any>> = new Map();\n\n if (initRender) {\n // 初次渲染,使用页面级别的 setData\n normalUpdate = data;\n } else {\n // 更新渲染,区分 CustomWrapper 与页面级别的 setData\n for (const p in data) {\n const dataPathArr = p.split('.');\n const found = findCustomWrapper(this, dataPathArr);\n if (found) {\n // 此项数据使用 CustomWrapper 去更新\n const { customWrapper, splitedPath } = found;\n // 合并同一个 customWrapper 的相关更新到一次 setData 中\n customWrapperMap.set(customWrapper, {\n ...(customWrapperMap.get(customWrapper) || {}),\n [`i.${splitedPath}`]: data[p],\n });\n } else {\n // 此项数据使用页面去更新\n normalUpdate[p] = data[p];\n }\n }\n }\n\n const customWrapperCount = customWrapperMap.size;\n const isNeedNormalUpdate = Object.keys(normalUpdate).length > 0;\n const updateArrLen = customWrapperCount + (isNeedNormalUpdate ? 1 : 0);\n let executeTime = 0;\n\n const cb = () => {\n if (++executeTime === updateArrLen) {\n perf.stop(setDataMark);\n this.flushUpdateCallback();\n initRender && perf.stop(PAGE_INIT);\n }\n };\n\n // custom-wrapper setData\n if (customWrapperCount) {\n customWrapperMap.forEach((data, ctx) => {\n if (process.env.NODE_ENV !== 'production' && options.debug) {\n // eslint-disable-next-line no-console\n console.log('custom wrapper setData: ', data);\n }\n ctx.setData(data, cb);\n });\n }\n\n // page setData\n if (isNeedNormalUpdate) {\n if (process.env.NODE_ENV !== 'production' && options.debug) {\n // eslint-disable-next-line no-console\n console.log('page setData:', normalUpdate);\n }\n ctx.setData(normalUpdate, cb);\n }\n });\n }\n\n public enqueueUpdateCallback(cb: TFunc, ctx?: Record<string, any>) {\n this.updateCallbacks.push(() => {\n ctx ? cb.call(ctx) : cb();\n });\n }\n\n public flushUpdateCallback() {\n const updateCallbacks = this.updateCallbacks;\n if (!updateCallbacks.length) return;\n\n const copies = updateCallbacks.slice(0);\n this.updateCallbacks.length = 0;\n for (let i = 0; i < copies.length; i++) {\n copies[i]();\n }\n }\n}\n"],"mappings":"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"}
@@ -0,0 +1,14 @@
1
+ import { TaroElement } from './element';
2
+ export declare class Style {
3
+ _pending: boolean;
4
+ _usedStyleProp: Set<string>;
5
+ _value: Partial<CSSStyleDeclaration>;
6
+ _element: TaroElement;
7
+ constructor(element: TaroElement);
8
+ private setCssVariables;
9
+ get cssText(): string;
10
+ set cssText(str: string);
11
+ setProperty(propertyName: string, value?: string | null): void;
12
+ removeProperty(propertyName: string): string;
13
+ getPropertyValue(propertyName: string): any;
14
+ }
@@ -0,0 +1,138 @@
1
+ import "../constants/index.js";
2
+ import { MutationObserver } from "../dom-external/mutation-observer/index.js";
3
+ import { styleProperties } from "./style_properties.js";
4
+ import { Shortcuts, hooks, isArray, isNull, isString, isUndefined, toCamelCase, toDashed, warn } from "@spcsn/taro-shared";
5
+ //#region src/dom/style.ts
6
+ function recordCss(obj) {
7
+ MutationObserver.record({
8
+ type: "attributes",
9
+ target: obj._element,
10
+ attributeName: "style",
11
+ oldValue: obj.cssText
12
+ });
13
+ }
14
+ function enqueueUpdate(obj) {
15
+ const element = obj._element;
16
+ if (element._root) element.enqueueUpdate({
17
+ path: `${element._path}.${Shortcuts.Style}`,
18
+ value: obj.cssText
19
+ });
20
+ }
21
+ function setStyle(newVal, styleKey) {
22
+ warn(isString(newVal) && newVal.length > 2046, `Style 属性 ${styleKey} 的值数据量过大,可能会影响渲染性能,考虑使用 CSS 类或其它方案替代。`);
23
+ if (this[styleKey] === newVal) return;
24
+ !this._pending && recordCss(this);
25
+ if (isNull(newVal) || isUndefined(newVal) || newVal === "") {
26
+ this._usedStyleProp.delete(styleKey);
27
+ delete this._value[styleKey];
28
+ } else {
29
+ this._usedStyleProp.add(styleKey);
30
+ this._value[styleKey] = newVal;
31
+ }
32
+ !this._pending && enqueueUpdate(this);
33
+ }
34
+ function initStyle(ctor, styleProperties) {
35
+ const properties = {};
36
+ for (let i = 0; i < styleProperties.length; i++) {
37
+ const styleKey = styleProperties[i];
38
+ if (ctor[styleKey]) return;
39
+ properties[styleKey] = {
40
+ get() {
41
+ const val = this._value[styleKey];
42
+ return isNull(val) || isUndefined(val) ? "" : val;
43
+ },
44
+ set(newVal) {
45
+ setStyle.call(this, newVal, styleKey);
46
+ }
47
+ };
48
+ }
49
+ Object.defineProperties(ctor.prototype, properties);
50
+ }
51
+ function isCssVariable(propertyName) {
52
+ return /^--/.test(propertyName);
53
+ }
54
+ var Style = class {
55
+ constructor(element) {
56
+ this._element = element;
57
+ this._usedStyleProp = /* @__PURE__ */ new Set();
58
+ this._value = {};
59
+ }
60
+ setCssVariables(styleKey) {
61
+ this.hasOwnProperty(styleKey) || Object.defineProperty(this, styleKey, {
62
+ enumerable: true,
63
+ configurable: true,
64
+ get: () => {
65
+ return this._value[styleKey] || "";
66
+ },
67
+ set: (newVal) => {
68
+ setStyle.call(this, newVal, styleKey);
69
+ }
70
+ });
71
+ }
72
+ get cssText() {
73
+ if (!this._usedStyleProp.size) return "";
74
+ const texts = [];
75
+ this._usedStyleProp.forEach((key) => {
76
+ const val = this[key];
77
+ if (isNull(val) || isUndefined(val)) return;
78
+ let styleName = isCssVariable(key) ? key : toDashed(key);
79
+ if (styleName.indexOf("webkit") === 0 || styleName.indexOf("Webkit") === 0) styleName = `-${styleName}`;
80
+ texts.push(`${styleName}: ${val};`);
81
+ });
82
+ return texts.join(" ");
83
+ }
84
+ set cssText(str) {
85
+ this._pending = true;
86
+ recordCss(this);
87
+ this._usedStyleProp.forEach((prop) => {
88
+ this.removeProperty(prop);
89
+ });
90
+ if (str === "" || isUndefined(str) || isNull(str)) {
91
+ this._pending = false;
92
+ enqueueUpdate(this);
93
+ return;
94
+ }
95
+ const rules = str.split(";");
96
+ for (let i = 0; i < rules.length; i++) {
97
+ const rule = rules[i].trim();
98
+ if (rule === "") continue;
99
+ const [propName, ...valList] = rule.split(":");
100
+ const val = valList.join(":");
101
+ if (isUndefined(val)) continue;
102
+ this.setProperty(propName.trim(), val.trim());
103
+ }
104
+ this._pending = false;
105
+ enqueueUpdate(this);
106
+ }
107
+ setProperty(propertyName, value) {
108
+ if (propertyName[0] === "-") this.setCssVariables(propertyName);
109
+ else propertyName = toCamelCase(propertyName);
110
+ if (isNull(value) || isUndefined(value)) this.removeProperty(propertyName);
111
+ else this[propertyName] = value;
112
+ }
113
+ removeProperty(propertyName) {
114
+ propertyName = toCamelCase(propertyName);
115
+ if (!this._usedStyleProp.has(propertyName)) return "";
116
+ const value = this[propertyName];
117
+ this[propertyName] = void 0;
118
+ return value;
119
+ }
120
+ getPropertyValue(propertyName) {
121
+ propertyName = toCamelCase(propertyName);
122
+ const value = this[propertyName];
123
+ if (!value) return "";
124
+ return value;
125
+ }
126
+ };
127
+ initStyle(Style, styleProperties);
128
+ hooks.tap("injectNewStyleProperties", (newStyleProperties) => {
129
+ if (isArray(newStyleProperties)) initStyle(Style, newStyleProperties);
130
+ else {
131
+ if (typeof newStyleProperties !== "string") return;
132
+ initStyle(Style, [newStyleProperties]);
133
+ }
134
+ });
135
+ //#endregion
136
+ export { Style };
137
+
138
+ //# sourceMappingURL=style.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"style.js","names":[],"sources":["../../src/dom/style.ts"],"sourcesContent":["import {\n hooks,\n isArray,\n isNull,\n isString,\n isUndefined,\n Shortcuts,\n toCamelCase,\n toDashed,\n warn,\n} from '@spcsn/taro-shared';\n\nimport { PROPERTY_THRESHOLD } from '../constants';\nimport { MutationObserver, MutationRecordType } from '../dom-external/mutation-observer';\nimport { TaroElement } from './element';\nimport { styleProperties } from './style_properties';\n\nfunction recordCss(obj: Style) {\n MutationObserver.record({\n type: MutationRecordType.ATTRIBUTES,\n target: obj._element,\n attributeName: 'style',\n oldValue: obj.cssText,\n });\n}\n\nfunction enqueueUpdate(obj: Style) {\n const element = obj._element;\n if (element._root) {\n element.enqueueUpdate({\n path: `${element._path}.${Shortcuts.Style}`,\n value: obj.cssText,\n });\n }\n}\n\nfunction setStyle(this: Style, newVal: string, styleKey: string) {\n process.env.NODE_ENV !== 'production' &&\n warn(\n isString(newVal) && newVal.length > PROPERTY_THRESHOLD,\n `Style 属性 ${styleKey} 的值数据量过大,可能会影响渲染性能,考虑使用 CSS 类或其它方案替代。`,\n );\n\n const old = this[styleKey];\n\n if (old === newVal) return;\n\n !this._pending && recordCss(this);\n\n if (isNull(newVal) || isUndefined(newVal) || newVal === '') {\n this._usedStyleProp.delete(styleKey);\n delete this._value[styleKey];\n } else {\n this._usedStyleProp.add(styleKey);\n this._value[styleKey] = newVal;\n }\n\n !this._pending && enqueueUpdate(this);\n}\n\nfunction initStyle(ctor: typeof Style, styleProperties: string[]) {\n const properties = {};\n\n for (let i = 0; i < styleProperties.length; i++) {\n const styleKey = styleProperties[i];\n\n if (ctor[styleKey]) return;\n\n properties[styleKey] = {\n get(this: Style) {\n const val = this._value[styleKey];\n return isNull(val) || isUndefined(val) ? '' : val;\n },\n set(this: Style, newVal: string) {\n setStyle.call(this, newVal, styleKey);\n },\n };\n }\n\n Object.defineProperties(ctor.prototype, properties);\n}\n\nfunction isCssVariable(propertyName) {\n return /^--/.test(propertyName);\n}\n\nexport class Style {\n public _pending: boolean;\n\n public _usedStyleProp: Set<string>;\n\n public _value: Partial<CSSStyleDeclaration>;\n\n public _element: TaroElement;\n\n public constructor(element: TaroElement) {\n this._element = element;\n this._usedStyleProp = new Set();\n this._value = {};\n }\n\n private setCssVariables(styleKey: string) {\n this.hasOwnProperty(styleKey) ||\n Object.defineProperty(this, styleKey, {\n enumerable: true,\n configurable: true,\n get: () => {\n return this._value[styleKey] || '';\n },\n set: (newVal: string) => {\n setStyle.call(this, newVal, styleKey);\n },\n });\n }\n\n public get cssText() {\n if (!this._usedStyleProp.size) return '';\n\n const texts: string[] = [];\n this._usedStyleProp.forEach((key) => {\n const val = this[key];\n if (isNull(val) || isUndefined(val)) return;\n let styleName = isCssVariable(key) ? key : toDashed(key);\n if (styleName.indexOf('webkit') === 0 || styleName.indexOf('Webkit') === 0) {\n styleName = `-${styleName}`;\n }\n texts.push(`${styleName}: ${val};`);\n });\n return texts.join(' ');\n }\n\n public set cssText(str: string) {\n this._pending = true;\n recordCss(this);\n\n this._usedStyleProp.forEach((prop) => {\n this.removeProperty(prop);\n });\n\n if (str === '' || isUndefined(str) || isNull(str)) {\n this._pending = false;\n enqueueUpdate(this);\n return;\n }\n\n const rules = str.split(';');\n\n for (let i = 0; i < rules.length; i++) {\n const rule = rules[i].trim();\n if (rule === '') {\n continue;\n }\n\n // 可能存在 'background: url(http:x/y/z)' 的情况\n const [propName, ...valList] = rule.split(':');\n const val = valList.join(':');\n\n if (isUndefined(val)) {\n continue;\n }\n this.setProperty(propName.trim(), val.trim());\n }\n\n this._pending = false;\n enqueueUpdate(this);\n }\n\n public setProperty(propertyName: string, value?: string | null) {\n if (propertyName[0] === '-') {\n // 支持 webkit 属性或 css 变量\n this.setCssVariables(propertyName);\n } else {\n propertyName = toCamelCase(propertyName);\n }\n\n if (isNull(value) || isUndefined(value)) {\n this.removeProperty(propertyName);\n } else {\n this[propertyName] = value;\n }\n }\n\n public removeProperty(propertyName: string): string {\n propertyName = toCamelCase(propertyName);\n if (!this._usedStyleProp.has(propertyName)) {\n return '';\n }\n\n const value = this[propertyName];\n this[propertyName] = undefined;\n return value;\n }\n\n public getPropertyValue(propertyName: string) {\n propertyName = toCamelCase(propertyName);\n const value = this[propertyName];\n if (!value) {\n return '';\n }\n\n return value;\n }\n}\n\ninitStyle(Style, styleProperties);\n\nhooks.tap('injectNewStyleProperties', (newStyleProperties: string[]) => {\n if (isArray(newStyleProperties)) {\n initStyle(Style, newStyleProperties);\n } else {\n if (typeof newStyleProperties !== 'string') return;\n\n initStyle(Style, [newStyleProperties]);\n }\n});\n"],"mappings":"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"}