glass-easel 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.
- package/README.md +40 -0
- package/dist/glass_easel.all.d.ts +1 -0
- package/dist/glass_easel.all.js +2 -0
- package/dist/glass_easel.all.js.map +1 -0
- package/dist/glass_easel.domlike.global.d.ts +1 -0
- package/dist/glass_easel.domlike.global.js +2 -0
- package/dist/glass_easel.domlike.global.js.map +1 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.js +1 -0
- package/dist/types/src/backend/backend_protocol.d.ts +119 -0
- package/dist/types/src/backend/backend_protocol.d.ts.map +1 -0
- package/dist/types/src/backend/composed_backend_protocol.d.ts +90 -0
- package/dist/types/src/backend/composed_backend_protocol.d.ts.map +1 -0
- package/dist/types/src/backend/domlike_backend_protocol.d.ts +76 -0
- package/dist/types/src/backend/domlike_backend_protocol.d.ts.map +1 -0
- package/dist/types/src/backend/mode.d.ts +46 -0
- package/dist/types/src/backend/mode.d.ts.map +1 -0
- package/dist/types/src/backend/suggested_backend_protocol.d.ts +30 -0
- package/dist/types/src/backend/suggested_backend_protocol.d.ts.map +1 -0
- package/dist/types/src/behavior.d.ts +428 -0
- package/dist/types/src/behavior.d.ts.map +1 -0
- package/dist/types/src/class_list.d.ts +79 -0
- package/dist/types/src/class_list.d.ts.map +1 -0
- package/dist/types/src/component.d.ts +291 -0
- package/dist/types/src/component.d.ts.map +1 -0
- package/dist/types/src/component_params.d.ts +239 -0
- package/dist/types/src/component_params.d.ts.map +1 -0
- package/dist/types/src/component_space.d.ts +164 -0
- package/dist/types/src/component_space.d.ts.map +1 -0
- package/dist/types/src/data_path.d.ts +5 -0
- package/dist/types/src/data_path.d.ts.map +1 -0
- package/dist/types/src/data_proxy.d.ts +107 -0
- package/dist/types/src/data_proxy.d.ts.map +1 -0
- package/dist/types/src/data_utils.d.ts +3 -0
- package/dist/types/src/data_utils.d.ts.map +1 -0
- package/dist/types/src/element.d.ts +275 -0
- package/dist/types/src/element.d.ts.map +1 -0
- package/dist/types/src/element_iterator.d.ts +43 -0
- package/dist/types/src/element_iterator.d.ts.map +1 -0
- package/dist/types/src/event.d.ts +104 -0
- package/dist/types/src/event.d.ts.map +1 -0
- package/dist/types/src/external_shadow_tree.d.ts +20 -0
- package/dist/types/src/external_shadow_tree.d.ts.map +1 -0
- package/dist/types/src/func_arr.d.ts +39 -0
- package/dist/types/src/func_arr.d.ts.map +1 -0
- package/dist/types/src/global_options.d.ts +111 -0
- package/dist/types/src/global_options.d.ts.map +1 -0
- package/dist/types/src/index.d.ts +43 -0
- package/dist/types/src/index.d.ts.map +1 -0
- package/dist/types/src/mutation_observer.d.ts +79 -0
- package/dist/types/src/mutation_observer.d.ts.map +1 -0
- package/dist/types/src/native_node.d.ts +8 -0
- package/dist/types/src/native_node.d.ts.map +1 -0
- package/dist/types/src/node.d.ts +49 -0
- package/dist/types/src/node.d.ts.map +1 -0
- package/dist/types/src/relation.d.ts +47 -0
- package/dist/types/src/relation.d.ts.map +1 -0
- package/dist/types/src/render.d.ts +3 -0
- package/dist/types/src/render.d.ts.map +1 -0
- package/dist/types/src/selector.d.ts +32 -0
- package/dist/types/src/selector.d.ts.map +1 -0
- package/dist/types/src/shadow_root.d.ts +136 -0
- package/dist/types/src/shadow_root.d.ts.map +1 -0
- package/dist/types/src/template_engine.d.ts +18 -0
- package/dist/types/src/template_engine.d.ts.map +1 -0
- package/dist/types/src/text_node.d.ts +32 -0
- package/dist/types/src/text_node.d.ts.map +1 -0
- package/dist/types/src/tmpl/index.d.ts +18 -0
- package/dist/types/src/tmpl/index.d.ts.map +1 -0
- package/dist/types/src/tmpl/native_rendering.d.ts +45 -0
- package/dist/types/src/tmpl/native_rendering.d.ts.map +1 -0
- package/dist/types/src/tmpl/proc_gen_wrapper.d.ts +80 -0
- package/dist/types/src/tmpl/proc_gen_wrapper.d.ts.map +1 -0
- package/dist/types/src/tmpl/proc_gen_wrapper_dom.d.ts +50 -0
- package/dist/types/src/tmpl/proc_gen_wrapper_dom.d.ts.map +1 -0
- package/dist/types/src/tmpl/range_list_diff.d.ts +19 -0
- package/dist/types/src/tmpl/range_list_diff.d.ts.map +1 -0
- package/dist/types/src/trait_behaviors.d.ts +38 -0
- package/dist/types/src/trait_behaviors.d.ts.map +1 -0
- package/dist/types/src/virtual_node.d.ts +10 -0
- package/dist/types/src/virtual_node.d.ts.map +1 -0
- package/dist/types/tests/backend/domlike.test.d.ts +2 -0
- package/dist/types/tests/backend/domlike.test.d.ts.map +1 -0
- package/dist/types/tests/base/env.d.ts +29 -0
- package/dist/types/tests/base/env.d.ts.map +1 -0
- package/dist/types/tests/base/match.d.ts +9 -0
- package/dist/types/tests/base/match.d.ts.map +1 -0
- package/dist/types/tests/core/backend.test.d.ts +2 -0
- package/dist/types/tests/core/backend.test.d.ts.map +1 -0
- package/dist/types/tests/core/behavior.test.d.ts +2 -0
- package/dist/types/tests/core/behavior.test.d.ts.map +1 -0
- package/dist/types/tests/core/component_space.test.d.ts +2 -0
- package/dist/types/tests/core/component_space.test.d.ts.map +1 -0
- package/dist/types/tests/core/data_update.test.d.ts +2 -0
- package/dist/types/tests/core/data_update.test.d.ts.map +1 -0
- package/dist/types/tests/core/misc.test.d.ts +2 -0
- package/dist/types/tests/core/misc.test.d.ts.map +1 -0
- package/dist/types/tests/core/placeholder.test.d.ts +2 -0
- package/dist/types/tests/core/placeholder.test.d.ts.map +1 -0
- package/dist/types/tests/core/slot.test.d.ts +2 -0
- package/dist/types/tests/core/slot.test.d.ts.map +1 -0
- package/dist/types/tests/core/trait_behaviors.test.d.ts +2 -0
- package/dist/types/tests/core/trait_behaviors.test.d.ts.map +1 -0
- package/dist/types/tests/tmpl/binding_map.test.d.ts +2 -0
- package/dist/types/tests/tmpl/binding_map.test.d.ts.map +1 -0
- package/dist/types/tests/tmpl/event.test.d.ts +2 -0
- package/dist/types/tests/tmpl/event.test.d.ts.map +1 -0
- package/dist/types/tests/tmpl/expression.test.d.ts +2 -0
- package/dist/types/tests/tmpl/expression.test.d.ts.map +1 -0
- package/dist/types/tests/tmpl/lvalue.test.d.ts +2 -0
- package/dist/types/tests/tmpl/lvalue.test.d.ts.map +1 -0
- package/dist/types/tests/tmpl/native_rendering.test.d.ts +2 -0
- package/dist/types/tests/tmpl/native_rendering.test.d.ts.map +1 -0
- package/dist/types/tests/tmpl/structure.test.d.ts +2 -0
- package/dist/types/tests/tmpl/structure.test.d.ts.map +1 -0
- package/dist/types/tests/types/chaining.test.d.ts +2 -0
- package/dist/types/tests/types/chaining.test.d.ts.map +1 -0
- package/dist/types/tests/types/createElement.test.d.ts +2 -0
- package/dist/types/tests/types/createElement.test.d.ts.map +1 -0
- package/dist/types/tests/types/definition.test.d.ts +2 -0
- package/dist/types/tests/types/definition.test.d.ts.map +1 -0
- package/guide/zh_CN/advanced/binding_map_update.md +32 -0
- package/guide/zh_CN/advanced/build_args.md +28 -0
- package/guide/zh_CN/advanced/component_filter.md +70 -0
- package/guide/zh_CN/advanced/component_space.md +124 -0
- package/guide/zh_CN/advanced/custom_backend.md +53 -0
- package/guide/zh_CN/advanced/error_listener.md +32 -0
- package/guide/zh_CN/advanced/external_component.md +73 -0
- package/guide/zh_CN/advanced/template_engine.md +61 -0
- package/guide/zh_CN/appendix/backend_protocol.md +501 -0
- package/guide/zh_CN/appendix/list_diff_algorithm.md +406 -0
- package/guide/zh_CN/basic/beginning.md +94 -0
- package/guide/zh_CN/basic/component.md +156 -0
- package/guide/zh_CN/basic/event.md +169 -0
- package/guide/zh_CN/basic/lifetime.md +66 -0
- package/guide/zh_CN/basic/method.md +62 -0
- package/guide/zh_CN/basic/template.md +135 -0
- package/guide/zh_CN/data_management/advanced_update.md +170 -0
- package/guide/zh_CN/data_management/data_deep_copy.md +157 -0
- package/guide/zh_CN/data_management/data_observer.md +154 -0
- package/guide/zh_CN/data_management/property_early_init.md +31 -0
- package/guide/zh_CN/data_management/pure_data_pattern.md +21 -0
- package/guide/zh_CN/index.md +93 -0
- package/guide/zh_CN/interaction/behavior.md +52 -0
- package/guide/zh_CN/interaction/component_path.md +37 -0
- package/guide/zh_CN/interaction/generic.md +73 -0
- package/guide/zh_CN/interaction/placeholder.md +40 -0
- package/guide/zh_CN/interaction/relation.md +151 -0
- package/guide/zh_CN/interaction/slot.md +137 -0
- package/guide/zh_CN/interaction/template_import.md +94 -0
- package/guide/zh_CN/interaction/trait_behavior.md +117 -0
- package/guide/zh_CN/styling/external_class.md +46 -0
- package/guide/zh_CN/styling/style_isolation.md +54 -0
- package/guide/zh_CN/styling/virtual_host.md +52 -0
- package/guide/zh_CN/tree/element_iterator.md +54 -0
- package/guide/zh_CN/tree/mutation_observer.md +52 -0
- package/guide/zh_CN/tree/node_tree.md +142 -0
- package/guide/zh_CN/tree/node_tree_modification.md +78 -0
- package/guide/zh_CN/tree/selector.md +66 -0
- package/jest.config.js +6 -0
- package/jest.dts.config.js +9 -0
- package/jest.unit.config.js +14 -0
- package/package.json +28 -0
- package/src/backend/backend_protocol.ts +313 -0
- package/src/backend/composed_backend_protocol.ts +252 -0
- package/src/backend/domlike_backend_protocol.ts +370 -0
- package/src/backend/mode.ts +51 -0
- package/src/backend/suggested_backend_protocol.ts +83 -0
- package/src/behavior.ts +1655 -0
- package/src/bootstrap_dom_dev.js +22 -0
- package/src/class_list.ts +376 -0
- package/src/component.ts +1309 -0
- package/src/component_params.ts +461 -0
- package/src/component_space.ts +547 -0
- package/src/data_path.ts +225 -0
- package/src/data_proxy.ts +670 -0
- package/src/data_utils.ts +50 -0
- package/src/element.ts +1966 -0
- package/src/element_iterator.ts +158 -0
- package/src/event.ts +401 -0
- package/src/external_shadow_tree.ts +27 -0
- package/src/func_arr.ts +198 -0
- package/src/global_options.ts +242 -0
- package/src/index.ts +187 -0
- package/src/mutation_observer.ts +252 -0
- package/src/native_node.ts +74 -0
- package/src/node.ts +174 -0
- package/src/relation.ts +380 -0
- package/src/render.ts +25 -0
- package/src/selector.ts +218 -0
- package/src/shadow_root.ts +766 -0
- package/src/template_engine.ts +45 -0
- package/src/text_node.ts +149 -0
- package/src/tmpl/index.ts +199 -0
- package/src/tmpl/native_rendering.ts +175 -0
- package/src/tmpl/proc_gen_wrapper.ts +954 -0
- package/src/tmpl/proc_gen_wrapper_dom.ts +230 -0
- package/src/tmpl/range_list_diff.ts +443 -0
- package/src/trait_behaviors.ts +51 -0
- package/src/virtual_node.ts +51 -0
- package/tests/backend/domlike.test.ts +254 -0
- package/tests/base/env.ts +78 -0
- package/tests/base/match.ts +185 -0
- package/tests/core/backend.test.ts +144 -0
- package/tests/core/behavior.test.ts +546 -0
- package/tests/core/component_space.test.ts +212 -0
- package/tests/core/data_update.test.ts +461 -0
- package/tests/core/misc.test.ts +339 -0
- package/tests/core/placeholder.test.ts +180 -0
- package/tests/core/slot.test.ts +1495 -0
- package/tests/core/trait_behaviors.test.ts +153 -0
- package/tests/legacy/README.md +3 -0
- package/tests/legacy/behavior.test.js +293 -0
- package/tests/legacy/component.test.js +1247 -0
- package/tests/legacy/data_path.test.js +149 -0
- package/tests/legacy/data_proxy.test.js +759 -0
- package/tests/legacy/element_iterator.test.js +148 -0
- package/tests/legacy/event.test.js +849 -0
- package/tests/legacy/external.test.js +510 -0
- package/tests/legacy/extra_info.test.js +109 -0
- package/tests/legacy/generics.test.js +176 -0
- package/tests/legacy/mutation_observer.test.js +210 -0
- package/tests/legacy/relation.test.js +517 -0
- package/tests/legacy/selector.test.js +263 -0
- package/tests/legacy/slot.test.js +915 -0
- package/tests/legacy/virtual.test.js +394 -0
- package/tests/tmpl/binding_map.test.ts +208 -0
- package/tests/tmpl/event.test.ts +206 -0
- package/tests/tmpl/expression.test.ts +429 -0
- package/tests/tmpl/lvalue.test.ts +160 -0
- package/tests/tmpl/native_rendering.test.ts +155 -0
- package/tests/tmpl/structure.test.ts +998 -0
- package/tests/types/chaining.test.ts +614 -0
- package/tests/types/createElement.test.ts +82 -0
- package/tests/types/definition.test.ts +442 -0
- package/tsconfig.json +11 -0
- package/webpack.config.js +270 -0
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
# 节点树遍历
|
|
2
|
+
|
|
3
|
+
## 使用节点树遍历器
|
|
4
|
+
|
|
5
|
+
通常,节点树遍历可以直接借助 `ElementIterator` 来实现。
|
|
6
|
+
|
|
7
|
+
例如,依次获得某个节点在 Shadow Tree 上的所有节点:
|
|
8
|
+
|
|
9
|
+
```js
|
|
10
|
+
export const myComponent = componentSpace.defineComponent({
|
|
11
|
+
lifetimes: {
|
|
12
|
+
attached() {
|
|
13
|
+
// 遍历模式: Shadow Tree 上所有子孙节点
|
|
14
|
+
const mode = 'shadow-descendants-root-first'
|
|
15
|
+
// 遍历
|
|
16
|
+
glassEasel.ElementIterator.create(this.shadowRoot, mode)
|
|
17
|
+
.forEach((node) => {
|
|
18
|
+
// 依次回调所有子孙节点
|
|
19
|
+
// 返回 false 会中断遍历
|
|
20
|
+
})
|
|
21
|
+
},
|
|
22
|
+
},
|
|
23
|
+
})
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
节点树遍历模式有以下几种。
|
|
27
|
+
|
|
28
|
+
| 模式 | 遍历范围 | 遍历顺序 |
|
|
29
|
+
| ---- | -------- | -------- |
|
|
30
|
+
| shadow-ancestors | Shadow Tree | 当前节点的祖先节点,由近及远 |
|
|
31
|
+
| shadow-descendants-root-first | Shadow Tree | 当前节点的子孙节点,先父节点再子节点(先根遍历) |
|
|
32
|
+
| shadow-descendants-root-last | Shadow Tree | 当前节点的子孙节点,先子节点再父节点(后根遍历) |
|
|
33
|
+
| composed-ancestors | Composed Tree | 当前节点的祖先节点,由近及远 |
|
|
34
|
+
| composed-descendants-root-first | Composed Tree | 当前节点的子孙节点,先父节点再子节点(先根遍历) |
|
|
35
|
+
| composed-descendants-root-last | Composed Tree | 当前节点的子孙节点,先子节点再父节点(后根遍历) |
|
|
36
|
+
|
|
37
|
+
## 限制节点遍历器返回的节点类型
|
|
38
|
+
|
|
39
|
+
常常,遍历时只需要关心某一类节点。例如,遍历过程中只需要处理 `glassEasel.Element` ,不需要 `glassEasel.TextNode` ,此时可以限制 `ElementIterator` 的返回类型:
|
|
40
|
+
|
|
41
|
+
```js
|
|
42
|
+
export const myComponent = componentSpace.defineComponent({
|
|
43
|
+
lifetimes: {
|
|
44
|
+
attached() {
|
|
45
|
+
const mode = 'shadow-descendants-root-first'
|
|
46
|
+
// 仅返回 glassEasel.Element
|
|
47
|
+
glassEasel.ElementIterator.create(this.shadowRoot, mode, glassEasel.Element)
|
|
48
|
+
.forEach((node) => {
|
|
49
|
+
// 依次回调所有 glassEasel.Element 节点
|
|
50
|
+
})
|
|
51
|
+
},
|
|
52
|
+
},
|
|
53
|
+
})
|
|
54
|
+
```
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
# 节点树变化监听
|
|
2
|
+
|
|
3
|
+
Shadow Tree 的变化可以通过 `MutationObserver` 来监听。
|
|
4
|
+
|
|
5
|
+
例如,获取整个 Shadow Tree 上子节点的变化:
|
|
6
|
+
|
|
7
|
+
```js
|
|
8
|
+
export const myComponent = componentSpace.defineComponent({
|
|
9
|
+
lifetimes: {
|
|
10
|
+
attached() {
|
|
11
|
+
// 监听 Shadow Tree 上的所有属性变化
|
|
12
|
+
glassEasel.MutationObserver.create((ev) => {
|
|
13
|
+
ev.type === 'properties' // true
|
|
14
|
+
ev.target // 是哪个节点发生了变化
|
|
15
|
+
// 如果是组件的属性变化,则 propertyName 会被设置
|
|
16
|
+
ev.propertyName // 变化的属性名
|
|
17
|
+
// 如果是节点的 id 、 slot 、 class 或 style 变化,则 attributeName 会被设置
|
|
18
|
+
ev.attributeName // 变化的项目名
|
|
19
|
+
}).observe(this.shadowRoot, { subtree: true, properties: true })
|
|
20
|
+
|
|
21
|
+
// 监听 Shadow Tree 上节点的插入、移动或移除
|
|
22
|
+
glassEasel.MutationObserver.create((ev) => {
|
|
23
|
+
ev.type === 'childList' // true
|
|
24
|
+
ev.target // 是哪个节点的子节点列表发生了变化
|
|
25
|
+
ev.addedNodes // 新增的节点列表
|
|
26
|
+
ev.removedNodes // 移除的节点列表
|
|
27
|
+
}).observe(this.shadowRoot, { subtree: true, childList: true })
|
|
28
|
+
|
|
29
|
+
// 监听 Shadow Tree 上文本节点的内容变化
|
|
30
|
+
glassEasel.MutationObserver.create((ev) => {
|
|
31
|
+
ev.type === 'characterData' // true
|
|
32
|
+
ev.target // 是哪个节点所含文本发生了变化
|
|
33
|
+
}).observe(this.shadowRoot, { subtree: true, characterData: true })
|
|
34
|
+
|
|
35
|
+
// 监听当前节点的 attach 和 detach 状态变化
|
|
36
|
+
glassEasel.MutationObserver.create((ev) => {
|
|
37
|
+
ev.type === 'attachStatus' // true
|
|
38
|
+
ev.status // 'attached' 或 'detached'
|
|
39
|
+
}).observe(this.shadowRoot, { attachStatus: true })
|
|
40
|
+
},
|
|
41
|
+
},
|
|
42
|
+
})
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
目前 glass-easel 支持的监听:
|
|
46
|
+
|
|
47
|
+
* `properties` 属性变化;
|
|
48
|
+
* `childList` 子节点列表变化;
|
|
49
|
+
* `characterData` 文本内容变化;
|
|
50
|
+
* `attachStatus` attach 和 detach 状态变化。
|
|
51
|
+
|
|
52
|
+
一个监听器可以同时监听多类变化。同时可以激活 `subtree: true` 来监听所有子孙节点的变化。( `subtree: true` 对 `attachStatus` 无效。)
|
|
@@ -0,0 +1,142 @@
|
|
|
1
|
+
# 节点树与节点类型
|
|
2
|
+
|
|
3
|
+
## Shadow Tree
|
|
4
|
+
|
|
5
|
+
glass-easel 自身以 **Shadow Tree** 为单位来存储节点树。每个组件实例对应于一个 Shadow Tree 。
|
|
6
|
+
|
|
7
|
+
例如,对于一个由以下两个组件构成的页面:
|
|
8
|
+
|
|
9
|
+
```js
|
|
10
|
+
export const childComponent = componentSpace.defineComponent({
|
|
11
|
+
template: compileTemplate(`
|
|
12
|
+
<div>Text in childComponent</div>
|
|
13
|
+
<slot />
|
|
14
|
+
`),
|
|
15
|
+
})
|
|
16
|
+
|
|
17
|
+
export const myComponent = componentSpace.defineComponent({
|
|
18
|
+
using: {
|
|
19
|
+
child: childComponent,
|
|
20
|
+
},
|
|
21
|
+
template: compileTemplate(`
|
|
22
|
+
<div class="blue" />
|
|
23
|
+
<child>
|
|
24
|
+
<span>{{ text }}</span>
|
|
25
|
+
</child>
|
|
26
|
+
`),
|
|
27
|
+
data: { text: 'Text in myComponent' },
|
|
28
|
+
})
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
这个页面中,包含两个 Shadow Tree 。其一是根组件 myComponent 的 Shadow Tree :
|
|
32
|
+
|
|
33
|
+
```
|
|
34
|
+
ShadowRoot
|
|
35
|
+
- div class="blue"
|
|
36
|
+
- child
|
|
37
|
+
- span
|
|
38
|
+
- "Text in myComponent"
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
其二是 childComponent 的 Shadow Tree :
|
|
42
|
+
|
|
43
|
+
```
|
|
44
|
+
ShadowRoot
|
|
45
|
+
- div
|
|
46
|
+
- "Text in childComponent"
|
|
47
|
+
- slot
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
Shadow Tree 有几个关键特点:
|
|
51
|
+
|
|
52
|
+
* Shadow Tree 是一个组件实例自身模板中包含的节点,包括 slot 节点本身,但不包括组件的使用者放入 slot 中的内容;
|
|
53
|
+
* 每个 Shadow Tree 都以一种特殊的 `ShadowRoot` 节点为根节点。
|
|
54
|
+
|
|
55
|
+
## Composed Tree
|
|
56
|
+
|
|
57
|
+
Shadow Tree 不能直接用于最终的页面,还需要经过一个 **树拼接** 过程,将所有 Shadow Tree 拼成一个大的 **Composed Tree** 。
|
|
58
|
+
|
|
59
|
+
这个拼接过程中,组件节点会和它的 `ShadowRoot` 对应组合, slot 中也会被放入内容。
|
|
60
|
+
|
|
61
|
+
对于上例, Composed Tree 是:
|
|
62
|
+
|
|
63
|
+
```
|
|
64
|
+
ShadowRoot
|
|
65
|
+
- div class="blue"
|
|
66
|
+
- child
|
|
67
|
+
- ShadowRoot
|
|
68
|
+
- div
|
|
69
|
+
- "Text in childComponent"
|
|
70
|
+
- slot
|
|
71
|
+
- span
|
|
72
|
+
- "Text in myComponent"
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
Composed Tree 中包含一些 **虚拟节点** ,如 `ShadowRoot` 和 slot ,将这些节点去掉之后就是真正的 DOM 节点树了。
|
|
76
|
+
|
|
77
|
+
## 直接树访问
|
|
78
|
+
|
|
79
|
+
访问组件实例的 `this.shadowRoot` 属性可以获取到这个组件实例对应的 `ShadowRoot` 节点。进而通过每个节点的 `childNodes` 数组可以直接访问到每个节点。例如:
|
|
80
|
+
|
|
81
|
+
```js
|
|
82
|
+
export const childComponent = componentSpace.defineComponent({
|
|
83
|
+
template: compileTemplate(`
|
|
84
|
+
<div>Text in childComponent</div>
|
|
85
|
+
<slot />
|
|
86
|
+
`),
|
|
87
|
+
lifetimes: {
|
|
88
|
+
attached() {
|
|
89
|
+
const shadowRoot = this.shadowRoot
|
|
90
|
+
const textNode = shadowRoot.childNodes[0].childNodes[0]
|
|
91
|
+
textNode.textContent === 'Text in childComponent' // true
|
|
92
|
+
},
|
|
93
|
+
},
|
|
94
|
+
})
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
## 节点类型
|
|
98
|
+
|
|
99
|
+
在通过 `childNodes` 访问节点树时,可能会访问到以下几种类型的节点:
|
|
100
|
+
|
|
101
|
+
* `glassEasel.TextNode` 文本节点;
|
|
102
|
+
* `glassEasel.NativeNode` 普通节点,如 `<div />` ;
|
|
103
|
+
* `glassEasel.Component` 组件节点;
|
|
104
|
+
* `glassEasel.VirtualNode` 虚拟节点。
|
|
105
|
+
|
|
106
|
+
其中,除了 `glassEasel.TextNode` 之外,其余类型共有一个基类 `glassEasel.Element` 。
|
|
107
|
+
|
|
108
|
+
`glassEasel.ShadowRoot` 是 `glassEasel.VirtualNode` 的子类。
|
|
109
|
+
|
|
110
|
+
## 常用树遍历属性和方法
|
|
111
|
+
|
|
112
|
+
除了 `childNodes` 外,还有一些属性和方法可以用来进行树遍历。常用的属性和方法如下:
|
|
113
|
+
|
|
114
|
+
* `glassEasel.Element#childNodes` 当前节点的所有 Shadow Tree 子节点列表;
|
|
115
|
+
* `glassEasel.Element#parentNode` 当前节点的 Shadow Tree 父节点;
|
|
116
|
+
* `glassEasel.Element#ownerShadowRoot` 当前节点所在 Shadow Tree 的 `ShadowRoot` ;
|
|
117
|
+
* `glassEasel.Element#getComposedChildren()` 当前节点的所有 Composed Tree 的子节点列表;
|
|
118
|
+
* `glassEasel.Element#getComposedParent()` 当前节点的 Composed Tree 的父节点;
|
|
119
|
+
* `glassEasel.Component#shadowRoot` 当前组件节点的 `ShadowRoot` ,对于 [外部组件](../advanced/external_component.md) 是一个 `glassEasel.ExternalShadowRoot` ;
|
|
120
|
+
* `glassEasel.Component#getShadowRoot()` 当前组件节点的 `ShadowRoot` ,对于 [外部组件](../advanced/external_component.md) 返回空;
|
|
121
|
+
* `glassEasel.ShadowRoot#getHostNode()` 当前 `ShadowRoot` 对应的组件节点;
|
|
122
|
+
|
|
123
|
+
注意:不要直接修改这些属性。
|
|
124
|
+
|
|
125
|
+
如果只是进行常规的树遍历,可以使用 [节点树遍历](element_iterator.md) 接口。
|
|
126
|
+
|
|
127
|
+
## 调试输出节点树
|
|
128
|
+
|
|
129
|
+
如果只是想临时输出节点树结构信息供调试使用,可以使用 `dumpElement` 或 `dumpElementToString` 方法:
|
|
130
|
+
|
|
131
|
+
```js
|
|
132
|
+
componentSpace.defineComponent({
|
|
133
|
+
lifetimes: {
|
|
134
|
+
attached() {
|
|
135
|
+
// 在 console 中输出 Shadow Tree
|
|
136
|
+
glassEasel.dumpElement(this.shadowRoot, false)
|
|
137
|
+
// 在 console 中输出 Composed Tree
|
|
138
|
+
glassEasel.dumpElement(this, true)
|
|
139
|
+
},
|
|
140
|
+
},
|
|
141
|
+
})
|
|
142
|
+
```
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
# 节点树变更
|
|
2
|
+
|
|
3
|
+
## 何时可以手工变更节点树
|
|
4
|
+
|
|
5
|
+
绝大多数情况下,节点树都应该通过模板和数据绑定来改变。但在极少数情况下,需要绕开模板来手工变更节点树。
|
|
6
|
+
|
|
7
|
+
一种情况是,在实现 [自定义模板引擎](../advanced/template_engine.md) 时需要手工变更节点树。
|
|
8
|
+
|
|
9
|
+
另一种情况是,有些极特殊的组件树结构无法采用模板引擎表达。请注意:这种情况下,对于节点树的手工变更常常会和模板带来的更新冲突!通常,只应该更新不在模板上的节点,例如在模板的一个空节点内部插入新节点。
|
|
10
|
+
|
|
11
|
+
变更节点树时,只需要变更 Shadow Tree ,而 Composed Tree 会自动变更。所以只关心 Shadow Tree 的变更方法即可。
|
|
12
|
+
|
|
13
|
+
## 创建一个节点
|
|
14
|
+
|
|
15
|
+
创建节点时,可以使用组件实例的 `this.shadowRoot` 下的几个创建方法。
|
|
16
|
+
|
|
17
|
+
| 方法名 | 说明 |
|
|
18
|
+
| ------ | ---- |
|
|
19
|
+
| createTextNode | 创建一个 `glassEasel.TextNode` 文本节点 |
|
|
20
|
+
| createNativeNode | 创建一个 `glassEasel.NativeNode` 普通节点 |
|
|
21
|
+
| createComponent | 创建一个 `glassEasel.Component` 组件节点 |
|
|
22
|
+
| createComponentOrNativeNode | 如果节点名字是一个组件,就创建一个 `glassEasel.Component` 组件节点,否则创建一个 `glassEasel.NativeNode` 普通节点 |
|
|
23
|
+
| createVirtualNode | 创建一个 `glassEasel.VirtualNode` 虚拟节点 |
|
|
24
|
+
|
|
25
|
+
注意,在一个 `glassEasel.ShadowRoot` 下创建的节点只能被插入到这个 Shadow Tree 中。
|
|
26
|
+
|
|
27
|
+
## 增删节点
|
|
28
|
+
|
|
29
|
+
将节点插入节点树或移出节点树时,可以使用 `glassEasel.Element` 下的几个插入、移除方法。
|
|
30
|
+
|
|
31
|
+
| 方法名 | 说明 |
|
|
32
|
+
| ------ | ---- |
|
|
33
|
+
| appendChild | 追加一个新子节点 |
|
|
34
|
+
| insertChildAt | 在第 index 个子节点的位置上插入一个新子节点 |
|
|
35
|
+
| insertBefore | 在指定的子节点之前插入一个新子节点 |
|
|
36
|
+
| insertChildren | 批量插入新子节点 |
|
|
37
|
+
| removeChildAt | 移除第 index 个子节点 |
|
|
38
|
+
| removeChild | 移除指定的子节点 |
|
|
39
|
+
| removeChildren | 批量移除子节点 |
|
|
40
|
+
| replaceChildAt | 替换第 index 个子节点为新子节点 |
|
|
41
|
+
| replaceChild | 替换指定的子节点为新子节点 |
|
|
42
|
+
| selfReplaceWith | 将节点自身替换为一个新节点 |
|
|
43
|
+
|
|
44
|
+
如果将一个已经被插入的节点插入到另一个位置上,则会自动变为一个移动操作。
|
|
45
|
+
|
|
46
|
+
glass-easel 内部使用的算法是针对在一个节点末尾追加新子节点(即 `appendChild` )来优化的,所以请尽量多使用这样的操作。
|
|
47
|
+
|
|
48
|
+
## 销毁节点
|
|
49
|
+
|
|
50
|
+
将一个节点移出节点树之后,如果它不再被使用,则需要调用销毁方法 `glassEasel.Element.destroyBackendElement` ,否则有些情况下会出现内存泄漏。
|
|
51
|
+
|
|
52
|
+
如果一个节点在被移出节点树后就必然不会再被使用,则可以提前调用 `glassEasel.Element.destroyBackendElementOnDetach` 使它在被移出后自动销毁,避免遗忘。
|
|
53
|
+
|
|
54
|
+
## 节点树变更流程示例
|
|
55
|
+
|
|
56
|
+
对节点树的操作流程可以大体上以下例表示:
|
|
57
|
+
|
|
58
|
+
```js
|
|
59
|
+
export const myComponent = componentSpace.defineComponent({
|
|
60
|
+
template: compileTemplate(`
|
|
61
|
+
<div id="wrapper" />
|
|
62
|
+
`),
|
|
63
|
+
lifetimes: {
|
|
64
|
+
attached() {
|
|
65
|
+
// 获得 wrapper 节点
|
|
66
|
+
const wrapper = this.shadowRoot.getElementById('#wrapper')
|
|
67
|
+
// 创建一个新的 span 节点
|
|
68
|
+
const span = this.shadowRoot.createNativeNode('span')
|
|
69
|
+
// 当 span 被移出时自动销毁它
|
|
70
|
+
span.destroyBackendElementOnDetach()
|
|
71
|
+
// 将 span 插入到 wrapper 下
|
|
72
|
+
wrapper.appendChild(span)
|
|
73
|
+
// 将 span 移除出来
|
|
74
|
+
wrapper.removeChildAt(0)
|
|
75
|
+
},
|
|
76
|
+
},
|
|
77
|
+
})
|
|
78
|
+
```
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
# 选择器查询
|
|
2
|
+
|
|
3
|
+
## 使用选择器获取节点
|
|
4
|
+
|
|
5
|
+
通常,可通过选择器来快速获得 Shadow Tree 上一个特定的子孙节点。
|
|
6
|
+
|
|
7
|
+
例如,获得一个 id 为 `the-id` 的子节点:
|
|
8
|
+
|
|
9
|
+
```js
|
|
10
|
+
export const myComponent = componentSpace.defineComponent({
|
|
11
|
+
template: compileTemplate(`
|
|
12
|
+
<div>
|
|
13
|
+
<span id="the-id">Some Text</span>
|
|
14
|
+
</div>
|
|
15
|
+
`),
|
|
16
|
+
lifetimes: {
|
|
17
|
+
attached() {
|
|
18
|
+
// 获取 id="the-id" 的节点
|
|
19
|
+
const span = this.shadowRoot.querySelector('#the-id')
|
|
20
|
+
span.childNodes[0].textContent = 'Some Text'
|
|
21
|
+
},
|
|
22
|
+
},
|
|
23
|
+
})
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
目前 glass-easel 支持的选择器列表如下。
|
|
27
|
+
|
|
28
|
+
| 名称 | 示例 | 说明 |
|
|
29
|
+
| ---- | ---- | ---- |
|
|
30
|
+
| id 选择器 | `#the-id` | 选择节点 id 为 `the-id` 的节点 |
|
|
31
|
+
| class 选择器 | `.the-class` | 选择节点 class 含 `the-class` 的节点 |
|
|
32
|
+
| 交集选择 | `#the-id.the-class` | 选择节点 id 为 `the-id` 且 class 含 `the-class` 的节点 |
|
|
33
|
+
| 儿子选择 | `#the-id > .the-class` | 在节点 id 为 `the-id` 节点的儿子节点中,选择节点 class 含 `the-class` 的节点 |
|
|
34
|
+
| 子孙选择 | `#the-id .the-class` | 在节点 id 为 `the-id` 节点的子孙节点中,选择节点 class 含 `the-class` 的节点 |
|
|
35
|
+
| 跨组件子孙选择 | `#the-id >>> .the-class` | 在节点 id 为 `the-id` 节点的子孙节点中,选择节点 class 含 `the-class` 的节点,查找时可以进入其他组件、不限于当前 Shadow Tree |
|
|
36
|
+
|
|
37
|
+
`querySelector` 只会返回第一个找到的节点。如果需要返回所有节点组成的列表,使用 `querySelectorAll` 。
|
|
38
|
+
|
|
39
|
+
## 节点类型特化
|
|
40
|
+
|
|
41
|
+
在使用 TypeScript 时,选择器查询返回的节点都是 `glassEasel.Element` 类型。此时可以使用一些类型特化方法将其转换为更具体的节点类型。
|
|
42
|
+
|
|
43
|
+
最常用的类型特化方法是 `asInstanceOf` ,用来将一个节点转为某个特定组件的实例,例如:
|
|
44
|
+
|
|
45
|
+
```js
|
|
46
|
+
export const childComponent = componentSpace.define()
|
|
47
|
+
.methods({
|
|
48
|
+
aPlusB(a, b) { return a + b }
|
|
49
|
+
})
|
|
50
|
+
.registerComponent()
|
|
51
|
+
export const myComponent = componentSpace.define()
|
|
52
|
+
.usingComponents({
|
|
53
|
+
child: childComponent,
|
|
54
|
+
})
|
|
55
|
+
.template(compileTemplate(`
|
|
56
|
+
<child id="the-id" />
|
|
57
|
+
`)
|
|
58
|
+
.lifetime('attached', function () {
|
|
59
|
+
// 获取 id="the-id" 的节点,并将其转换为 childComponent 的实例
|
|
60
|
+
const child = this.shadowRoot.querySelector('#the-id').asInstanceOf(childComponent)!
|
|
61
|
+
child.aPlusB(1, 2) === 3 // true
|
|
62
|
+
})
|
|
63
|
+
.registerComponent()
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
另一种比较好的实现方式是不关心节点的具体类型、只关心节点实现的接口,以实现更好的组件间解耦,此时可以使用 [Trait Behaviors](../interaction/trait_behavior.md) 。
|
package/jest.config.js
ADDED
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
module.exports = {
|
|
2
|
+
preset: 'ts-jest/presets/js-with-babel',
|
|
3
|
+
globals: {
|
|
4
|
+
'ts-jest': {
|
|
5
|
+
tsconfig: 'tsconfig.json',
|
|
6
|
+
},
|
|
7
|
+
},
|
|
8
|
+
roots: ['tests'],
|
|
9
|
+
testMatch: ['**/?(*.)+(spec|test).[jt]s?(x)', '!**/types/**'],
|
|
10
|
+
testEnvironment: 'jsdom',
|
|
11
|
+
"collectCoverageFrom": [
|
|
12
|
+
"src/**/*.ts"
|
|
13
|
+
],
|
|
14
|
+
}
|
package/package.json
ADDED
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "glass-easel",
|
|
3
|
+
"description": "The core module of the glass-easel project",
|
|
4
|
+
"version": "0.1.0",
|
|
5
|
+
"repository": {
|
|
6
|
+
"type": "git",
|
|
7
|
+
"url": "https://github.com/wechat-miniprogram/glass-easel.git"
|
|
8
|
+
},
|
|
9
|
+
"keywords": ["glass-easel"],
|
|
10
|
+
"author": "wechat-miniprogram",
|
|
11
|
+
"license": "MIT",
|
|
12
|
+
"bugs": {
|
|
13
|
+
"url": "https://github.com/wechat-miniprogram/glass-easel/issues"
|
|
14
|
+
},
|
|
15
|
+
"homepage": "https://github.com/wechat-miniprogram/glass-easel",
|
|
16
|
+
"main": "dist/index.js",
|
|
17
|
+
"scripts": {
|
|
18
|
+
"doc": "typedoc src/index.ts --excludePrivate --excludeProtected --excludeInternal",
|
|
19
|
+
"build": "webpack --config webpack.config.js",
|
|
20
|
+
"dev": "webpack --config webpack.config.js --watch",
|
|
21
|
+
"lint": "eslint src/**/*.ts",
|
|
22
|
+
"test": "jest -c jest.config.js",
|
|
23
|
+
"coverage": "jest -c jest.config.js --collect-coverage"
|
|
24
|
+
},
|
|
25
|
+
"devDependencies": {
|
|
26
|
+
"glass-easel-template-compiler": "*"
|
|
27
|
+
}
|
|
28
|
+
}
|