subay 0.0.7 → 0.0.10
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 +543 -239
- package/README.zh.md +682 -377
- package/examples/todo-app.html +286 -0
- package/lib/h.d.ts.map +1 -1
- package/lib/h.js +50 -32
- package/lib/h.js.map +1 -1
- package/lib/index.d.ts.map +1 -1
- package/lib/index.dev.js +3 -0
- package/lib/index.js +1 -2
- package/lib/index.js.map +1 -1
- package/lib/name.d.ts +2 -0
- package/lib/name.d.ts.map +1 -0
- package/lib/name.js +58 -0
- package/lib/name.js.map +1 -0
- package/lib/s.d.ts +12 -1
- package/lib/s.d.ts.map +1 -1
- package/lib/s.js +62 -64
- package/lib/s.js.map +1 -1
- package/package.json +13 -8
- package/src/h.ts +56 -42
- package/src/index.ts +0 -2
- package/src/name.ts +60 -0
- package/src/s.ts +96 -95
package/README.zh.md
CHANGED
|
@@ -1,377 +1,682 @@
|
|
|
1
|
-
#
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
##
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
);
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
});
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
```
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
```
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
const
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
```
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
//
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
1
|
+
# Subay
|
|
2
|
+
|
|
3
|
+
Subay 是一个轻量级的响应式编程库,提供了状态管理和 DOM 操作的功能。
|
|
4
|
+
|
|
5
|
+
## API
|
|
6
|
+
|
|
7
|
+
### root
|
|
8
|
+
|
|
9
|
+
**简介**
|
|
10
|
+
创建一个根更新上下文,用于管理响应式状态的生命周期。
|
|
11
|
+
|
|
12
|
+
**语法**
|
|
13
|
+
|
|
14
|
+
```typescript
|
|
15
|
+
root<T>(fn: (destroy: () => void) => T): T
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
**参数**
|
|
19
|
+
|
|
20
|
+
- `fn`: 一个函数,接收一个 `destroy` 函数作为参数,用于手动销毁根上下文。
|
|
21
|
+
|
|
22
|
+
**返回值**
|
|
23
|
+
|
|
24
|
+
- `T`: `fn` 函数的返回值。
|
|
25
|
+
|
|
26
|
+
**例子**
|
|
27
|
+
|
|
28
|
+
```typescript
|
|
29
|
+
import { root, o, S } from 'subay';
|
|
30
|
+
|
|
31
|
+
root((destroy) => {
|
|
32
|
+
const count = o(0);
|
|
33
|
+
const doubled = S(() => count() * 2);
|
|
34
|
+
|
|
35
|
+
console.log(doubled()); // 0
|
|
36
|
+
count(1);
|
|
37
|
+
console.log(doubled()); // 2
|
|
38
|
+
|
|
39
|
+
// 手动销毁
|
|
40
|
+
destroy();
|
|
41
|
+
});
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
**注意**
|
|
45
|
+
|
|
46
|
+
销毁使用 `root` 创建的上下文的唯一方式就是调用 `destroy` 回调。
|
|
47
|
+
|
|
48
|
+
### S
|
|
49
|
+
|
|
50
|
+
**简介**
|
|
51
|
+
创建一个计算值,当依赖的可观察值变化时自动重新计算。
|
|
52
|
+
|
|
53
|
+
**语法**
|
|
54
|
+
|
|
55
|
+
```typescript
|
|
56
|
+
S<T>(fn: (pv: T | undefined) => T, value?: T): IS<T>
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
**参数**
|
|
60
|
+
|
|
61
|
+
- `fn`: 计算函数,接收上一次的计算值作为参数。
|
|
62
|
+
- `value`: 可选的初始值。
|
|
63
|
+
|
|
64
|
+
**返回值**
|
|
65
|
+
|
|
66
|
+
- `IS<T>`: 一个函数,调用时返回计算值。
|
|
67
|
+
|
|
68
|
+
**例子**
|
|
69
|
+
|
|
70
|
+
```typescript
|
|
71
|
+
import { S, o } from 'subay';
|
|
72
|
+
|
|
73
|
+
const count = o(0);
|
|
74
|
+
const doubled = S(() => count() * 2);
|
|
75
|
+
|
|
76
|
+
console.log(doubled()); // 0
|
|
77
|
+
count(1);
|
|
78
|
+
console.log(doubled()); // 2
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
### o / observable
|
|
82
|
+
|
|
83
|
+
**简介**
|
|
84
|
+
创建一个可观察值,用于存储和更新状态。
|
|
85
|
+
|
|
86
|
+
**语法**
|
|
87
|
+
|
|
88
|
+
```typescript
|
|
89
|
+
o<T>(value: T): IO<T>
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
**参数**
|
|
93
|
+
|
|
94
|
+
- `value`: 初始值。
|
|
95
|
+
|
|
96
|
+
**返回值**
|
|
97
|
+
|
|
98
|
+
- `IO<T>`: 一个函数,无参数调用时返回当前值,带参数调用时更新值并返回新值。
|
|
99
|
+
|
|
100
|
+
**例子**
|
|
101
|
+
|
|
102
|
+
```typescript
|
|
103
|
+
import { o } from 'subay';
|
|
104
|
+
|
|
105
|
+
const count = o(0);
|
|
106
|
+
console.log(count()); // 0
|
|
107
|
+
count(1);
|
|
108
|
+
console.log(count()); // 1
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
### cleanup
|
|
112
|
+
|
|
113
|
+
**简介**
|
|
114
|
+
注册一个清理函数,当当前更新上下文被销毁时执行。
|
|
115
|
+
|
|
116
|
+
**语法**
|
|
117
|
+
|
|
118
|
+
```typescript
|
|
119
|
+
cleanup<T extends () => void>(f: T): T
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
**参数**
|
|
123
|
+
|
|
124
|
+
- `f`: 清理函数。
|
|
125
|
+
|
|
126
|
+
**返回值**
|
|
127
|
+
|
|
128
|
+
- `T`: 传入的清理函数。
|
|
129
|
+
|
|
130
|
+
**例子**
|
|
131
|
+
|
|
132
|
+
```typescript
|
|
133
|
+
import { root, S, o, cleanup } from 'subay';
|
|
134
|
+
|
|
135
|
+
root(() => {
|
|
136
|
+
const count = o(0);
|
|
137
|
+
|
|
138
|
+
S(() => {
|
|
139
|
+
console.log(count());
|
|
140
|
+
cleanup(() => {
|
|
141
|
+
console.log('Cleanup called');
|
|
142
|
+
});
|
|
143
|
+
});
|
|
144
|
+
|
|
145
|
+
count(1);
|
|
146
|
+
});
|
|
147
|
+
// 输出: 0, 1, Cleanup called
|
|
148
|
+
```
|
|
149
|
+
|
|
150
|
+
### transaction
|
|
151
|
+
|
|
152
|
+
**简介**
|
|
153
|
+
创建一个事务,批量更新可观察值,避免中间状态的计算。
|
|
154
|
+
|
|
155
|
+
**语法**
|
|
156
|
+
|
|
157
|
+
```typescript
|
|
158
|
+
transaction<T>(f: () => T): T
|
|
159
|
+
```
|
|
160
|
+
|
|
161
|
+
**参数**
|
|
162
|
+
|
|
163
|
+
- `f`: 事务函数,在其中可以更新多个可观察值。
|
|
164
|
+
|
|
165
|
+
**返回值**
|
|
166
|
+
|
|
167
|
+
- `T`: `f` 函数的返回值。
|
|
168
|
+
|
|
169
|
+
**例子**
|
|
170
|
+
|
|
171
|
+
```typescript
|
|
172
|
+
import { transaction, o, S } from 'subay';
|
|
173
|
+
|
|
174
|
+
const a = o(1);
|
|
175
|
+
const b = o(2);
|
|
176
|
+
const sum = S(() => a() + b());
|
|
177
|
+
|
|
178
|
+
S(() => console.log(sum())); // 3
|
|
179
|
+
|
|
180
|
+
transaction(() => {
|
|
181
|
+
a(2);
|
|
182
|
+
b(3);
|
|
183
|
+
});
|
|
184
|
+
// 输出: 5 (只计算一次)
|
|
185
|
+
```
|
|
186
|
+
|
|
187
|
+
### sample
|
|
188
|
+
|
|
189
|
+
**简介**
|
|
190
|
+
在不建立依赖关系的情况下获取可观察值的值。
|
|
191
|
+
|
|
192
|
+
**语法**
|
|
193
|
+
|
|
194
|
+
```typescript
|
|
195
|
+
sample<T>(f: () => T): T
|
|
196
|
+
```
|
|
197
|
+
|
|
198
|
+
**参数**
|
|
199
|
+
|
|
200
|
+
- `f`: 函数,在其中可以访问可观察值但不会建立依赖关系。
|
|
201
|
+
|
|
202
|
+
**返回值**
|
|
203
|
+
|
|
204
|
+
- `T`: `f` 函数的返回值。
|
|
205
|
+
|
|
206
|
+
**例子**
|
|
207
|
+
|
|
208
|
+
```typescript
|
|
209
|
+
import { sample, o, S } from 'subay';
|
|
210
|
+
|
|
211
|
+
const count = o(0);
|
|
212
|
+
let cachedValue;
|
|
213
|
+
|
|
214
|
+
S(() => {
|
|
215
|
+
// 不建立依赖关系
|
|
216
|
+
cachedValue = sample(() => count());
|
|
217
|
+
console.log(cachedValue);
|
|
218
|
+
});
|
|
219
|
+
|
|
220
|
+
count(1); // 不会触发重新计算
|
|
221
|
+
console.log(cachedValue); // 0
|
|
222
|
+
```
|
|
223
|
+
|
|
224
|
+
### isListening
|
|
225
|
+
|
|
226
|
+
**简介**
|
|
227
|
+
检查当前是否处于响应式监听状态。
|
|
228
|
+
|
|
229
|
+
**语法**
|
|
230
|
+
|
|
231
|
+
```typescript
|
|
232
|
+
isListening(): boolean
|
|
233
|
+
```
|
|
234
|
+
|
|
235
|
+
**参数**
|
|
236
|
+
|
|
237
|
+
- 无
|
|
238
|
+
|
|
239
|
+
**返回值**
|
|
240
|
+
|
|
241
|
+
- `boolean`: 当前是否处于响应式监听状态。
|
|
242
|
+
|
|
243
|
+
**例子**
|
|
244
|
+
|
|
245
|
+
```typescript
|
|
246
|
+
import { isListening, S } from 'subay';
|
|
247
|
+
|
|
248
|
+
console.log(isListening()); // false
|
|
249
|
+
|
|
250
|
+
S(() => {
|
|
251
|
+
console.log(isListening()); // true
|
|
252
|
+
});
|
|
253
|
+
```
|
|
254
|
+
|
|
255
|
+
### subscribe
|
|
256
|
+
|
|
257
|
+
**简介**
|
|
258
|
+
订阅一个函数,当依赖的可观察值变化时自动执行。
|
|
259
|
+
|
|
260
|
+
**语法**
|
|
261
|
+
|
|
262
|
+
```typescript
|
|
263
|
+
subscribe(f: () => void): () => void
|
|
264
|
+
```
|
|
265
|
+
|
|
266
|
+
**参数**
|
|
267
|
+
|
|
268
|
+
- `f`: 订阅函数。
|
|
269
|
+
|
|
270
|
+
**返回值**
|
|
271
|
+
|
|
272
|
+
- `() => void`: 取消订阅的函数。
|
|
273
|
+
|
|
274
|
+
**例子**
|
|
275
|
+
|
|
276
|
+
```typescript
|
|
277
|
+
import { subscribe, o } from 'subay';
|
|
278
|
+
|
|
279
|
+
const count = o(0);
|
|
280
|
+
const unsubscribe = subscribe(() => {
|
|
281
|
+
console.log(count());
|
|
282
|
+
});
|
|
283
|
+
|
|
284
|
+
count(1); // 输出: 1
|
|
285
|
+
count(2); // 输出: 2
|
|
286
|
+
|
|
287
|
+
unsubscribe();
|
|
288
|
+
count(3); // 无输出
|
|
289
|
+
```
|
|
290
|
+
|
|
291
|
+
### unsubscribe
|
|
292
|
+
|
|
293
|
+
**简介**
|
|
294
|
+
取消订阅一个函数。
|
|
295
|
+
|
|
296
|
+
**语法**
|
|
297
|
+
|
|
298
|
+
```typescript
|
|
299
|
+
unsubscribe(f: () => void): void
|
|
300
|
+
```
|
|
301
|
+
|
|
302
|
+
**参数**
|
|
303
|
+
|
|
304
|
+
- `f`: 要取消订阅的函数。
|
|
305
|
+
|
|
306
|
+
**返回值**
|
|
307
|
+
|
|
308
|
+
- 无
|
|
309
|
+
|
|
310
|
+
**例子**
|
|
311
|
+
|
|
312
|
+
```typescript
|
|
313
|
+
import { subscribe, unsubscribe, o } from 'subay';
|
|
314
|
+
|
|
315
|
+
const count = o(0);
|
|
316
|
+
const fn = () => console.log(count());
|
|
317
|
+
|
|
318
|
+
subscribe(fn);
|
|
319
|
+
count(1); // 输出: 1
|
|
320
|
+
|
|
321
|
+
unsubscribe(fn);
|
|
322
|
+
count(2); // 无输出
|
|
323
|
+
```
|
|
324
|
+
|
|
325
|
+
### isObservable
|
|
326
|
+
|
|
327
|
+
**简介**
|
|
328
|
+
检查一个值是否是可观察值。
|
|
329
|
+
|
|
330
|
+
**语法**
|
|
331
|
+
|
|
332
|
+
```typescript
|
|
333
|
+
isObservable(o: any): o is IO<any>
|
|
334
|
+
```
|
|
335
|
+
|
|
336
|
+
**参数**
|
|
337
|
+
|
|
338
|
+
- `o`: 要检查的值。
|
|
339
|
+
|
|
340
|
+
**返回值**
|
|
341
|
+
|
|
342
|
+
- `boolean`: 是否是可观察值。
|
|
343
|
+
|
|
344
|
+
**例子**
|
|
345
|
+
|
|
346
|
+
```typescript
|
|
347
|
+
import { isObservable, o, S } from 'subay';
|
|
348
|
+
|
|
349
|
+
const count = o(0);
|
|
350
|
+
const doubled = S(() => count() * 2);
|
|
351
|
+
|
|
352
|
+
console.log(isObservable(count)); // true
|
|
353
|
+
console.log(isObservable(doubled)); // false
|
|
354
|
+
```
|
|
355
|
+
|
|
356
|
+
### isComputed
|
|
357
|
+
|
|
358
|
+
**简介**
|
|
359
|
+
检查一个值是否是计算值。
|
|
360
|
+
|
|
361
|
+
**语法**
|
|
362
|
+
|
|
363
|
+
```typescript
|
|
364
|
+
isComputed(o: any): o is IS<any>
|
|
365
|
+
```
|
|
366
|
+
|
|
367
|
+
**参数**
|
|
368
|
+
|
|
369
|
+
- `o`: 要检查的值。
|
|
370
|
+
|
|
371
|
+
**返回值**
|
|
372
|
+
|
|
373
|
+
- `boolean`: 是否是计算值。
|
|
374
|
+
|
|
375
|
+
**例子**
|
|
376
|
+
|
|
377
|
+
```typescript
|
|
378
|
+
import { isComputed, o, S } from 'subay';
|
|
379
|
+
|
|
380
|
+
const count = o(0);
|
|
381
|
+
const doubled = S(() => count() * 2);
|
|
382
|
+
|
|
383
|
+
console.log(isComputed(count)); // false
|
|
384
|
+
console.log(isComputed(doubled)); // true
|
|
385
|
+
```
|
|
386
|
+
|
|
387
|
+
### isReactive
|
|
388
|
+
|
|
389
|
+
**简介**
|
|
390
|
+
检查一个值是否是响应式值(可观察值或计算值)。
|
|
391
|
+
|
|
392
|
+
**语法**
|
|
393
|
+
|
|
394
|
+
```typescript
|
|
395
|
+
isReactive(o: any): o is IO<any> | IS<any>
|
|
396
|
+
```
|
|
397
|
+
|
|
398
|
+
**参数**
|
|
399
|
+
|
|
400
|
+
- `o`: 要检查的值。
|
|
401
|
+
|
|
402
|
+
**返回值**
|
|
403
|
+
|
|
404
|
+
- `boolean`: 是否是响应式值。
|
|
405
|
+
|
|
406
|
+
**例子**
|
|
407
|
+
|
|
408
|
+
```typescript
|
|
409
|
+
import { isReactive, o, S } from 'subay';
|
|
410
|
+
|
|
411
|
+
const count = o(0);
|
|
412
|
+
const doubled = S(() => count() * 2);
|
|
413
|
+
|
|
414
|
+
console.log(isReactive(count)); // true
|
|
415
|
+
console.log(isReactive(doubled)); // true
|
|
416
|
+
console.log(isReactive(42)); // false
|
|
417
|
+
```
|
|
418
|
+
|
|
419
|
+
### map
|
|
420
|
+
|
|
421
|
+
**简介**
|
|
422
|
+
将一个数组映射为 DOM 节点数组,当数组变化时自动更新。
|
|
423
|
+
|
|
424
|
+
**语法**
|
|
425
|
+
|
|
426
|
+
```typescript
|
|
427
|
+
map<T>(array: () => T[], f: (item: T) => Node[]): Node[]
|
|
428
|
+
```
|
|
429
|
+
|
|
430
|
+
**参数**
|
|
431
|
+
|
|
432
|
+
- `array`: 一个返回数组的函数。
|
|
433
|
+
- `f`: 映射函数,将数组项转换为 DOM 节点数组。
|
|
434
|
+
|
|
435
|
+
**返回值**
|
|
436
|
+
|
|
437
|
+
- `Node[]`: DOM 节点数组。
|
|
438
|
+
|
|
439
|
+
**例子**
|
|
440
|
+
|
|
441
|
+
```typescript
|
|
442
|
+
import { map, o, html } from 'subay';
|
|
443
|
+
|
|
444
|
+
const items = o(['a', 'b', 'c']);
|
|
445
|
+
const list = map(
|
|
446
|
+
() => items(),
|
|
447
|
+
(item) => html`<li>${item}</li>`,
|
|
448
|
+
);
|
|
449
|
+
|
|
450
|
+
document.body.append(...list);
|
|
451
|
+
// 渲染: <li>a</li><li>b</li><li>c</li>
|
|
452
|
+
|
|
453
|
+
items(['a', 'b', 'c', 'd']);
|
|
454
|
+
// 自动更新: <li>a</li><li>b</li><li>c</li><li>d</li>
|
|
455
|
+
```
|
|
456
|
+
|
|
457
|
+
### svg
|
|
458
|
+
|
|
459
|
+
**简介**
|
|
460
|
+
创建 SVG 元素的模板标签函数。
|
|
461
|
+
|
|
462
|
+
**语法**
|
|
463
|
+
|
|
464
|
+
```typescript
|
|
465
|
+
svg(segments: TemplateStringsArray, ...values: any[]): Node[]
|
|
466
|
+
```
|
|
467
|
+
|
|
468
|
+
**参数**
|
|
469
|
+
|
|
470
|
+
- `segments`: 模板字符串的静态部分。
|
|
471
|
+
- `values`: 模板字符串的动态部分。
|
|
472
|
+
|
|
473
|
+
**返回值**
|
|
474
|
+
|
|
475
|
+
- `Node[]`: SVG 元素节点数组。
|
|
476
|
+
|
|
477
|
+
**例子**
|
|
478
|
+
|
|
479
|
+
```typescript
|
|
480
|
+
import { svg, o } from 'subay';
|
|
481
|
+
|
|
482
|
+
const radius = o(50);
|
|
483
|
+
const circle = svg`<circle cx="100" cy="100" r="${radius}" fill="red"/>`;
|
|
484
|
+
|
|
485
|
+
document.getElementById('svg').append(...circle);
|
|
486
|
+
```
|
|
487
|
+
|
|
488
|
+
### html
|
|
489
|
+
|
|
490
|
+
**简介**
|
|
491
|
+
创建 HTML 元素的模板标签函数。
|
|
492
|
+
|
|
493
|
+
**语法**
|
|
494
|
+
|
|
495
|
+
```typescript
|
|
496
|
+
html(segments: TemplateStringsArray, ...values: any[]): Node[]
|
|
497
|
+
```
|
|
498
|
+
|
|
499
|
+
**参数**
|
|
500
|
+
|
|
501
|
+
- `segments`: 模板字符串的静态部分。
|
|
502
|
+
- `values`: 模板字符串的动态部分。
|
|
503
|
+
|
|
504
|
+
**返回值**
|
|
505
|
+
|
|
506
|
+
- `Node[]`: HTML 元素节点数组。
|
|
507
|
+
|
|
508
|
+
**例子**
|
|
509
|
+
|
|
510
|
+
```typescript
|
|
511
|
+
import { html, o } from 'subay';
|
|
512
|
+
|
|
513
|
+
const count = o(0);
|
|
514
|
+
const counter = html`
|
|
515
|
+
<div>
|
|
516
|
+
<p>Count: ${count}</p>
|
|
517
|
+
<button onclick=${() => count(count() + 1)}>Increment</button>
|
|
518
|
+
</div>
|
|
519
|
+
`;
|
|
520
|
+
|
|
521
|
+
document.body.append(...counter);
|
|
522
|
+
// 点击按钮会自动更新 count 的值
|
|
523
|
+
```
|
|
524
|
+
|
|
525
|
+
**使用 HTML**
|
|
526
|
+
|
|
527
|
+
Subay 使用 `DOMParser` 解析 HTML 模板, `html` 的参数必须是合法的 HTML 字符串,(同理, `svg` 的参数必须是合法的 SVG 字符串), 这是有别于 JSX 的地方。
|
|
528
|
+
|
|
529
|
+
**例子**
|
|
530
|
+
|
|
531
|
+
```typescript
|
|
532
|
+
import { html } from 'subay';
|
|
533
|
+
|
|
534
|
+
// 合法的 HTML 字符串
|
|
535
|
+
const validHtml = html`<div><p>Hello</p></div>`;
|
|
536
|
+
|
|
537
|
+
document.body.append(...validHtml);
|
|
538
|
+
```
|
|
539
|
+
|
|
540
|
+
**错误示例**
|
|
541
|
+
|
|
542
|
+
```typescript
|
|
543
|
+
import { html } from 'subay';
|
|
544
|
+
|
|
545
|
+
// 自闭合标签
|
|
546
|
+
const invalidHtml = html`<div>
|
|
547
|
+
<span />
|
|
548
|
+
<span />
|
|
549
|
+
</div>`; // 会导致解析成 <div><span><span></span></span></div>
|
|
550
|
+
```
|
|
551
|
+
|
|
552
|
+
**传入对象作为元素属性**
|
|
553
|
+
|
|
554
|
+
如果需要传入一个对象作为元素属性,可以使用 `...` 语法。
|
|
555
|
+
|
|
556
|
+
**语法**
|
|
557
|
+
|
|
558
|
+
```typescript
|
|
559
|
+
html`<tag ...${props}></tag>`;
|
|
560
|
+
```
|
|
561
|
+
|
|
562
|
+
**例子**
|
|
563
|
+
|
|
564
|
+
```typescript
|
|
565
|
+
import { html, o } from 'subay';
|
|
566
|
+
|
|
567
|
+
const props = o({
|
|
568
|
+
className: 'container',
|
|
569
|
+
style: 'color: red;',
|
|
570
|
+
});
|
|
571
|
+
|
|
572
|
+
const element = html`<div ...${props}></div>`;
|
|
573
|
+
|
|
574
|
+
document.body.append(...element);
|
|
575
|
+
```
|
|
576
|
+
|
|
577
|
+
**组件的声明**
|
|
578
|
+
|
|
579
|
+
组件是一个返回 Node\[] 的函数,可以接收参数。和 React、Vue 等不同,组件的参数是一个列表。
|
|
580
|
+
|
|
581
|
+
**语法**
|
|
582
|
+
|
|
583
|
+
```typescript
|
|
584
|
+
const Component = (text, children: () => Node[]) => {
|
|
585
|
+
return html`<div>${text}</div>`;
|
|
586
|
+
};
|
|
587
|
+
```
|
|
588
|
+
|
|
589
|
+
**例子**
|
|
590
|
+
|
|
591
|
+
```typescript
|
|
592
|
+
import { html } from 'subay';
|
|
593
|
+
|
|
594
|
+
const Greeting = (name: string, children: () => Node[]) => {
|
|
595
|
+
return html`
|
|
596
|
+
<div>
|
|
597
|
+
<h1>Hello, ${name}!</h1>
|
|
598
|
+
${children()}
|
|
599
|
+
</div>
|
|
600
|
+
`;
|
|
601
|
+
};
|
|
602
|
+
```
|
|
603
|
+
|
|
604
|
+
**组件的使用**
|
|
605
|
+
|
|
606
|
+
在模板中使用组件时,在标签处引用组件。
|
|
607
|
+
因为模板是 HTML 字符串,引用的时候不支持自闭合标签。
|
|
608
|
+
传给组件的参数必须和组件声明的参数顺序一致。
|
|
609
|
+
组件获得的参数总是和传入的保持一致。
|
|
610
|
+
|
|
611
|
+
**例子**
|
|
612
|
+
|
|
613
|
+
```typescript
|
|
614
|
+
import { html, o } from 'subay';
|
|
615
|
+
|
|
616
|
+
const Greeting = (greet: string, name: () => string) => {
|
|
617
|
+
return html`<h1>${greet}, ${name}!</h1>`;
|
|
618
|
+
};
|
|
619
|
+
|
|
620
|
+
const name = o('World');
|
|
621
|
+
const app = html` <div><${Greeting} greet=${'Hello'} name=${name}></${Greeting}></div> `;
|
|
622
|
+
|
|
623
|
+
document.body.append(...app);
|
|
624
|
+
```
|
|
625
|
+
|
|
626
|
+
**错误示例**
|
|
627
|
+
|
|
628
|
+
```typescript
|
|
629
|
+
import { html, o } from 'subay';
|
|
630
|
+
|
|
631
|
+
const Greeting = (greet: string, name: () => string) => {
|
|
632
|
+
return html`<h1>${greet}, ${name}!</h1>`;
|
|
633
|
+
};
|
|
634
|
+
|
|
635
|
+
const name = o('World');
|
|
636
|
+
// 错误, 后面的 span 会被当做 Greeting 的子节点。
|
|
637
|
+
const app = html`
|
|
638
|
+
<div>
|
|
639
|
+
<${Greeting}
|
|
640
|
+
greet=${'Hello'}
|
|
641
|
+
name=${name}
|
|
642
|
+
/>
|
|
643
|
+
<span></span>
|
|
644
|
+
</div>
|
|
645
|
+
`;
|
|
646
|
+
// 错误, 参数顺序和 Greeting 的参数不一致
|
|
647
|
+
const app = html` <div><${Greeting} name=${name} greet=${'Hi'} ></${Greeting}></div> `;
|
|
648
|
+
|
|
649
|
+
document.body.append(...app);
|
|
650
|
+
```
|
|
651
|
+
|
|
652
|
+
**动态的组件**
|
|
653
|
+
|
|
654
|
+
标签位置的插值可以是 `S` 或 `o` 的返回值,可以根据条件动态选择要渲染的组件。
|
|
655
|
+
|
|
656
|
+
**例子**
|
|
657
|
+
|
|
658
|
+
```typescript
|
|
659
|
+
import { html, o, S } from 'subay';
|
|
660
|
+
|
|
661
|
+
const Greeting = (name: () => string) => {
|
|
662
|
+
return html`<h1>Hello, ${name}!</h1>`;
|
|
663
|
+
};
|
|
664
|
+
|
|
665
|
+
const Farewell = (name: () => string) => {
|
|
666
|
+
return html`<h1>Goodbye, ${name}!</h1>`;
|
|
667
|
+
};
|
|
668
|
+
|
|
669
|
+
const showGreeting = o(true);
|
|
670
|
+
const name = o('World');
|
|
671
|
+
const Component = S(() => (showGreeting() ? Greeting : Farewell));
|
|
672
|
+
|
|
673
|
+
const app = html`
|
|
674
|
+
<div>
|
|
675
|
+
<${Component} name=${name} ></${Component}>
|
|
676
|
+
<button onclick=${() => showGreeting(!showGreeting())}>Toggle</button>
|
|
677
|
+
</div>
|
|
678
|
+
`;
|
|
679
|
+
|
|
680
|
+
document.body.append(...app);
|
|
681
|
+
```
|
|
682
|
+
|