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,151 @@
|
|
|
1
|
+
# 组件间关系
|
|
2
|
+
|
|
3
|
+
## 基于组件的 relations
|
|
4
|
+
|
|
5
|
+
有时会遇到一些组件相互之间存在紧密的逻辑联系,在它们作为父子节点被联合使用时,需要执行一些额外的逻辑。
|
|
6
|
+
|
|
7
|
+
例如,需要实现表单控件 `<form>` `<input>` ,而它们之间有紧密的关联逻辑。此时可以使用 relations ,使它们之间可以相互获取组件实例 `this` :
|
|
8
|
+
|
|
9
|
+
```js
|
|
10
|
+
// form 组件,需要关联到子孙节点中的 input 组件
|
|
11
|
+
export const formComponent = componentSpace.defineComponent({
|
|
12
|
+
is: 'component/form',
|
|
13
|
+
relations: {
|
|
14
|
+
// 需要关联到 input 组件
|
|
15
|
+
'./input': {
|
|
16
|
+
// 关联范围是子孙节点
|
|
17
|
+
type: 'descendant',
|
|
18
|
+
linked(target) {
|
|
19
|
+
// 每当有 input 组件插入时,这个函数会执行一次
|
|
20
|
+
// 参数中的 target 是 input 组件实例
|
|
21
|
+
// 使用 getRelationNodes 可以获取当前关联到的所有 input 组件
|
|
22
|
+
this.getRelationNodes('./input')
|
|
23
|
+
},
|
|
24
|
+
unlinked(target) {
|
|
25
|
+
// 每当有 input 组件移除时,这个函数会执行一次
|
|
26
|
+
},
|
|
27
|
+
}
|
|
28
|
+
},
|
|
29
|
+
})
|
|
30
|
+
|
|
31
|
+
// input 组件,需要关联到祖先节点中的 form 组件
|
|
32
|
+
export const myComponent = componentSpace.defineComponent({
|
|
33
|
+
is: 'component/input',
|
|
34
|
+
relations: {
|
|
35
|
+
// 需要关联到 form 组件
|
|
36
|
+
'./form': {
|
|
37
|
+
// 关联范围是祖先节点
|
|
38
|
+
type: 'ancestor',
|
|
39
|
+
linked(target) {
|
|
40
|
+
// 关联到 form 组件时,这个函数会执行一次
|
|
41
|
+
},
|
|
42
|
+
linkFailed() {
|
|
43
|
+
// 没有关联到 form 组件时,这个函数会执行一次
|
|
44
|
+
},
|
|
45
|
+
}
|
|
46
|
+
},
|
|
47
|
+
})
|
|
48
|
+
|
|
49
|
+
// 同时使用这两个组件
|
|
50
|
+
export const myComponent = componentSpace.defineComponent({
|
|
51
|
+
using: {
|
|
52
|
+
form: formComponent,
|
|
53
|
+
input: inputComponent,
|
|
54
|
+
},
|
|
55
|
+
template: compileTemplate(`
|
|
56
|
+
<form>
|
|
57
|
+
<input />
|
|
58
|
+
</form>
|
|
59
|
+
`),
|
|
60
|
+
})
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
这样, `<form>` 和 `<input>` 可以实现更复杂的关联逻辑。
|
|
64
|
+
|
|
65
|
+
目前 relation 支持的关联范围有以下这些。
|
|
66
|
+
|
|
67
|
+
| 关联范围 | 含义 |
|
|
68
|
+
| ---- | ---- |
|
|
69
|
+
| `ancestor` | 需关联到一个祖先组件 |
|
|
70
|
+
| `descendant` | 可关联到若干子孙组件 |
|
|
71
|
+
| `parent` | 需关联到一个祖先组件,但中间不能间隔其他组件节点 |
|
|
72
|
+
| `child` | 可关联到若干子孙组件,但中间不能间隔其他组件节点 |
|
|
73
|
+
| `parent-common-node` | 需关联到一个祖先组件,但中间不能间隔其他普通节点或组件节点 |
|
|
74
|
+
| `child-common-node` | 可关联到若干子孙组件,但中间不能间隔其他普通节点或组件节点 |
|
|
75
|
+
|
|
76
|
+
注意:它们必须成对使用,只在一个节点上声明 `relations` 、使用不成对的关联范围都是无效的。
|
|
77
|
+
|
|
78
|
+
每个 relation 定义都包含了四个 relation 生命周期。
|
|
79
|
+
|
|
80
|
+
| relation 生命周期 | 首个参数 | 触发时机 |
|
|
81
|
+
| ----------------- | -------- | -------- |
|
|
82
|
+
| `linked` | 对应组件实例 this | 每当关联到新的组件实例 |
|
|
83
|
+
| `linkChanged` | 对应组件实例 this | 每当有关联到的组件实例发生了移动 |
|
|
84
|
+
| `unlinked` | 对应组件实例 this | 每当有关联到的组件实例被移除 |
|
|
85
|
+
| `linkFailed` | (无) | 当未找到需要关联的祖先组件时 |
|
|
86
|
+
|
|
87
|
+
## 基于 trait behavior 的 relations
|
|
88
|
+
|
|
89
|
+
如果建立 relations 的组件不是某个特定的组件,而是一类组件,则可以使用 behaviors 或者 trait behaviors 来规定 relations 。
|
|
90
|
+
|
|
91
|
+
例如,表单组件 `<form>` 需要关联 `<input>` `<button>` 等一类组件,可以对 `<input>` `<button>` 实现同一个 trait behavior ,这样也会有更好的 TypeScript 类型支持。这种情况下,使用 init 来实现比较好:
|
|
92
|
+
|
|
93
|
+
```ts
|
|
94
|
+
// 定义一个公共的 trait behavior
|
|
95
|
+
interface FormControlInterface {
|
|
96
|
+
getName(): string
|
|
97
|
+
getValue(): string
|
|
98
|
+
}
|
|
99
|
+
const FormControl = componentSpace.defineTraitBehavior<FormControlInterface>()
|
|
100
|
+
|
|
101
|
+
// 定义 form 组件
|
|
102
|
+
export const formComponent = componentSpace.define()
|
|
103
|
+
.init(function ({ implement, relation }) {
|
|
104
|
+
// 关联到所有 FormControl
|
|
105
|
+
const rel = relation({
|
|
106
|
+
type: 'descendant',
|
|
107
|
+
target: FormControl,
|
|
108
|
+
linked(target) {
|
|
109
|
+
// 获得目标节点对 trait behavior 的实现
|
|
110
|
+
const impl = target.traitBehavior(FormControl)
|
|
111
|
+
impl.getName()
|
|
112
|
+
impl.getValue()
|
|
113
|
+
},
|
|
114
|
+
})
|
|
115
|
+
// 获取当前关联到的所有组件
|
|
116
|
+
rel.list()
|
|
117
|
+
})
|
|
118
|
+
.registerComponent()
|
|
119
|
+
|
|
120
|
+
// 定义 input 组件
|
|
121
|
+
export const inputComponent = componentSpace.define()
|
|
122
|
+
.init(function ({ implement, relation }) {
|
|
123
|
+
// 实现 FormControl
|
|
124
|
+
implement(FormControl, {
|
|
125
|
+
getName() { return '...' },
|
|
126
|
+
getValue() { return '...' },
|
|
127
|
+
})
|
|
128
|
+
// 关联到 form
|
|
129
|
+
relation({
|
|
130
|
+
type: 'ancestor',
|
|
131
|
+
target: formComponent,
|
|
132
|
+
})
|
|
133
|
+
})
|
|
134
|
+
.registerComponent()
|
|
135
|
+
|
|
136
|
+
// 定义 button 组件
|
|
137
|
+
export const buttonComponent = componentSpace.define()
|
|
138
|
+
.init(function ({ implement, relation }) {
|
|
139
|
+
// 实现 FormControl
|
|
140
|
+
implement(FormControl, {
|
|
141
|
+
getName() { return '...' },
|
|
142
|
+
getValue() { return '...' },
|
|
143
|
+
})
|
|
144
|
+
// 关联到 form
|
|
145
|
+
relation({
|
|
146
|
+
type: 'ancestor',
|
|
147
|
+
target: formComponent,
|
|
148
|
+
})
|
|
149
|
+
})
|
|
150
|
+
.registerComponent()
|
|
151
|
+
```
|
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
# slot 及 slot 类型
|
|
2
|
+
|
|
3
|
+
## 单一 slot
|
|
4
|
+
|
|
5
|
+
子组件可以通过 `<slot />` 节点来承载它在父组件上的子树内容,例如:
|
|
6
|
+
|
|
7
|
+
```js
|
|
8
|
+
export const childComponent = componentSpace.defineComponent({
|
|
9
|
+
template: compileTemplate(`
|
|
10
|
+
<div>
|
|
11
|
+
<slot />
|
|
12
|
+
</div>
|
|
13
|
+
`),
|
|
14
|
+
})
|
|
15
|
+
export const myComponent = componentSpace.defineComponent({
|
|
16
|
+
using: {
|
|
17
|
+
child: childComponent,
|
|
18
|
+
},
|
|
19
|
+
template: compileTemplate(`
|
|
20
|
+
<div>
|
|
21
|
+
<child>
|
|
22
|
+
<div class="a" />
|
|
23
|
+
</child>
|
|
24
|
+
</div>
|
|
25
|
+
`),
|
|
26
|
+
})
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
上例中 `<div class="a" />` 将被放置到子组件中的 `<slot />` 位置上。
|
|
30
|
+
|
|
31
|
+
## 多 slot
|
|
32
|
+
|
|
33
|
+
有时子组件需要放置多个 slot 节点。此时可以指定组件的 `multipleSlots` 选项,并使用 `name` 来区分多个节点,例如:
|
|
34
|
+
|
|
35
|
+
```js
|
|
36
|
+
export const childComponent = componentSpace.defineComponent({
|
|
37
|
+
options: {
|
|
38
|
+
multipleSlots: true,
|
|
39
|
+
},
|
|
40
|
+
template: compileTemplate(`
|
|
41
|
+
<div>
|
|
42
|
+
<slot name="body" />
|
|
43
|
+
</div>
|
|
44
|
+
<slot name="footer" />
|
|
45
|
+
`),
|
|
46
|
+
})
|
|
47
|
+
export const myComponent = componentSpace.defineComponent({
|
|
48
|
+
using: {
|
|
49
|
+
child: childComponent,
|
|
50
|
+
},
|
|
51
|
+
template: compileTemplate(`
|
|
52
|
+
<div>
|
|
53
|
+
<child>
|
|
54
|
+
<div slot="body"> 这段内容被插入到 name="body" 的 slot 中 </div>
|
|
55
|
+
<div slot="footer"> 这段内容被插入到 name="footer" 的 slot 中 </div>
|
|
56
|
+
</child>
|
|
57
|
+
</div>
|
|
58
|
+
`),
|
|
59
|
+
})
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
glass-easel 本身为单一 slot 应用了更多优化。激活 `multipleSlots` 同时也禁用了一些优化,对于不需要多 slot 的组件,最好不要激活这个选项。
|
|
63
|
+
|
|
64
|
+
## 动态 slot
|
|
65
|
+
|
|
66
|
+
上述两种 slot 类型要求(相同 name 的) slot 节点只有一个,重复的 `<slot />` 中只有第一个会生效。
|
|
67
|
+
|
|
68
|
+
但有时,需要在列表中放置 `<slot />` ,表示将 slot 内容重复多次。此时需要指定组件的 `dynamicSlots` 选项,例如:
|
|
69
|
+
|
|
70
|
+
```js
|
|
71
|
+
export const childComponent = componentSpace.defineComponent({
|
|
72
|
+
options: {
|
|
73
|
+
dynamicSlots: true,
|
|
74
|
+
},
|
|
75
|
+
template: compileTemplate(`
|
|
76
|
+
<block wx:for="{{ list }}">
|
|
77
|
+
<slot />
|
|
78
|
+
</div>
|
|
79
|
+
`),
|
|
80
|
+
data: {
|
|
81
|
+
list: ['A', 'B', 'C'],
|
|
82
|
+
},
|
|
83
|
+
})
|
|
84
|
+
export const myComponent = componentSpace.defineComponent({
|
|
85
|
+
using: {
|
|
86
|
+
child: childComponent,
|
|
87
|
+
},
|
|
88
|
+
template: compileTemplate(`
|
|
89
|
+
<div>
|
|
90
|
+
<child>
|
|
91
|
+
<div class="a" />
|
|
92
|
+
</child>
|
|
93
|
+
</div>
|
|
94
|
+
`),
|
|
95
|
+
})
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
当 `dynamicSlots` 选项激活时,还可以向 slot 中传递数据,组件的使用者可以通过 `slot:` 来接收 slot 传递的数据,例如:
|
|
99
|
+
|
|
100
|
+
```js
|
|
101
|
+
export const childComponent = componentSpace.defineComponent({
|
|
102
|
+
options: {
|
|
103
|
+
dynamicSlots: true,
|
|
104
|
+
},
|
|
105
|
+
template: compileTemplate(`
|
|
106
|
+
<block wx:for="{{ list }}">
|
|
107
|
+
<slot list-index="{{ index }}" item="{{ item }}" />
|
|
108
|
+
</div>
|
|
109
|
+
`),
|
|
110
|
+
data: {
|
|
111
|
+
list: ['A', 'B', 'C'],
|
|
112
|
+
},
|
|
113
|
+
})
|
|
114
|
+
export const myComponent = componentSpace.defineComponent({
|
|
115
|
+
using: {
|
|
116
|
+
child: childComponent,
|
|
117
|
+
},
|
|
118
|
+
template: compileTemplate(`
|
|
119
|
+
<div>
|
|
120
|
+
<child>
|
|
121
|
+
<div class="a" slot:item>{{ item }}</div>
|
|
122
|
+
</child>
|
|
123
|
+
</div>
|
|
124
|
+
`),
|
|
125
|
+
})
|
|
126
|
+
```
|
|
127
|
+
|
|
128
|
+
使用 `slot:` 来接收数据时,也可以用 `=` 来指定一个别名。此外,接收数据的节点也可以是 `<block />` 。例如:
|
|
129
|
+
|
|
130
|
+
```xml
|
|
131
|
+
<child>
|
|
132
|
+
<div class="a" slot:listIndex="index">{{ index }}</div>
|
|
133
|
+
<block slot:item>{{ item }}</div>
|
|
134
|
+
</child>
|
|
135
|
+
```
|
|
136
|
+
|
|
137
|
+
通过 slot 传递的数据受到 [数据字段拷贝控制](../data_management/data_deep_copy.md) 选项中的 `propertyPassingDeepCopy` 选项控制。
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
# 多文件模板
|
|
2
|
+
|
|
3
|
+
## 模板片段
|
|
4
|
+
|
|
5
|
+
模板中可以使用 `<template>` 来提取一些公共的模板片段。
|
|
6
|
+
|
|
7
|
+
其中, `<template name="...">` 可以用来定义模板片段,片段中可以使用数据绑定,例如:
|
|
8
|
+
|
|
9
|
+
```xml
|
|
10
|
+
<template name="shared-template-slice">
|
|
11
|
+
<div> {{ a }} + {{ b }} = {{ c }} </div>
|
|
12
|
+
</template>
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
而 `<template is="...">` 可以用来引用模板片段,引用时需要指定数据绑定,例如:
|
|
16
|
+
|
|
17
|
+
```xml
|
|
18
|
+
<template is="shared-template-slice" data="{{ a: 1, b: 2 }}"></template>
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
注意, `data="{{ }}"` 内部就是一个对象形式定义。
|
|
22
|
+
|
|
23
|
+
## 跨组件的模板片段
|
|
24
|
+
|
|
25
|
+
如果需要在多个组件中使用同一个模板片段,则需要调整模板编译方式。
|
|
26
|
+
|
|
27
|
+
在模板编译时,首先需要创建一个 `TmplGroup` 对象。这个对象可以同时管理多个路径的模板代码,例如:
|
|
28
|
+
|
|
29
|
+
```js
|
|
30
|
+
import { TmplGroup } from 'glass-easel-template-compiler'
|
|
31
|
+
|
|
32
|
+
const group = new TmplGroup()
|
|
33
|
+
|
|
34
|
+
// 添加一个模板路径及其对应的模板内容
|
|
35
|
+
group.addTmpl('path/to/a/component', `
|
|
36
|
+
<div> text in a template </div>
|
|
37
|
+
`)
|
|
38
|
+
|
|
39
|
+
// 添加另一个模板路径及其对应的模板内容
|
|
40
|
+
group.addTmpl('path/to/another/component', `
|
|
41
|
+
<div> text in another template </div>
|
|
42
|
+
`)
|
|
43
|
+
|
|
44
|
+
// 生成模板编译结果
|
|
45
|
+
const genObjectSrc = `return ${group.getTmplGenObjectGroups()}`
|
|
46
|
+
const genObjectGroupList = (new Function(genObjectSrc))() as { [key: string]: any }
|
|
47
|
+
group.free()
|
|
48
|
+
|
|
49
|
+
// 从编译结果中提取指定路径的模板
|
|
50
|
+
const templateForAComponent = {
|
|
51
|
+
groupList: genObjectGroupList,
|
|
52
|
+
content: genObjectGroupList['path/to/a/template'],
|
|
53
|
+
}
|
|
54
|
+
const templateForAnotherComponent = {
|
|
55
|
+
groupList: genObjectGroupList,
|
|
56
|
+
content: genObjectGroupList['path/to/another/template'],
|
|
57
|
+
}
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
这样,可以使用一个独立的模板路径来存放公共的模板片段,例如:
|
|
61
|
+
|
|
62
|
+
```js
|
|
63
|
+
group.addTmpl('path/to/shared', `
|
|
64
|
+
<template name="shared-template-slice">
|
|
65
|
+
<div> {{ a }} + {{ b }} = {{ c }} </div>
|
|
66
|
+
</template>
|
|
67
|
+
`)
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
在其他路径的模板中,可以使用 `<import>` 引入模板片段:
|
|
71
|
+
|
|
72
|
+
```js
|
|
73
|
+
group.addTmpl('path/to/a/component', `
|
|
74
|
+
<import src="../shared" />
|
|
75
|
+
|
|
76
|
+
<template is="shared-template-slice" data="{{ a: 1, b: 2 }}" />
|
|
77
|
+
`)
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
## 模板文件引入
|
|
81
|
+
|
|
82
|
+
在引用其他路径的模板时,也可以使用 `<include>` 直接将整个模板文件内容嵌入到当前位置上,例如:
|
|
83
|
+
|
|
84
|
+
```js
|
|
85
|
+
group.addTmpl('path/to/shared', `
|
|
86
|
+
<div> some text in shared template </div>
|
|
87
|
+
`)
|
|
88
|
+
|
|
89
|
+
group.addTmpl('path/to/a/component', `
|
|
90
|
+
<div>
|
|
91
|
+
<include src="../shared" />
|
|
92
|
+
</div>
|
|
93
|
+
`)
|
|
94
|
+
```
|
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
# Trait Behaviors
|
|
2
|
+
|
|
3
|
+
## 定义和实现 trait behavior
|
|
4
|
+
|
|
5
|
+
trait behaviors 是一种组件间共享接口的机制,也可以用于给组件归类(类似于一些编程语言的 trait )。
|
|
6
|
+
|
|
7
|
+
在 TypeScript 下,通过 trait behaviors ,可以定义一组接口方法,若干组件都可以实现这组接口方法。这样,在外部访问这些组件时,可以不关注组件具体是什么,只需要关心组件提供的接口。例如,在 TypeScript 中定义并实现一个 trait behavior :
|
|
8
|
+
|
|
9
|
+
```ts
|
|
10
|
+
// 定义一个 trait behavior
|
|
11
|
+
interface AddMinus {
|
|
12
|
+
add(a: number, b: number): number
|
|
13
|
+
minus(a: number, b: number): number
|
|
14
|
+
}
|
|
15
|
+
const addMinusTrait = componentSpace.defineTraitBehavior<AddMinus>()
|
|
16
|
+
|
|
17
|
+
// 使用 Chaining API 实现 trait behavior
|
|
18
|
+
const childComponent = componentSpace.define()
|
|
19
|
+
.implement(addMinusTrait, {
|
|
20
|
+
add(a, b) {
|
|
21
|
+
return a + b
|
|
22
|
+
},
|
|
23
|
+
minus(a, b) {
|
|
24
|
+
return a - b
|
|
25
|
+
},
|
|
26
|
+
})
|
|
27
|
+
.defineComponent()
|
|
28
|
+
// 或在 init 中实现 trait behavior
|
|
29
|
+
const childComponent = componentSpace.define()
|
|
30
|
+
.init(function ({ implement }) {
|
|
31
|
+
implement(addMinusTrait, {
|
|
32
|
+
add(a, b) {
|
|
33
|
+
return a + b
|
|
34
|
+
},
|
|
35
|
+
minus(a, b) {
|
|
36
|
+
return a - b
|
|
37
|
+
},
|
|
38
|
+
})
|
|
39
|
+
})
|
|
40
|
+
.defineComponent()
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
在从组件外访问这个组件时,可以使用 trait behavior :
|
|
44
|
+
|
|
45
|
+
```ts
|
|
46
|
+
const myComponent = componentSpace.define()
|
|
47
|
+
.usingComponents({
|
|
48
|
+
child: childComponent,
|
|
49
|
+
})
|
|
50
|
+
.template(compileTemplate(`
|
|
51
|
+
<child id="c" />
|
|
52
|
+
`))
|
|
53
|
+
.lifetime('attached', function () {
|
|
54
|
+
// 获取到子组件对应的节点
|
|
55
|
+
const child = this.shadowRoot.querySelector('#c')!
|
|
56
|
+
// 获得它对应的 addMinusTrait 的实现
|
|
57
|
+
const impl = child.traitBehavior(addMinusTrait)!
|
|
58
|
+
// 调用其中方法
|
|
59
|
+
impl.add(1, 2) === 3 // true
|
|
60
|
+
impl.minus(5, 3) === 2 // true
|
|
61
|
+
})
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
这样,在使用组件时就不需要关心组件具体实现,只需要关心组件提供的 trait behavior ,利于代码解耦。
|
|
65
|
+
|
|
66
|
+
## 含接口转换的 trait behavior
|
|
67
|
+
|
|
68
|
+
trait behavior 本身可以做一些接口转换,使得提供的接口比需要实现的接口更丰富。
|
|
69
|
+
|
|
70
|
+
例如, `addMinusTrait` 提供 `add` 和 `minus` 两个接口方法,但可以只要求实现者实现 `add` 接口方法:
|
|
71
|
+
|
|
72
|
+
```ts
|
|
73
|
+
interface Add {
|
|
74
|
+
add(a: number, b: number): number
|
|
75
|
+
}
|
|
76
|
+
interface AddMinus {
|
|
77
|
+
add(a: number, b: number): number
|
|
78
|
+
minus(a: number, b: number): number
|
|
79
|
+
}
|
|
80
|
+
// 这个 trait behavior 要求实现 add 接口方法,但可以提供 add 和 minus 两个接口方法
|
|
81
|
+
const addMinusTrait = componentSpace.defineTraitBehavior<Add, AddMinus>((impl) => ({
|
|
82
|
+
// 具体而言:
|
|
83
|
+
// 入参中的 impl 是对 interface Add 的实现
|
|
84
|
+
// 这里需要返回对 interface AddMinus 的实现
|
|
85
|
+
add(a: number, b: number): number {
|
|
86
|
+
return impl.add(a, b)
|
|
87
|
+
},
|
|
88
|
+
// 需要额外实现 minus 接口方法
|
|
89
|
+
minus(a: number, b: number): number {
|
|
90
|
+
return impl.add(a, -b)
|
|
91
|
+
},
|
|
92
|
+
}))
|
|
93
|
+
|
|
94
|
+
const childComponent = componentSpace.define()
|
|
95
|
+
.implement(addMinusTrait, {
|
|
96
|
+
// 对于实现者,只需要实现 add 接口方法
|
|
97
|
+
add(a, b) {
|
|
98
|
+
return a + b
|
|
99
|
+
}
|
|
100
|
+
})
|
|
101
|
+
.defineComponent()
|
|
102
|
+
|
|
103
|
+
const myComponent = componentSpace.define()
|
|
104
|
+
.usingComponents({
|
|
105
|
+
child: childComponent,
|
|
106
|
+
})
|
|
107
|
+
.template(compileTemplate(`
|
|
108
|
+
<child id="c" />
|
|
109
|
+
`))
|
|
110
|
+
.lifetime('attached', function () {
|
|
111
|
+
const child = this.shadowRoot.querySelector('#c')!
|
|
112
|
+
const impl = child.traitBehavior(addMinusTrait)!
|
|
113
|
+
// 可以调用 add 和 minus 两个接口
|
|
114
|
+
impl.add(1, 2) === 3 // true
|
|
115
|
+
impl.minus(5, 3) === 2 // true
|
|
116
|
+
})
|
|
117
|
+
```
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
# 外部样式类
|
|
2
|
+
|
|
3
|
+
有时,一个组件的部分样式规则需要由它的使用者来指定。此时可以使用 **外部样式类** 。
|
|
4
|
+
|
|
5
|
+
组件可以指定它自身的一些 class 可以由组件外传递,例如:
|
|
6
|
+
|
|
7
|
+
```js
|
|
8
|
+
// 使用 Definition API 指定外部样式类
|
|
9
|
+
export const childComponent = componentSpace.defineComponent({
|
|
10
|
+
externalClasses: ['my-class'],
|
|
11
|
+
// 在模板的 class 中可以使用外部样式类
|
|
12
|
+
template: compileTemplate(`
|
|
13
|
+
<div class="my-class" />
|
|
14
|
+
`),
|
|
15
|
+
})
|
|
16
|
+
// 或使用 Chaining API 指定外部样式类
|
|
17
|
+
export const childComponent = componentSpace.define()
|
|
18
|
+
.externalClasses(['my-class'])
|
|
19
|
+
.template(compileTemplate(`
|
|
20
|
+
<div id="a" class="my-class" />
|
|
21
|
+
`))
|
|
22
|
+
.registerComponent()
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
使用这个组件时,就可以指定:
|
|
26
|
+
|
|
27
|
+
```js
|
|
28
|
+
export const myComponent = componentSpace.defineComponent({
|
|
29
|
+
using: {
|
|
30
|
+
child: childComponent,
|
|
31
|
+
},
|
|
32
|
+
template: compileTemplate(`
|
|
33
|
+
<child my-class="some-class" />
|
|
34
|
+
`),
|
|
35
|
+
})
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
这样,子组件中的 `<div id="a" />` 就会最终应用 `.some-class` 的样式规则:
|
|
39
|
+
|
|
40
|
+
```css
|
|
41
|
+
.some-class {
|
|
42
|
+
/* ... */
|
|
43
|
+
}
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
即使启用了 [样式隔离](style_isolation.md) ,外部样式类依然可用。
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
# 样式隔离
|
|
2
|
+
|
|
3
|
+
glass-easel 的默认设置中,组件之间的样式是共享的。如果想将一个样式表仅用于一个组件,可以考虑启用 style scope 支持。
|
|
4
|
+
|
|
5
|
+
在 DOM 环境下, style scope 要求样式表预处理时对样式表中的 class 都添加一个前缀,例如:
|
|
6
|
+
|
|
7
|
+
```css
|
|
8
|
+
.my-prefix--header {
|
|
9
|
+
font-size: 1.5em;
|
|
10
|
+
}
|
|
11
|
+
.my-prefix--footer {
|
|
12
|
+
font-size: 0.9em;
|
|
13
|
+
}
|
|
14
|
+
```
|
|
15
|
+
|
|
16
|
+
通过 `glass-easel-stylesheet-compiler` 工具可以为样式表添加固定的前缀,具体用法请参考它的相关文档。
|
|
17
|
+
|
|
18
|
+
添加前缀后,可以注册一个 style scope :
|
|
19
|
+
|
|
20
|
+
```js
|
|
21
|
+
const myStyleScope = componentSpace.styleScopeManager.register('my-prefix')
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
组件定义时,可以指定它使用这个 style scope :
|
|
25
|
+
|
|
26
|
+
```js
|
|
27
|
+
export const myComponent = componentSpace.defineComponent({
|
|
28
|
+
options: {
|
|
29
|
+
styleScope: myStyleScope,
|
|
30
|
+
},
|
|
31
|
+
template: compileTemplate(`
|
|
32
|
+
<div class="header" />
|
|
33
|
+
<div class="footer" />
|
|
34
|
+
`)
|
|
35
|
+
})
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
如果指定了 style scope ,模板中的所有 class 指定的样式将只应用含有前缀的 class 样式规则。
|
|
39
|
+
|
|
40
|
+
若想要同时应用无前缀和含前缀两种 class 样式规则,可以改用 `extraStyleScope` 选项:
|
|
41
|
+
|
|
42
|
+
```js
|
|
43
|
+
export const myComponent = componentSpace.defineComponent({
|
|
44
|
+
options: {
|
|
45
|
+
extraStyleScope: myStyleScope,
|
|
46
|
+
},
|
|
47
|
+
template: compileTemplate(`
|
|
48
|
+
<div class="header" />
|
|
49
|
+
<div class="footer" />
|
|
50
|
+
`)
|
|
51
|
+
})
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
[自定义后端](../advanced/custom_backend.md) 对样式隔离的支持方式略有不同,请参考它的相关文档。
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
# 虚拟组件节点
|
|
2
|
+
|
|
3
|
+
默认情况下,代表组件的节点本身会和普通节点一样接收 class 和 style ,例如:
|
|
4
|
+
|
|
5
|
+
```js
|
|
6
|
+
export const myComponent = componentSpace.defineComponent({
|
|
7
|
+
using: {
|
|
8
|
+
child: childComponent,
|
|
9
|
+
},
|
|
10
|
+
template: compileTemplate(`
|
|
11
|
+
<div class="a" style="color: red" />
|
|
12
|
+
<child class="b" style="color: blue" />
|
|
13
|
+
`)
|
|
14
|
+
})
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
在 DOM 节点树上, `<child>` 节点本身也会生成一个对应的 DOM 节点,使其能直接使用 class 和 style ;但这也使得一些情况下布局难以控制,例如在使用 flex 布局时, `<child>` 节点本身会成为一个 flex 内容项。
|
|
18
|
+
|
|
19
|
+
通过指定组件的 `virtualHost` 选项,可以改变这一行为,使其本身不生成一个对应的 DOM 节点,这样:
|
|
20
|
+
|
|
21
|
+
* flex 布局时,它本身不作为 flex 内容项参与布局;
|
|
22
|
+
* 节点本身的 class 和 style 失效。
|
|
23
|
+
|
|
24
|
+
虽然节点本身的 class 和 style 会失效,但可以将 class 定义为一个 [外部样式类](external_class.md) 、可以将 style 定义为一个属性,这样就可以用上它们,例如:
|
|
25
|
+
|
|
26
|
+
```js
|
|
27
|
+
export const childComponent = componentSpace.defineComponent({
|
|
28
|
+
options: {
|
|
29
|
+
virtualHost: true,
|
|
30
|
+
},
|
|
31
|
+
// 将 class 作为一个外部样式类
|
|
32
|
+
externalClasses: ['class'],
|
|
33
|
+
// 将 style 作为一个属性
|
|
34
|
+
properties: {
|
|
35
|
+
style: String,
|
|
36
|
+
},
|
|
37
|
+
// 将 class 和 style 应用到组件内部的节点上
|
|
38
|
+
template: compileTemplate(`
|
|
39
|
+
<div class="class" style="{{ style }}" />
|
|
40
|
+
`),
|
|
41
|
+
})
|
|
42
|
+
|
|
43
|
+
export const myComponent = componentSpace.defineComponent({
|
|
44
|
+
using: {
|
|
45
|
+
child: childComponent,
|
|
46
|
+
},
|
|
47
|
+
// 同样可以使用 class 和 style
|
|
48
|
+
template: compileTemplate(`
|
|
49
|
+
<child class="b" style="color: blue" />
|
|
50
|
+
`)
|
|
51
|
+
})
|
|
52
|
+
```
|