cdui-js 1.0.6 → 1.0.8
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 +490 -183
- package/build/css.ts +32 -23
- package/package.json +22 -22
- package/src/components/{Dialog.tsx → Dialog.ts} +36 -36
- package/src/components/{For.tsx → For.ts} +26 -26
- package/src/components/{If.tsx → If.ts} +14 -14
- package/src/components/{KeepAlive.tsx → KeepAlive.ts} +26 -26
- package/src/components/{Switch.tsx → Switch.ts} +49 -49
- package/src/reactive.ts +361 -241
package/README.md
CHANGED
|
@@ -1,183 +1,490 @@
|
|
|
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
|
-
|
|
1
|
+
> 不建议直接使用此库,而是基于 [cdui-template](https://github.com/china-difi/cdui-template) 项目模板构建项目,更简单功能也更强大。
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
# 响应式原理
|
|
5
|
+
|
|
6
|
+
响应式`(Reactivity)`增强了应用程序的交互性。这种编程范式是指系统自动响应数据或状态变化的能力,确保用户界面 (UI) 和状态保持同步,从而减少手动更新的需要。
|
|
7
|
+
|
|
8
|
+
## 响应式对象
|
|
9
|
+
|
|
10
|
+
响应式对象是响应式体系的核心元素,在数据管理和系统响应中发挥着重要作用。其负责存储和管理数据,收集相关的依赖,以及在属性值发生变化时自动同步更新相应的依赖。响应式对象的每-个属性都绑定了`getter`和`setter`方法,响应式对象的每一个属性都是一个响应式数据。
|
|
11
|
+
|
|
12
|
+
读取响应式对象的属性时,会自动调用其相应的`getter`方法,此时系统会自动收集依赖并返回其存储的值。
|
|
13
|
+
修改响应式对象的属性时,会自动调用其相应的`setter`方法,此时系统会修改其存储的值且自动更新相应依赖。
|
|
14
|
+
|
|
15
|
+
```tsx
|
|
16
|
+
import { reactive } from 'cdui-js';
|
|
17
|
+
|
|
18
|
+
// 创建响应式数据
|
|
19
|
+
const state = reactive({
|
|
20
|
+
count: 0,
|
|
21
|
+
items: []
|
|
22
|
+
});
|
|
23
|
+
|
|
24
|
+
// 读取响应式属性值
|
|
25
|
+
console.log(state.count);
|
|
26
|
+
|
|
27
|
+
// 修改响应式属性值
|
|
28
|
+
state.count++;
|
|
29
|
+
|
|
30
|
+
// 数组也是响应式的,子项发生变化时也会自动同步相应的依赖
|
|
31
|
+
state.items.push({});
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
## 订阅者
|
|
35
|
+
|
|
36
|
+
订阅者负责追踪响应式数据的变化并在变化时自动执行相应函数,以保持系统与最新的数据变化同步。
|
|
37
|
+
|
|
38
|
+
有三种订阅变化并同步的方式:
|
|
39
|
+
|
|
40
|
+
1. watch
|
|
41
|
+
|
|
42
|
+
```tsx
|
|
43
|
+
import { reactive, watch } from 'cdui-js';
|
|
44
|
+
|
|
45
|
+
// 创建响应式数据
|
|
46
|
+
const state = reactive({ count: 0 });
|
|
47
|
+
|
|
48
|
+
// 观测响应式数据的变化,当观测的响应式数据发生变化时,会自动执行观测函数
|
|
49
|
+
watch(() => state.count, (count) => {
|
|
50
|
+
console.log(count);
|
|
51
|
+
});
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
可以同时观测多个响应式数据,对于`typescript`,可以使用`as const`断言标观测到的数据类型。
|
|
55
|
+
|
|
56
|
+
```tsx
|
|
57
|
+
import { reactive, watch } from 'cdui-js';
|
|
58
|
+
|
|
59
|
+
const state1 = reactive({ value: 0 });
|
|
60
|
+
const state2 = reactive({ value: 1 });
|
|
61
|
+
|
|
62
|
+
// 注意,as const 把返回值类型标记为元组
|
|
63
|
+
watch(() => [state1.value, state2.value] as const, ([value1, value2]) => {
|
|
64
|
+
console.log(value1, value1);
|
|
65
|
+
});
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
2. createEffect
|
|
69
|
+
|
|
70
|
+
`watch`方法只有在依赖发生变化时才执行相应函数,而`createEffect`创建时立即执行相应函数并自动收集相应的依赖。
|
|
71
|
+
|
|
72
|
+
```tsx
|
|
73
|
+
import { reactive, createEffect } from 'cdui-js';
|
|
74
|
+
|
|
75
|
+
const state1 = reactive({ value: 0 });
|
|
76
|
+
const state2 = reactive({ value: 1 });
|
|
77
|
+
|
|
78
|
+
createEffect(() => {
|
|
79
|
+
console.log(state1.value);
|
|
80
|
+
|
|
81
|
+
// 注意短路问题(state1.value 发生变化时并不会执行回调函数)
|
|
82
|
+
console.log(state2.value || state1.value);
|
|
83
|
+
});
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
3. createMemo
|
|
87
|
+
|
|
88
|
+
`createMemo`用于缓存响应式计算结果,只有当依赖的响应式数据发生变化时才会重新计算,适用于依赖响应式数据的昂贵计算(简单计算性能返而更低),注意,`createMemo`同样存在短路的问题。
|
|
89
|
+
|
|
90
|
+
```tsx
|
|
91
|
+
import { reactive, createMemo } from 'cdui-js';
|
|
92
|
+
|
|
93
|
+
const state = reactive({ value: 0 });
|
|
94
|
+
|
|
95
|
+
// 创建响应式缓存表示式(注意返回值是一个 function,只有 state.value 发生变化时才会重新计算)
|
|
96
|
+
const getValue = createMemo(() => state.value + 100);
|
|
97
|
+
|
|
98
|
+
// 读取缓存的响应式结果
|
|
99
|
+
console.log(getValue());
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
|
|
103
|
+
# 响应式组件
|
|
104
|
+
|
|
105
|
+
任意一个函数,如果返回了`JSX.Element`,则这个函数就是一个响应式组件。建议使用`tsx`作为组件模板,本响应式框架没有虚拟`DOM`,也更轻量高效。
|
|
106
|
+
|
|
107
|
+
```tsx
|
|
108
|
+
import { reactive } from 'cdui-js';
|
|
109
|
+
|
|
110
|
+
function Counter() {
|
|
111
|
+
// 创建响应式状态
|
|
112
|
+
const state = reactive({ count: 0 });
|
|
113
|
+
|
|
114
|
+
return (
|
|
115
|
+
<div>
|
|
116
|
+
<span>Count: {state.count}</span>{" "}
|
|
117
|
+
{/* 当按钮点击的时候,会自动更新页面 */}
|
|
118
|
+
<button type="button" onclick={() => state.count++}>
|
|
119
|
+
Increment
|
|
120
|
+
</button>
|
|
121
|
+
</div>
|
|
122
|
+
);
|
|
123
|
+
}
|
|
124
|
+
```
|
|
125
|
+
|
|
126
|
+
在这段代码中,当点击`Counter`组件内的按钮时,响应式数据`state.count`自增`1`,绑定了响应式数据`state.count`的部分会自动更新,但不会重新渲染整个组件。也就是说,在`return`语句之前的代码,只在函数调用时执行一次。
|
|
127
|
+
|
|
128
|
+
|
|
129
|
+
## 组件生命周期
|
|
130
|
+
|
|
131
|
+
1. onMount 与 ref
|
|
132
|
+
|
|
133
|
+
`onMount`在组件挂载后运行,只会执行一次,且在服务端渲染时不会执行,也不跟踪任何依赖项,`onMount`函数内可以访问相应的`DOM`对象。
|
|
134
|
+
|
|
135
|
+
```tsx
|
|
136
|
+
import { onMount } from 'cdui-js';
|
|
137
|
+
|
|
138
|
+
function Component() {
|
|
139
|
+
onMount(async () => {
|
|
140
|
+
// 此处可通过选择器获取相应的DOM对象
|
|
141
|
+
let dom = document.getElementById('dom-id');
|
|
142
|
+
});
|
|
143
|
+
|
|
144
|
+
return <div id="dom-id">...</div>;
|
|
145
|
+
}
|
|
146
|
+
```
|
|
147
|
+
|
|
148
|
+
但是,不建议通过选择器获取`DOM`对象,因为选择器可能会冲突,最好声明一个变量并将其绑定到`ref`属性:
|
|
149
|
+
|
|
150
|
+
```tsx
|
|
151
|
+
import { onMount } from 'cdui-js';
|
|
152
|
+
|
|
153
|
+
function Component() {
|
|
154
|
+
// 声明绑定到`ref`属性的变量
|
|
155
|
+
let dom;
|
|
156
|
+
|
|
157
|
+
onMount(async () => {
|
|
158
|
+
// 此处即可访问声明的变量 dom 来操控 div 对象
|
|
159
|
+
});
|
|
160
|
+
|
|
161
|
+
// 通过 ref 属性绑定变量
|
|
162
|
+
return <div ref={dom}>...</div>;
|
|
163
|
+
}
|
|
164
|
+
```
|
|
165
|
+
|
|
166
|
+
> 注意,必须在`onMount`内访问`ref`绑定的变量,此时才能保证声明的变量成功绑定到`ref`属性,同时,也不会影响服务端渲染,因为服务端渲染不会执行`onMount`函数。
|
|
167
|
+
|
|
168
|
+
|
|
169
|
+
1. onCleanup
|
|
170
|
+
|
|
171
|
+
`onCleanup`用于在组件卸载时执行一些清理任务,以避免内存泄漏及一些不必要的操作。
|
|
172
|
+
|
|
173
|
+
```tsx
|
|
174
|
+
import { reactive, onMount, onCleanup } from 'cdui-js';
|
|
175
|
+
|
|
176
|
+
function Component() {
|
|
177
|
+
let dom;
|
|
178
|
+
const state = reactive({ count: 1 });
|
|
179
|
+
|
|
180
|
+
const timer = setInterval(() => {
|
|
181
|
+
state.count += 1;
|
|
182
|
+
}, 1000);
|
|
183
|
+
|
|
184
|
+
onMount(() => {
|
|
185
|
+
const onclick = () => console.log('clicked');
|
|
186
|
+
|
|
187
|
+
dom.addEventListener('click', onclick);
|
|
188
|
+
// 组件卸载时移除事件
|
|
189
|
+
onCleanup(() => {
|
|
190
|
+
dom.removeEventListener('click', onclick);
|
|
191
|
+
});
|
|
192
|
+
});
|
|
193
|
+
|
|
194
|
+
// 组件卸载时清理定时器
|
|
195
|
+
onCleanup(() => {
|
|
196
|
+
clearInterval(timer);
|
|
197
|
+
});
|
|
198
|
+
|
|
199
|
+
return <div ref={dom}>Count: {state.count}</div>;
|
|
200
|
+
}
|
|
201
|
+
```
|
|
202
|
+
|
|
203
|
+
## class
|
|
204
|
+
|
|
205
|
+
可以通过`class`属性设置`DOM`元素的样式。
|
|
206
|
+
|
|
207
|
+
```tsx
|
|
208
|
+
// 值为字符串常
|
|
209
|
+
<div class="bg-c"></div>
|
|
210
|
+
// 值为表示式
|
|
211
|
+
<div class={window.innerWidth > 480 ? 'pc' : 'mobile'}></div>
|
|
212
|
+
```
|
|
213
|
+
|
|
214
|
+
当您想将多个类名应用于一个元素时,可以使用`classList`属性。可以传递一个对象,其中键代表类名,值代表布尔表达式。当值为`true`时,应用该类名;当值为`false`时,删除该类名。
|
|
215
|
+
|
|
216
|
+
```tsx
|
|
217
|
+
import { reactive } from 'cdui-js';
|
|
218
|
+
|
|
219
|
+
const state = reactive({ hidden: false });
|
|
220
|
+
|
|
221
|
+
<div>
|
|
222
|
+
<span classList={{ hidden: state.hidden }}>classList</span>
|
|
223
|
+
<button onclick={() => state.hidden = !state.hidden}>toggle</button>
|
|
224
|
+
</div>
|
|
225
|
+
```
|
|
226
|
+
|
|
227
|
+
> 注意不要混合使用 `class`和`classlist`,这可能会产生不可意料的结果
|
|
228
|
+
|
|
229
|
+
|
|
230
|
+
## style
|
|
231
|
+
|
|
232
|
+
`style`属性允许您设置单个元素的样式。可以值字符串的形式,也可以使用对象的形式,在`typescript`使用对象形式可以得到更好的提示。
|
|
233
|
+
|
|
234
|
+
```tsx
|
|
235
|
+
// 字符串值
|
|
236
|
+
<div style="color:red">Red</div>
|
|
237
|
+
|
|
238
|
+
// 对象值
|
|
239
|
+
<div style={{ color: 'red' }}>Red</div>
|
|
240
|
+
```
|
|
241
|
+
|
|
242
|
+
## 自定义属性(props)
|
|
243
|
+
|
|
244
|
+
`props`是一种将状态从父组件传递到子组件的方法。在子组件中可定义`props`对象参数:
|
|
245
|
+
|
|
246
|
+
```tsx
|
|
247
|
+
function ChildComponent(props: { name: string }) {
|
|
248
|
+
return <div>Hello {props.name}</div>;
|
|
249
|
+
}
|
|
250
|
+
```
|
|
251
|
+
|
|
252
|
+
父组件可通过`JSX`属性传入:
|
|
253
|
+
|
|
254
|
+
```tsx
|
|
255
|
+
function ParentComponent() {
|
|
256
|
+
return <MyComponent name="Your Name" />
|
|
257
|
+
}
|
|
258
|
+
```
|
|
259
|
+
|
|
260
|
+
有时候,需要把不同的属性值应用到不同的`DOM`节点,可以使用`splitProps`方法对`props`进行切分。切分后的任一部分都具有响应式特性。
|
|
261
|
+
|
|
262
|
+
```tsx
|
|
263
|
+
import { splitProps } from 'cdui-js';
|
|
264
|
+
|
|
265
|
+
function Component(props: { title: string, children: JSX.Element[] }) {
|
|
266
|
+
// restProps 为拆分后剩余的部分
|
|
267
|
+
const [titleProps, childrenProps, restProps] = splitProps(props, ['title'], ['children']);
|
|
268
|
+
|
|
269
|
+
return (
|
|
270
|
+
<div {...restProps}>
|
|
271
|
+
<div>{titleProps.title}</div>
|
|
272
|
+
<div>{childrenProps.children}</div>
|
|
273
|
+
</div>
|
|
274
|
+
);
|
|
275
|
+
}
|
|
276
|
+
```
|
|
277
|
+
|
|
278
|
+
> 注意,解构`props`对象会丧失响应性,除非你确定要这样,否则不要随意解构任意`props`或响应式对象。
|
|
279
|
+
|
|
280
|
+
```tsx
|
|
281
|
+
function Component(props: { name: string }) {
|
|
282
|
+
let name = props.name;
|
|
283
|
+
// 注意:name 不再具备响应式能力
|
|
284
|
+
return <div>{name}</div>
|
|
285
|
+
}
|
|
286
|
+
```
|
|
287
|
+
|
|
288
|
+
## 事件
|
|
289
|
+
|
|
290
|
+
可以通过`onxxx`属性像`HTML`那样绑定事件:
|
|
291
|
+
|
|
292
|
+
```tsx
|
|
293
|
+
<div onclick={() => console.log('clicked')}>click</div>
|
|
294
|
+
```
|
|
295
|
+
|
|
296
|
+
事件处理方法与标准事件一致,可通过`event`参数获取事件信息或控制事件:
|
|
297
|
+
|
|
298
|
+
```tsx
|
|
299
|
+
<div onclick={event => event.stopPropagation()}>click</div>
|
|
300
|
+
```
|
|
301
|
+
|
|
302
|
+
|
|
303
|
+
# 条件渲染(If)
|
|
304
|
+
|
|
305
|
+
`If`组件可实现按需渲染。
|
|
306
|
+
|
|
307
|
+
```tsx
|
|
308
|
+
import { If } from 'cdui-js';
|
|
309
|
+
|
|
310
|
+
<If when={...}>when 值为真时才会显示这段文字</If>
|
|
311
|
+
```
|
|
312
|
+
|
|
313
|
+
可以指定`when`为假时显示其它组件。
|
|
314
|
+
|
|
315
|
+
```tsx
|
|
316
|
+
import { If } from 'cdui-js';
|
|
317
|
+
|
|
318
|
+
<If when={...} else={<span>when 值为假时显示这段文字</span>}>when 值为真时显示这段文字</If>
|
|
319
|
+
```
|
|
320
|
+
|
|
321
|
+
|
|
322
|
+
# 保活(KeepAlive)
|
|
323
|
+
|
|
324
|
+
`If`组件的条件发生变化时,原来的内容会被销毁,有时我们希望条件切换后不要销毁相应内容,而是缓存起来,再下次条件切换回来的时候直接复用缓存的内容,可以使用`KeepAlive`组件。
|
|
325
|
+
|
|
326
|
+
```tsx
|
|
327
|
+
import { KeepAlive } from 'cdui-js';
|
|
328
|
+
|
|
329
|
+
<KeepAlive show={...}>这一段内容在 show 属性为假时会缓存起来</KeepAlive>
|
|
330
|
+
```
|
|
331
|
+
|
|
332
|
+
|
|
333
|
+
# 循环渲染(For)
|
|
334
|
+
|
|
335
|
+
`For`组件可以根据数组内容循环渲染。
|
|
336
|
+
|
|
337
|
+
```tsx
|
|
338
|
+
import { For } from 'cdui-js';
|
|
339
|
+
|
|
340
|
+
<For each={[...]}>{
|
|
341
|
+
(item, index) => <div>{`index: ${index()} item: ${item}`}</div>
|
|
342
|
+
}</For>
|
|
343
|
+
```
|
|
344
|
+
|
|
345
|
+
|
|
346
|
+
## 响应式布局(layout)
|
|
347
|
+
|
|
348
|
+
`layout`是一全局响应式数据对象,由 [cdui-template](https://github.com/china-difi/cdui-template) 模板项目的`index.html`中会自动设置此对象相应属性值,样式相关响应式布局规范可参考模板项目的`README.md`文档,此处不展开。
|
|
349
|
+
|
|
350
|
+
代码中可使用相应的布局临界值属性实现按需渲染,比如有一个移动端的页面和一个`PC`端的页面,在页面宽度小于等于`480`像素时渲染移动端页面,否则渲染`PC端页面`。
|
|
351
|
+
|
|
352
|
+
```tsx
|
|
353
|
+
import { KeepAlive, layout } from 'cdui-js';
|
|
354
|
+
|
|
355
|
+
<>
|
|
356
|
+
<KeepAlive when={layout['le-480']}>
|
|
357
|
+
<PC></PC>
|
|
358
|
+
</KeepAlive>
|
|
359
|
+
<KeepAlive when={layout['gt-480']}>
|
|
360
|
+
<Mobile></Mobile>
|
|
361
|
+
</KeepAlive>
|
|
362
|
+
</>
|
|
363
|
+
```
|
|
364
|
+
|
|
365
|
+
|
|
366
|
+
# 路由(Switch + location)
|
|
367
|
+
|
|
368
|
+
`Switch`组件可根据`case`条件动态渲染内容。
|
|
369
|
+
|
|
370
|
+
```tsx
|
|
371
|
+
import { Switch } from 'cdui-js';
|
|
372
|
+
|
|
373
|
+
const routes = [
|
|
374
|
+
{
|
|
375
|
+
id: 'component1',
|
|
376
|
+
component: ...
|
|
377
|
+
},
|
|
378
|
+
{
|
|
379
|
+
id: 'component2',
|
|
380
|
+
component: ...
|
|
381
|
+
}
|
|
382
|
+
];
|
|
383
|
+
|
|
384
|
+
<Switch case={xxx ? routes[0] : routes[1]}></Switch>
|
|
385
|
+
```
|
|
386
|
+
|
|
387
|
+
`case`对象的`id`属性控制缓存,不设置则不会缓存相应内容,设置后,如果存在相应`id`的缓存内容,则直接复用缓存伯内容。
|
|
388
|
+
|
|
389
|
+
配合全局响应式对象`location`,可根据当前页面灵活控制渲染内容。
|
|
390
|
+
|
|
391
|
+
```tsx
|
|
392
|
+
import { Switch } from 'cdui-js';
|
|
393
|
+
|
|
394
|
+
const routes = [
|
|
395
|
+
{
|
|
396
|
+
id: 'component1',
|
|
397
|
+
path: 'p1',
|
|
398
|
+
component: ...
|
|
399
|
+
},
|
|
400
|
+
{
|
|
401
|
+
id: 'component2',
|
|
402
|
+
path: 'p2',
|
|
403
|
+
component: ...
|
|
404
|
+
}
|
|
405
|
+
];
|
|
406
|
+
|
|
407
|
+
// 404
|
|
408
|
+
const NotFound = {
|
|
409
|
+
id: '404',
|
|
410
|
+
component: () => {
|
|
411
|
+
return <div>Not Found</div>;
|
|
412
|
+
}
|
|
413
|
+
};
|
|
414
|
+
|
|
415
|
+
<Switch case={routes.find(item => item.path === location.path) || NotFound}></Switch>
|
|
416
|
+
```
|
|
417
|
+
|
|
418
|
+
> 实际业务场景还可使用`location`的`paths、query、hash`属性值进行匹配
|
|
419
|
+
|
|
420
|
+
|
|
421
|
+
# 异步加载数据(createFetcher)
|
|
422
|
+
|
|
423
|
+
使用`createFetcher`方法可以创建一个异步数据加载器,返回的对象也是一个响应式对象。
|
|
424
|
+
|
|
425
|
+
```tsx
|
|
426
|
+
import { If, createFetcher } from 'cdui-js';
|
|
427
|
+
|
|
428
|
+
// 加载异步数据的方法
|
|
429
|
+
const loadAsyncData = () => {
|
|
430
|
+
return new Promise(resolve => {
|
|
431
|
+
setTimeout(() => resolve([...]), 1000);
|
|
432
|
+
});
|
|
433
|
+
};
|
|
434
|
+
|
|
435
|
+
export const LoadAsyncDataComponent = () => {
|
|
436
|
+
// 创建异步数据加载器
|
|
437
|
+
const fetcher = createFetcher(loadAsyncData);
|
|
438
|
+
|
|
439
|
+
return (
|
|
440
|
+
<div>
|
|
441
|
+
{/* 成功返回时渲染 */}
|
|
442
|
+
<If when={fetcher.result}>
|
|
443
|
+
<For each={fetcher.result}>
|
|
444
|
+
</For>
|
|
445
|
+
</If>
|
|
446
|
+
{/* 加载时渲染 */}
|
|
447
|
+
<If when={fetcher.status === 'loading'}>
|
|
448
|
+
loading ...
|
|
449
|
+
</If>
|
|
450
|
+
</div>
|
|
451
|
+
);
|
|
452
|
+
};
|
|
453
|
+
```
|
|
454
|
+
|
|
455
|
+
可以配合`watch`实现当依赖数据发生变化时自动加载数据并渲染。
|
|
456
|
+
|
|
457
|
+
|
|
458
|
+
```tsx
|
|
459
|
+
import { If, createFetcher, reactive } from 'cdui-js';
|
|
460
|
+
|
|
461
|
+
export const LoadAsyncDataComponent = () => {
|
|
462
|
+
// 创建加载条件响应式数据
|
|
463
|
+
const state = reactive({ filter: '' });
|
|
464
|
+
// 创建异步数据加载器
|
|
465
|
+
const fetcher = createFetcher(() => { // 此处根据 state.filter 返回不同的结果 });
|
|
466
|
+
|
|
467
|
+
// 观测加载条件
|
|
468
|
+
watch(() => state.fitler, filter => {
|
|
469
|
+
// 此处根据 state.filter 重新加载数据
|
|
470
|
+
let ... = ...;
|
|
471
|
+
|
|
472
|
+
// 设置新数据到 fetcher,系统自动更新相应绑定
|
|
473
|
+
fetcher.result = ...;
|
|
474
|
+
});
|
|
475
|
+
|
|
476
|
+
return (
|
|
477
|
+
<div>
|
|
478
|
+
{/* 成功返回时渲染 */}
|
|
479
|
+
<If when={fetcher.result}>
|
|
480
|
+
<For each={fetcher.result}>
|
|
481
|
+
</For>
|
|
482
|
+
</If>
|
|
483
|
+
{/* 加载时渲染 */}
|
|
484
|
+
<If when={fetcher.status === 'loading'}>
|
|
485
|
+
loading ...
|
|
486
|
+
</If>
|
|
487
|
+
</div>
|
|
488
|
+
);
|
|
489
|
+
};
|
|
490
|
+
```
|