compelem 0.0.0 → 0.1.1-beta
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/CHANGELOG.md +1 -0
- package/CompElem.d.ts +137 -0
- package/IComponent.d.ts +49 -0
- package/LICENSE +21 -0
- package/README.md +402 -0
- package/decorator/Decorator.d.ts +34 -0
- package/decorator/index.d.ts +32 -0
- package/decorators/computed.d.ts +10 -0
- package/decorators/event.d.ts +26 -0
- package/decorators/prop.d.ts +57 -0
- package/decorators/query.d.ts +26 -0
- package/decorators/state.d.ts +19 -0
- package/decorators/tag.d.ts +6 -0
- package/decorators/watch.d.ts +26 -0
- package/directive/Directive.d.ts +43 -0
- package/directive/index.d.ts +52 -0
- package/directives/Bind.d.ts +1 -0
- package/directives/Classes.d.ts +1 -0
- package/directives/ForEach.d.ts +2 -0
- package/directives/IfElse.d.ts +2 -0
- package/directives/IfTrue.d.ts +2 -0
- package/directives/Model.d.ts +5 -0
- package/directives/Show.d.ts +1 -0
- package/directives/Slot.d.ts +2 -0
- package/directives/Styles.d.ts +1 -0
- package/directives/Sync.d.ts +1 -0
- package/directives/When.d.ts +2 -0
- package/events/event.d.ts +13 -0
- package/events/extends.d.ts +2 -0
- package/index.d.ts +26 -0
- package/index.js +3119 -0
- package/package.json +51 -12
- package/reactive.d.ts +39 -0
- package/render/RenderContext.d.ts +37 -0
- package/render/render.d.ts +69 -0
- package/types.d.ts +41 -0
- package/utils.d.ts +5 -0
package/CHANGELOG.md
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
# Changelog
|
package/CompElem.d.ts
ADDED
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
import { Directive } from "./directive/Directive";
|
|
2
|
+
import { IComponent } from "./IComponent";
|
|
3
|
+
import { Template } from "./render/render";
|
|
4
|
+
import { IRenderContext } from "./render/RenderContext";
|
|
5
|
+
import { TmplFn } from "./types";
|
|
6
|
+
declare const CompElem_base: {
|
|
7
|
+
new (...args: any[]): {
|
|
8
|
+
[x: string]: any;
|
|
9
|
+
render(...args: any): void | Template | Template[] | ((...args: any[]) => (Template | Template[]));
|
|
10
|
+
__expPos: Record<string, import("./types").ExpPos>;
|
|
11
|
+
__expPosMap: Record<string, Record<string, import("./types").ExpPos> | null>;
|
|
12
|
+
__directives: Record<string, Directive>;
|
|
13
|
+
slotComponent: CompElem;
|
|
14
|
+
renderComponent: CompElem;
|
|
15
|
+
renderContext(...args: any): [NodeListOf<ChildNode>, Record<string, import("./types").ExpPos>, Record<string, Record<string, import("./types").ExpPos> | null>];
|
|
16
|
+
updateContext(...args: any): void;
|
|
17
|
+
__updateExpPos(tmpl: Template, _expPos: Record<string, import("./types").ExpPos>): void;
|
|
18
|
+
};
|
|
19
|
+
} & {
|
|
20
|
+
new (): HTMLElement;
|
|
21
|
+
prototype: HTMLElement;
|
|
22
|
+
};
|
|
23
|
+
/**
|
|
24
|
+
* CompElem基类,意为组件元素。提供了基本内置属性及生命周期等必备接口
|
|
25
|
+
* 每个组件都需要继承自该类
|
|
26
|
+
*
|
|
27
|
+
* @author holyhigh2
|
|
28
|
+
*/
|
|
29
|
+
export declare abstract class CompElem extends CompElem_base implements IComponent {
|
|
30
|
+
#private;
|
|
31
|
+
static __l_globalRule: HTMLStyleElement;
|
|
32
|
+
__events: Record<string, Array<Node | ((e: Event) => void)>[]>;
|
|
33
|
+
get reactiveData(): Record<string, any>;
|
|
34
|
+
get attrs(): Record<string, string>;
|
|
35
|
+
get props(): Record<string, any>;
|
|
36
|
+
get renderRoot(): HTMLElement;
|
|
37
|
+
get renderRoots(): HTMLElement[];
|
|
38
|
+
get parentComponent(): HTMLElement | null;
|
|
39
|
+
get slotHooks(): Record<string, (...args: any[]) => Template>;
|
|
40
|
+
get styles(): CSSStyleSheet[];
|
|
41
|
+
get isMounted(): boolean;
|
|
42
|
+
get slots(): Record<string, Array<Node>>;
|
|
43
|
+
/**
|
|
44
|
+
* 是否自动插入插槽,如果需要控制插槽类型时,可以设置为false
|
|
45
|
+
*/
|
|
46
|
+
static get autoSlot(): boolean;
|
|
47
|
+
/**
|
|
48
|
+
* 组件样式,CSSStyleSheet可动态变更
|
|
49
|
+
*/
|
|
50
|
+
static get styles(): Array<string | CSSStyleSheet>;
|
|
51
|
+
static get globalStyles(): Array<string>;
|
|
52
|
+
get css(): string;
|
|
53
|
+
constructor(...args: any[]);
|
|
54
|
+
connectedCallback(): void;
|
|
55
|
+
disconnectedCallback(): void;
|
|
56
|
+
__init(): void;
|
|
57
|
+
/**
|
|
58
|
+
* 初始化属性及状态,该回调内可以访问props和state
|
|
59
|
+
* 此时组件dom并未构建,但已有parent 属性,没有root属性
|
|
60
|
+
*/
|
|
61
|
+
connected(): void;
|
|
62
|
+
/**
|
|
63
|
+
* props初始化完成回调
|
|
64
|
+
*/
|
|
65
|
+
propsReady(): void;
|
|
66
|
+
/**
|
|
67
|
+
* 每次更新时调用
|
|
68
|
+
*/
|
|
69
|
+
abstract render(): Template;
|
|
70
|
+
/**
|
|
71
|
+
* dom渲染完毕后调用,该回调内可以query注解初始化完成
|
|
72
|
+
*/
|
|
73
|
+
mounted(): void;
|
|
74
|
+
slotchange(slot: HTMLSlotElement, name: string): void;
|
|
75
|
+
/**
|
|
76
|
+
* 是否需要更新,可获取变更属性
|
|
77
|
+
* 返回true时更新
|
|
78
|
+
*/
|
|
79
|
+
shouldUpdate(changed: Record<string, any>): boolean;
|
|
80
|
+
/**
|
|
81
|
+
* 1. 调用render
|
|
82
|
+
* 2. 更新@query/all
|
|
83
|
+
* 3. 更新ref
|
|
84
|
+
* 4. 更新prop到attr的映射
|
|
85
|
+
* @param changed
|
|
86
|
+
*/
|
|
87
|
+
updated(changed: Record<string, any>): void;
|
|
88
|
+
/**
|
|
89
|
+
* 抛出自定义事件
|
|
90
|
+
* @param evName 事件名称
|
|
91
|
+
* @param args 自定义参数
|
|
92
|
+
*/
|
|
93
|
+
emit(evName: string, arg?: Record<string, any>, options?: {
|
|
94
|
+
event?: Event;
|
|
95
|
+
bubbles?: boolean;
|
|
96
|
+
composed?: boolean;
|
|
97
|
+
}): void;
|
|
98
|
+
/**
|
|
99
|
+
* 在root上绑定事件
|
|
100
|
+
* @param evName
|
|
101
|
+
* @param hook
|
|
102
|
+
*/
|
|
103
|
+
on(evName: string, hook: (e: Event) => void): void;
|
|
104
|
+
/**
|
|
105
|
+
* 下一帧执行
|
|
106
|
+
* @param cbk
|
|
107
|
+
*/
|
|
108
|
+
nextTick(cbk: () => void): void;
|
|
109
|
+
/**
|
|
110
|
+
* 强制更新一次视图
|
|
111
|
+
*/
|
|
112
|
+
forceUpdate(): void;
|
|
113
|
+
/**
|
|
114
|
+
* 由监控变量调用
|
|
115
|
+
* @param stateKey
|
|
116
|
+
* @param ov
|
|
117
|
+
* @param rootStateKey 如果是对象内部属性变更,会返回根属性名
|
|
118
|
+
* @returns
|
|
119
|
+
*/
|
|
120
|
+
_notify(ov: any, chain: string[]): void;
|
|
121
|
+
/**
|
|
122
|
+
* @deprecated
|
|
123
|
+
*/
|
|
124
|
+
_setParentProps(props: Record<string, any>, attrs?: Record<string, any>): void;
|
|
125
|
+
_updateProps(props: Record<string, any>): void;
|
|
126
|
+
_initProps(props: Record<string, any>, attrs?: Record<string, any>): void;
|
|
127
|
+
/**
|
|
128
|
+
* 绑定slot标签,render时调用
|
|
129
|
+
*/
|
|
130
|
+
_bindSlot(slot: HTMLSlotElement, name: string, props: Record<string, any>): void;
|
|
131
|
+
_bindSlotHook(name: string, hook: (...args: any[]) => Template): void;
|
|
132
|
+
_updateSlot(name: string, propName?: string, value?: any): void;
|
|
133
|
+
_asyncDirectives: WeakMap<TmplFn, IRenderContext>;
|
|
134
|
+
renderAsync(cbk: TmplFn, ...args: any[]): void;
|
|
135
|
+
_regDeps(varPath: string, renderContext: CompElem | Directive): void;
|
|
136
|
+
}
|
|
137
|
+
export {};
|
package/IComponent.d.ts
ADDED
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import { Template } from "./render/render";
|
|
2
|
+
/**
|
|
3
|
+
* 组件接口
|
|
4
|
+
* 定义组件属性、生命周期及方法
|
|
5
|
+
* @author holyhigh2
|
|
6
|
+
*/
|
|
7
|
+
export interface IComponent {
|
|
8
|
+
get attrs(): Record<string, string>;
|
|
9
|
+
get props(): Record<string, any>;
|
|
10
|
+
get renderRoot(): HTMLElement;
|
|
11
|
+
get renderRoots(): HTMLElement[];
|
|
12
|
+
get parentComponent(): HTMLElement | null;
|
|
13
|
+
get slots(): Record<string, Array<Node>>;
|
|
14
|
+
get slotHooks(): Record<string, (...args: any[]) => Template>;
|
|
15
|
+
get styles(): CSSStyleSheet[];
|
|
16
|
+
get isMounted(): boolean;
|
|
17
|
+
connected(): void;
|
|
18
|
+
propsReady(): void;
|
|
19
|
+
render(): Template;
|
|
20
|
+
mounted(): void;
|
|
21
|
+
shouldUpdate(changed: Record<string, any>): boolean;
|
|
22
|
+
updated(changed: Record<string, any>): void;
|
|
23
|
+
slotchange(slot: HTMLSlotElement, name: string): void;
|
|
24
|
+
/**
|
|
25
|
+
* 抛出自定义事件
|
|
26
|
+
* @param evName 事件名称
|
|
27
|
+
* @param args 自定义参数
|
|
28
|
+
*/
|
|
29
|
+
emit(evName: string, arg: Record<string, any>, options?: {
|
|
30
|
+
event?: Event;
|
|
31
|
+
bubbles?: boolean;
|
|
32
|
+
composed?: boolean;
|
|
33
|
+
}): void;
|
|
34
|
+
/**
|
|
35
|
+
* 在root上绑定事件
|
|
36
|
+
* @param evName
|
|
37
|
+
* @param hook
|
|
38
|
+
*/
|
|
39
|
+
on(evName: string, hook: (e: Event) => void): void;
|
|
40
|
+
/**
|
|
41
|
+
* 下一帧执行
|
|
42
|
+
* @param cbk
|
|
43
|
+
*/
|
|
44
|
+
nextTick(cbk: () => void): void;
|
|
45
|
+
/**
|
|
46
|
+
* 强制更新一次视图
|
|
47
|
+
*/
|
|
48
|
+
forceUpdate(): void;
|
|
49
|
+
}
|
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2024 holyhigh2
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,402 @@
|
|
|
1
|
+
# CompElem
|
|
2
|
+
|
|
3
|
+
一个现代化、响应式、快速、轻量的 WebComponent 开发库。为开发者提供丰富、灵活、可扩展的声明式接口
|
|
4
|
+
|
|
5
|
+
## 概览
|
|
6
|
+
|
|
7
|
+
CompElem 基于 Class 进行构建,该模型允许开发者使用装饰器进行声明式编码,核心特性包括:
|
|
8
|
+
|
|
9
|
+
- 类 JSX 的原生模板系统
|
|
10
|
+
- 丰富的装饰器及指令
|
|
11
|
+
- 可选的生命周期
|
|
12
|
+
- 原生插槽系统
|
|
13
|
+
- 响应式域样式
|
|
14
|
+
- ...
|
|
15
|
+
|
|
16
|
+
创建一个 WebComponent 总会从声明一个组件元素(CompElem 子类)开始
|
|
17
|
+
|
|
18
|
+
```ts
|
|
19
|
+
const Slogan = ["complete", "componentize", "compact", "companion"];
|
|
20
|
+
@tag("page-test")
|
|
21
|
+
export class PageTest extends CompElem {
|
|
22
|
+
//////////////////////////////////// props
|
|
23
|
+
@prop arg: any;
|
|
24
|
+
|
|
25
|
+
@state colorR = (Math.random() * 255) % 255 >> 0;
|
|
26
|
+
@state colorG = (Math.random() * 255) % 255 >> 0;
|
|
27
|
+
@state colorB = (Math.random() * 255) % 255 >> 0;
|
|
28
|
+
@state rotation = 0;
|
|
29
|
+
|
|
30
|
+
//////////////////////////////////// computed
|
|
31
|
+
@computed
|
|
32
|
+
get color() {
|
|
33
|
+
return `linear-gradient(90deg,rgb(${this.colorR},${this.colorG},${
|
|
34
|
+
this.colorB
|
|
35
|
+
}), rgb(${255 - this.colorR},${255 - this.colorG},${255 - this.colorB}));`;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
//////////////////////////////////// watch
|
|
39
|
+
@watch("rotation")
|
|
40
|
+
function(nv: number) {
|
|
41
|
+
console.log(nv);
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
//////////////////////////////////// styles
|
|
45
|
+
//静态样式
|
|
46
|
+
static get styles(): Array<string | CSSStyleSheet> {
|
|
47
|
+
return [
|
|
48
|
+
`:host{
|
|
49
|
+
font-size:16px;
|
|
50
|
+
}...`,
|
|
51
|
+
];
|
|
52
|
+
}
|
|
53
|
+
//动态样式
|
|
54
|
+
get css() {
|
|
55
|
+
return `h2,p,i,h3{
|
|
56
|
+
background-image:${this.color}
|
|
57
|
+
filter:hue-rotate(${this.rotation}deg)
|
|
58
|
+
}`;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
@query('i[name="text"]')
|
|
62
|
+
text: HTMLElement;
|
|
63
|
+
sloganIndex = 0;
|
|
64
|
+
|
|
65
|
+
//////////////////////////////////// lifecycles
|
|
66
|
+
mounted(): void {
|
|
67
|
+
setInterval(() => {
|
|
68
|
+
this.rotation += 1;
|
|
69
|
+
}, 24);
|
|
70
|
+
|
|
71
|
+
setInterval(() => {
|
|
72
|
+
this.text.classList.add("hide");
|
|
73
|
+
setTimeout(() => {
|
|
74
|
+
this.text.innerHTML = Slogan[this.sloganIndex % 4];
|
|
75
|
+
this.sloganIndex++;
|
|
76
|
+
this.text.classList.remove("hide");
|
|
77
|
+
}, 500);
|
|
78
|
+
}, 5000);
|
|
79
|
+
}
|
|
80
|
+
render(): Template {
|
|
81
|
+
return html`<div>
|
|
82
|
+
<i>Welcome to</i>
|
|
83
|
+
<br />
|
|
84
|
+
<h2>CompElem</h2>
|
|
85
|
+
<br />
|
|
86
|
+
<i>A modern, reactive, fast and lightweight library</i>
|
|
87
|
+
<br />
|
|
88
|
+
<i>for building</i>
|
|
89
|
+
<h3>Web Components</h3>
|
|
90
|
+
<p><c-element> <i name="text">...</i> </c-element></p>
|
|
91
|
+
${this.arg}
|
|
92
|
+
</div>`;
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
而后即可在 HTML 中直接使用,与使用一个原生元素如 DIV 没有任何区别
|
|
98
|
+
|
|
99
|
+
```html
|
|
100
|
+
<body>
|
|
101
|
+
<page-test arg="args..."></page-test>
|
|
102
|
+
</body>
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
当然,也可以直接嵌入其他 UI 库中只要引入编译后的 js 即可
|
|
106
|
+
|
|
107
|
+
## APIs
|
|
108
|
+
|
|
109
|
+
- ### 视图模板
|
|
110
|
+
使用`render()`函数定义组件视图模板
|
|
111
|
+
```ts
|
|
112
|
+
render(): Template{
|
|
113
|
+
return html`<div>Hello CompElem</div>`
|
|
114
|
+
}
|
|
115
|
+
```
|
|
116
|
+
- ### 视图模板-属性表达式
|
|
117
|
+
|
|
118
|
+
通过再视图模板中插入表达式可以实现动态视图,表达式通过在不同位置使用分为不同类型见(#### 指令类型)。其中属性表达式根据前缀分为
|
|
119
|
+
|
|
120
|
+
| 前缀 | 描述 | 示例 |
|
|
121
|
+
| ---- | ------------------------------------------------------------- | -------------------------------------- |
|
|
122
|
+
| @ | 事件属性,可用于任何标签 | `<div @click="${this.onClick}">` |
|
|
123
|
+
| . | 参数属性,仅用于给组件标签传递参数 | `<l-input .value="${this.text}">` |
|
|
124
|
+
| ? | 可选属性,用于 disabled/readonly 等 toggle 类属性 | `<input ?disabled="${this.disabled}">` |
|
|
125
|
+
| \* | 引用属性,表达式求值后才会设置该属性。常用于 SVG 相关属性设置 | `<circle *r="${this.r}">` |
|
|
126
|
+
|
|
127
|
+
> 引用属性可通过属性参数进行格式转换,如
|
|
128
|
+
|
|
129
|
+
```ts
|
|
130
|
+
render(): Template{
|
|
131
|
+
return html`<svg *view-box:camel="">...</svg>`// <svg viewBox="">
|
|
132
|
+
}
|
|
133
|
+
```
|
|
134
|
+
|
|
135
|
+
支持格式包括:
|
|
136
|
+
|
|
137
|
+
- camel 驼峰式
|
|
138
|
+
- kebab 短横线
|
|
139
|
+
- snake 下划线
|
|
140
|
+
|
|
141
|
+
- ### 样式
|
|
142
|
+
使用静态函数定义组件样式或全局样式(如弹框)
|
|
143
|
+
```ts
|
|
144
|
+
static get styles(): Array<string | CSSStyleSheet> {
|
|
145
|
+
return [];
|
|
146
|
+
}
|
|
147
|
+
static get globalStyles(): Array<string> {
|
|
148
|
+
return [];
|
|
149
|
+
}
|
|
150
|
+
```
|
|
151
|
+
对于需要动态控制 host 元素样式可以使用组件实例 getter
|
|
152
|
+
```ts
|
|
153
|
+
get css():string{
|
|
154
|
+
return `:host{
|
|
155
|
+
${this.border?'border: 1px solid rgb(var(--l-color-border-secondary)); ':''}
|
|
156
|
+
}`
|
|
157
|
+
}
|
|
158
|
+
```
|
|
159
|
+
- ### 属性
|
|
160
|
+
|
|
161
|
+
属性是由组件外部提供参数的响应变量,可通过`@prop`注解定义
|
|
162
|
+
|
|
163
|
+
```ts
|
|
164
|
+
@prop({ type: Boolean }) loading = false;//显式定义属性类型
|
|
165
|
+
@prop round = true;//通过默认值自动推断属性类型
|
|
166
|
+
@prop({ type: [Boolean,String] }) round = true;//多种类型使用数组定义
|
|
167
|
+
@prop({ type: Array }) datalist: Array<string>;//没有默认值必须显式指定属性类型
|
|
168
|
+
@prop({ type: [String, Number], sync: true }) //通过get/set设置属性
|
|
169
|
+
get value() {
|
|
170
|
+
return this.__innerValue ?? ''
|
|
171
|
+
}
|
|
172
|
+
set value(v: any) {
|
|
173
|
+
this.__innerValue = v
|
|
174
|
+
if (isNil(v)) {
|
|
175
|
+
this.__innerValue = '';
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
```
|
|
179
|
+
|
|
180
|
+
属性可以在组件内修改但默认不会同步父组件,除非显式指定`sync`或自行 emit update 事件
|
|
181
|
+
全部注解参数见 `PropOption`
|
|
182
|
+
|
|
183
|
+
- ### 状态
|
|
184
|
+
状态是仅由组件内部初始化的响应变量,可通过`@state`注解定义
|
|
185
|
+
```ts
|
|
186
|
+
@state hasLeft = false;//定义状态
|
|
187
|
+
@state({//自定义变化判断
|
|
188
|
+
hasChanged(nv: any[], ov: any[]) {
|
|
189
|
+
return isEqual(nv , ov)
|
|
190
|
+
}
|
|
191
|
+
}) private nodes: Array<Record<string, any>>;
|
|
192
|
+
```
|
|
193
|
+
状态仅能在组件内修改
|
|
194
|
+
全部注解参数见 `StateOption`
|
|
195
|
+
- ### 状态监视
|
|
196
|
+
|
|
197
|
+
使用`@watch`注解可以对属性/状态进行变化监视
|
|
198
|
+
|
|
199
|
+
```ts
|
|
200
|
+
@prop width = "auto";
|
|
201
|
+
|
|
202
|
+
@watch("width", { immediate: true })
|
|
203
|
+
watchWidth(nv: string, ov: string, sourceName: string) {
|
|
204
|
+
this.style.width = nv;
|
|
205
|
+
}
|
|
206
|
+
```
|
|
207
|
+
|
|
208
|
+
对于同类属性共享处理逻辑的监视,可以批量处理
|
|
209
|
+
|
|
210
|
+
```ts
|
|
211
|
+
@watch(['height', 'minHeight', 'maxHeight'], { immediate: true })
|
|
212
|
+
watchHeight(nv: string, ov: string, sourceName: string) {
|
|
213
|
+
this.style[srcName] = nv;
|
|
214
|
+
}
|
|
215
|
+
```
|
|
216
|
+
|
|
217
|
+
- ### 计算状态
|
|
218
|
+
计算状态会缓存 return 结果,只有当内部使用的任意属性/状态发生变化时才会重新计算
|
|
219
|
+
使用`@computed`注解的 Getter,如
|
|
220
|
+
```ts
|
|
221
|
+
@computed
|
|
222
|
+
get hasHeader() {
|
|
223
|
+
return !isEmpty(this.slots.header) || !!this.header
|
|
224
|
+
}
|
|
225
|
+
```
|
|
226
|
+
- ### 节点引用
|
|
227
|
+
使用`@query/all`注解及`ref`属性
|
|
228
|
+
```ts
|
|
229
|
+
//query
|
|
230
|
+
@query('l-icon')
|
|
231
|
+
iconEl: HTMLElement
|
|
232
|
+
//ref
|
|
233
|
+
refNode: HTMLElement
|
|
234
|
+
```
|
|
235
|
+
```ts
|
|
236
|
+
divRef = createRef<HTMLDivElement>();
|
|
237
|
+
//视图片段
|
|
238
|
+
return html` <l-icon></l-icon>
|
|
239
|
+
<div ref="${divRef}"></div>`;
|
|
240
|
+
```
|
|
241
|
+
- ### 内置属性及函数
|
|
242
|
+
- `readonly` parent 父组件引用,可能为空
|
|
243
|
+
- `readonly` el/els 根元素/根元素列表
|
|
244
|
+
- `readonly` slots 插槽元素
|
|
245
|
+
- `readonly` slotHooks 动态插槽钩子
|
|
246
|
+
- `readonly` styles 组件样式对象列表
|
|
247
|
+
- `readonly` attrs 组件特性
|
|
248
|
+
- `readonly` props 组件属性
|
|
249
|
+
- slotComponent 所在插槽组件
|
|
250
|
+
- on()
|
|
251
|
+
- emit()
|
|
252
|
+
- nextTick()
|
|
253
|
+
- forceUpdate()
|
|
254
|
+
|
|
255
|
+
## 组件渲染流程
|
|
256
|
+
|
|
257
|
+
CompElem 组件既可以在 CompElem 环境内调用,也可以直接在原生环境调用,区别只是原生环境无法像组件传`递类型参数`。流程如下:
|
|
258
|
+
|
|
259
|
+
> 创建流程
|
|
260
|
+
|
|
261
|
+
| 功能 | | 生命周期 |
|
|
262
|
+
| ------------------------------------------------------------ | --- | ----------- |
|
|
263
|
+
| 1. 创建组件实例,完成类属性默认值设置(prop/state/...) | | |
|
|
264
|
+
| 2. 初始化类全局样式(仅一次)及 实例样式(产生 styles 数组) | | |
|
|
265
|
+
| 3. 创建 shadowRoot 并挂载组件样式 | | constructor |
|
|
266
|
+
| 4. 绑定 parent | | connected |
|
|
267
|
+
| 5. 获取 this.attribute 及 parentProps 进行验证及初始化 props | | propsReady |
|
|
268
|
+
| 6. 注入 link 外部样式表 | | |
|
|
269
|
+
| 7. 渲染 render 及依赖绑定 | | render |
|
|
270
|
+
| 8. 绑定 el 及 els | | |
|
|
271
|
+
| 9. 执行 ref | | |
|
|
272
|
+
| 10. 执行 @query 注解 | | |
|
|
273
|
+
| 11. 执行 @watch(immediate) 注解 | | |
|
|
274
|
+
| 12. 执行 @event 注解 | | mounted |
|
|
275
|
+
| 13. 执行 slot filter / 动态 slot | | slotchange |
|
|
276
|
+
|
|
277
|
+
> 更新流程【普通】
|
|
278
|
+
|
|
279
|
+
| 功能 | 生命周期 |
|
|
280
|
+
| ------------------------------ | ------------ |
|
|
281
|
+
| 1. 父组件 props 变更【或】 | propsReady |
|
|
282
|
+
| 1. 子组件 state 变更【或】 | |
|
|
283
|
+
| 2. 执行@watch 注解 | |
|
|
284
|
+
| 3. 合并变更内容并判断是否更新 | shouldUpdate |
|
|
285
|
+
| 4. 更新依赖域指令(非 render) | |
|
|
286
|
+
| 5. 更新动态 slot | |
|
|
287
|
+
| 6. 执行 ref | |
|
|
288
|
+
| 7. 执行@query 注解 | update |
|
|
289
|
+
|
|
290
|
+
> 更新流程【强制】
|
|
291
|
+
|
|
292
|
+
| 功能 | 生命周期 |
|
|
293
|
+
| ------------------ | -------- |
|
|
294
|
+
| 1. forceUpdate | |
|
|
295
|
+
| 2. 渲染 render | render |
|
|
296
|
+
| 3. 执行@query 注解 | update |
|
|
297
|
+
|
|
298
|
+
## 插槽 Slot
|
|
299
|
+
|
|
300
|
+
#### 定义插槽
|
|
301
|
+
|
|
302
|
+
使用原生 `<slot></slot>` 标签来嵌入插槽,可以通过`node-filter`属性过滤插槽内容
|
|
303
|
+
|
|
304
|
+
```html
|
|
305
|
+
<slot
|
|
306
|
+
.node-filter="${{
|
|
307
|
+
type: [HTMLElement, CompElem],
|
|
308
|
+
maxCount:1
|
|
309
|
+
}}"
|
|
310
|
+
></slot>
|
|
311
|
+
<!-- 或使用函数精细控制 -->
|
|
312
|
+
<slot .node-filter="${(nodes:Node[])=>Node[]}"></slot>
|
|
313
|
+
```
|
|
314
|
+
|
|
315
|
+
#### 插入节点(静态)
|
|
316
|
+
|
|
317
|
+
```html
|
|
318
|
+
<l-tooltip>
|
|
319
|
+
<l-button>默认插槽内容</l-button>
|
|
320
|
+
<div slot="content">命名插槽内容</div>
|
|
321
|
+
</l-tooltip>
|
|
322
|
+
```
|
|
323
|
+
|
|
324
|
+
#### 插入节点(动态)
|
|
325
|
+
|
|
326
|
+
动态内容插入仅可在 CompElem 组件中编码,可以通过组件注入参数动态生成插槽内容
|
|
327
|
+
|
|
328
|
+
```ts
|
|
329
|
+
//仅可用于CompElem组件中
|
|
330
|
+
return html` <l-tooltip>
|
|
331
|
+
//动态内容通过slot指令定义 ${slot(
|
|
332
|
+
(args: Record<string, any>) => html`
|
|
333
|
+
<div>我是动态内容-${args.data.id}</div>
|
|
334
|
+
`,
|
|
335
|
+
"content"
|
|
336
|
+
)}
|
|
337
|
+
</l-tooltip>`;
|
|
338
|
+
```
|
|
339
|
+
|
|
340
|
+
在`slot`标签上注入参数
|
|
341
|
+
|
|
342
|
+
```html
|
|
343
|
+
<slot .data="${this.row}"></slot>
|
|
344
|
+
```
|
|
345
|
+
|
|
346
|
+
**_注意_**,动态插槽必须关闭自动插槽,否则无效
|
|
347
|
+
|
|
348
|
+
```ts
|
|
349
|
+
static get autoSlot() {
|
|
350
|
+
return false;
|
|
351
|
+
}
|
|
352
|
+
```
|
|
353
|
+
|
|
354
|
+
## 指令 Directive
|
|
355
|
+
|
|
356
|
+
指令用于分支/循环/动态插槽等结构及隐藏显示等
|
|
357
|
+
|
|
358
|
+
#### 指令类型
|
|
359
|
+
|
|
360
|
+
不同的指令类型限制了指令仅能用于对应的插入点
|
|
361
|
+
|指令|插入位置|描述|示例|
|
|
362
|
+
|-------|-------|-------|-------|
|
|
363
|
+
|ATTR|特性|可用于任何特性值之中,仅能插入一个|`attr="${xxx}"`|
|
|
364
|
+
|PROP|属性|可用于任何属性值之中,必须是组件标签,仅能插入一个|`.value="${xxx}"`|
|
|
365
|
+
|TEXT|文本|标签体内,可插入多个|`<div>${xx1}${xx2}${...}</div>`|
|
|
366
|
+
|CLASS|样式类|用于 class 属性值中,仅能插入一个|`class="a ${b}"`|
|
|
367
|
+
|STYLE|样式规则|用于 style 属性值中,仅能插入一个|`style="a:1;${b}"`|
|
|
368
|
+
|SLOT|插槽|与 TEXT 类似,但标签必须是组件||
|
|
369
|
+
|TAG|标签|直接插入在节点标签上|`<div a="b" ${show(..)}>`|
|
|
370
|
+
|
|
371
|
+
#### 内置指令
|
|
372
|
+
|
|
373
|
+
| 指令 | 类型 | 描述 | 示例 |
|
|
374
|
+
| ------- | --------- | ----------------------------------------------------------- | ------------------------------------------------------ |
|
|
375
|
+
| bind | TAG | 绑定属性/特性到标签上,根据标签类型及组件 prop 定义自动判断 | `<div a="b" ${bind(obj)}>` |
|
|
376
|
+
| show | TAG | 隐藏/显示标签(基于 display) | `<div a="b" ${show(visible)}>` |
|
|
377
|
+
| model | TAG | 双向绑定 | `<div a="b" ${model(xx)}>` |
|
|
378
|
+
| classes | CLASS | 绑定样式类属性,支持对象/数组/字符串。可以和静态字符混用 | `<div class="otherClass ${classes(obj)}>"` |
|
|
379
|
+
| styles | STYLE | 绑定样式规则属性,支持对象/字符串。可以和静态字符混用 | `<div style="a:b;${styles(obj)}>"` |
|
|
380
|
+
| forEach | TEXT/SLOT | 输出循环结构 | `...>${forEach(ary,(item)=>html`...`)}<...` |
|
|
381
|
+
| ifTrue | TEXT/SLOT | 当条件为 true 时输出模板内容 | `...>${ifTrue(condition,()=>html`...`)}<...` |
|
|
382
|
+
| ifElse | TEXT/SLOT | 当条件为 true/false 时输出对应模板内容 | ` ...>${ifElse(condition,()=>html``,()=>html``)}<... ` |
|
|
383
|
+
| when | TEXT/SLOT | 多条件分支,支持 switch/ifelse 两种模式 | ` ...>${when(condition,{c1:()=>html``,c2:...})}<... ` |
|
|
384
|
+
| slot | SLOT | 动态插槽 | ` ...>${slot((args) => html``)}<... ` |
|
|
385
|
+
|
|
386
|
+
## 装饰器 Decorator
|
|
387
|
+
|
|
388
|
+
- @state 定义组件内状态属性。可选参数{prop},可指定 propName 初始化值
|
|
389
|
+
- @prop 定义父组件参数,默认不可修改。可选参数{type,required,sync,getter,setter}
|
|
390
|
+
> 设置 getter/setter 后,该属性的`@watch` 将会失效
|
|
391
|
+
- @query/queryAll 定义 CssSelector 查询结果
|
|
392
|
+
- @tag 自定义组件的标签名
|
|
393
|
+
- @event 定义全局事件
|
|
394
|
+
- @watch 监控 state/prop 变更
|
|
395
|
+
|
|
396
|
+
## 事件
|
|
397
|
+
|
|
398
|
+
事件分为三类
|
|
399
|
+
|
|
400
|
+
1. 原生事件 —— `<div @click="..."`,监听器回调参数返回原生事件对象
|
|
401
|
+
2. 组件自定义事件 —— `<l-select @change="..."`,监听器回调参数返回`CustomEvent`事件对象
|
|
402
|
+
3. 扩展原生事件 —— `<div @resize="..."`,监听器回调参数返回`CustomEvent`事件对象
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import { CompElem } from "../CompElem";
|
|
2
|
+
export declare enum DecoratorType {
|
|
3
|
+
CLASS = "class",
|
|
4
|
+
FIELD = "field",
|
|
5
|
+
METHOD = "method"
|
|
6
|
+
}
|
|
7
|
+
/**
|
|
8
|
+
* 用于构造装饰器
|
|
9
|
+
* @author holyhigh2
|
|
10
|
+
*/
|
|
11
|
+
export declare abstract class Decorator {
|
|
12
|
+
/**
|
|
13
|
+
* 装饰器使用范围,超出范围会报错
|
|
14
|
+
*/
|
|
15
|
+
abstract get targets(): Array<DecoratorType>;
|
|
16
|
+
/**
|
|
17
|
+
* 构造会传递自定义参数
|
|
18
|
+
* @param args 自定义参数
|
|
19
|
+
*/
|
|
20
|
+
/**
|
|
21
|
+
* 返回用于识别唯一实例的key,比如@watch(a.b.c)中的变量路径就会作为唯一key
|
|
22
|
+
* @param args
|
|
23
|
+
*/
|
|
24
|
+
abstract created(component: CompElem, ...args: any[]): any;
|
|
25
|
+
/**
|
|
26
|
+
* 执行时机与组件一致
|
|
27
|
+
* @param component 组件实例
|
|
28
|
+
* @param setReactive 为实例设置响应属性,注意,仅是设置到了instance.reactiveData中并非this.key。如需实现this访问,可自行定义组件的properties
|
|
29
|
+
* @param args 装饰器函数参数
|
|
30
|
+
*/
|
|
31
|
+
abstract propsReady(component: CompElem, setReactive: (key: string, value: any) => any, ...args: any[]): any;
|
|
32
|
+
abstract mounted(component: CompElem, setReactive: (key: string, value: any) => any, ...args: any[]): any;
|
|
33
|
+
abstract updated(component: CompElem, changed: Record<string, any>): any;
|
|
34
|
+
}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { Constructor } from './../types';
|
|
2
|
+
/*************************************************************
|
|
3
|
+
* 装饰器
|
|
4
|
+
* @author holyhigh2
|
|
5
|
+
*************************************************************/
|
|
6
|
+
import { CompElem } from "../CompElem";
|
|
7
|
+
import { Decorator } from "./Decorator";
|
|
8
|
+
export declare const GetKeyFnName = "getKey";
|
|
9
|
+
export declare const DecoratorsKey = "__decorators";
|
|
10
|
+
/**
|
|
11
|
+
* 装饰器包装类
|
|
12
|
+
* 用于框架内部,表示class上的一个装饰器属性定义
|
|
13
|
+
* 该定义在实例初始化时会产生装饰器实例属性
|
|
14
|
+
*/
|
|
15
|
+
export declare class DecoratorWrapper {
|
|
16
|
+
args: any[];
|
|
17
|
+
metadata: any[];
|
|
18
|
+
decoratorClass: Constructor<Decorator>;
|
|
19
|
+
instanceMap: WeakMap<CompElem, Decorator>;
|
|
20
|
+
key?: string;
|
|
21
|
+
constructor(args: any[], metadata: any[], decoratorClass: Constructor<Decorator>);
|
|
22
|
+
create(comp: CompElem): void;
|
|
23
|
+
propsReady(comp: CompElem, setReactive: (key: string, value: any) => any): void;
|
|
24
|
+
mounted(comp: CompElem, setReactive: (key: string, value: any) => any): void;
|
|
25
|
+
updated(comp: CompElem, changed: Record<string, any>): void;
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* 该函数用于创建一个装饰器
|
|
29
|
+
* @param decoClass 装饰器构造
|
|
30
|
+
* @returns 装饰器函数
|
|
31
|
+
*/
|
|
32
|
+
export declare function decorator<T extends Array<any>>(decoClass: Constructor<Decorator>): (...args: T) => (...metadata: any[]) => void;
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 定义计算属性
|
|
3
|
+
* 计算属性会自动跟踪get函数内的state/prop,并在变动时自动变更
|
|
4
|
+
* 只能应用在一个非静态get属性上
|
|
5
|
+
* @param source 变量名(数组),支持访问链
|
|
6
|
+
* @param immediate 立即执行
|
|
7
|
+
* @param deep 深度监控
|
|
8
|
+
*/
|
|
9
|
+
export declare function computed(arg?: any): void;
|
|
10
|
+
export declare function computed(target: any, propertyKey: string): void;
|