@doubao-dev/plugin-app-dev 0.0.0-stage → 0.0.40-canary-dea0ddc73-20261026073950

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.
Files changed (107) hide show
  1. package/README.md +10 -2
  2. package/dist/147.js +9 -0
  3. package/dist/assets.d.ts +5 -0
  4. package/dist/assets.js +4 -0
  5. package/dist/index.d.ts +43 -0
  6. package/dist/index.js +1378 -0
  7. package/dist/plugin.d.ts +102 -0
  8. package/dist/plugin.js +4995 -0
  9. package/dist/preview.js +16 -0
  10. package/dist/rslib-runtime.js +33 -0
  11. package/dist/skills/doubao-plugin-app/SKILL.md +21 -0
  12. package/dist/skills/doubao-plugin-app/references/app-development.md +85 -0
  13. package/dist/skills/doubao-plugin-app/references/frontend/components/container-overlay.md +131 -0
  14. package/dist/skills/doubao-plugin-app/references/frontend/components/form-controls.md +146 -0
  15. package/dist/skills/doubao-plugin-app/references/frontend/components/interactive-controls.md +120 -0
  16. package/dist/skills/doubao-plugin-app/references/frontend/components/map-canvas.md +107 -0
  17. package/dist/skills/doubao-plugin-app/references/frontend/components/overview.md +43 -0
  18. package/dist/skills/doubao-plugin-app/references/frontend/components/scroll-list.md +149 -0
  19. package/dist/skills/doubao-plugin-app/references/frontend/components/text-media.md +209 -0
  20. package/dist/skills/doubao-plugin-app/references/frontend/doubao-agentic-service-api/01-/345/237/272/347/241/200.md +1389 -0
  21. package/dist/skills/doubao-plugin-app/references/frontend/doubao-agentic-service-api/02-/347/263/273/347/273/237.md +1376 -0
  22. package/dist/skills/doubao-plugin-app/references/frontend/doubao-agentic-service-api/03-/350/207/252/345/256/232/344/271/211/351/200/232/344/277/241.md +127 -0
  23. package/dist/skills/doubao-plugin-app/references/frontend/doubao-agentic-service-api/04-/345/256/232/344/275/215.md +784 -0
  24. package/dist/skills/doubao-plugin-app/references/frontend/doubao-agentic-service-api/05-/345/255/230/345/202/250.md +1176 -0
  25. package/dist/skills/doubao-plugin-app/references/frontend/doubao-agentic-service-api/06-/350/267/257/347/224/261.md +839 -0
  26. package/dist/skills/doubao-plugin-app/references/frontend/doubao-agentic-service-api/07-/347/225/214/351/235/242.md +376 -0
  27. package/dist/skills/doubao-plugin-app/references/frontend/doubao-agentic-service-api/08-/344/272/244/344/272/222.md +1319 -0
  28. package/dist/skills/doubao-plugin-app/references/frontend/doubao-agentic-service-api/09-/350/276/223/345/205/245.md +192 -0
  29. package/dist/skills/doubao-plugin-app/references/frontend/doubao-agentic-service-api/10-/347/275/221/347/273/234.md +900 -0
  30. package/dist/skills/doubao-plugin-app/references/frontend/doubao-agentic-service-api/11-/345/252/222/344/275/223.md +1496 -0
  31. package/dist/skills/doubao-plugin-app/references/frontend/doubao-agentic-service-api/12-/344/270/232/345/212/241/350/203/275/345/212/233.md +1281 -0
  32. package/dist/skills/doubao-plugin-app/references/frontend/doubao-agentic-service-api/13-/347/231/273/345/275/225.md +511 -0
  33. package/dist/skills/doubao-plugin-app/references/frontend/doubao-agentic-service-api/14-/346/224/257/344/273/230.md +943 -0
  34. package/dist/skills/doubao-plugin-app/references/frontend/doubao-agentic-service-api/15-/346/225/260/346/215/256/345/210/206/346/236/220.md +124 -0
  35. package/dist/skills/doubao-plugin-app/references/frontend/doubao-agentic-service-api/16-/350/223/235/347/211/231.md +3364 -0
  36. package/dist/skills/doubao-plugin-app/references/frontend/doubao-agentic-service-api/17-wi-fi.md +1028 -0
  37. package/dist/skills/doubao-plugin-app/references/frontend/doubao-agentic-service-api/18-/345/212/240/351/200/237/345/272/246/350/256/241.md +354 -0
  38. package/dist/skills/doubao-plugin-app/references/frontend/doubao-agentic-service-api/19-ibeacon.md +508 -0
  39. package/dist/skills/doubao-plugin-app/references/frontend/doubao-agentic-service-api/20-/347/275/227/347/233/230.md +320 -0
  40. package/dist/skills/doubao-plugin-app/references/frontend/doubao-agentic-service-api/21-/350/256/276/345/244/207/346/226/271/345/220/221.md +351 -0
  41. package/dist/skills/doubao-plugin-app/references/frontend/doubao-agentic-service-api/22-/351/231/200/350/236/272/344/273/252.md +354 -0
  42. package/dist/skills/doubao-plugin-app/references/frontend/doubao-agentic-service-api/23-/345/252/222/344/275/223-/350/256/276/345/244/207-/347/275/221/347/273/234.md +264 -0
  43. package/dist/skills/doubao-plugin-app/references/frontend/doubao-agentic-service-api/24-/347/237/255/344/277/241.md +155 -0
  44. package/dist/skills/doubao-plugin-app/references/frontend/doubao-agentic-service-api/25-/346/227/240/351/232/234/347/242/215.md +144 -0
  45. package/dist/skills/doubao-plugin-app/references/frontend/doubao-agentic-service-api/26-/345/237/272/347/241/200/344/277/241/346/201/257.md +238 -0
  46. package/dist/skills/doubao-plugin-app/references/frontend/doubao-agentic-service-api/27-/347/224/265/346/261/240.md +235 -0
  47. package/dist/skills/doubao-plugin-app/references/frontend/doubao-agentic-service-api/28-/345/211/252/350/264/264/346/235/277.md +303 -0
  48. package/dist/skills/doubao-plugin-app/references/frontend/doubao-agentic-service-api/29-/345/212/240/345/257/206.md +126 -0
  49. package/dist/skills/doubao-plugin-app/references/frontend/doubao-agentic-service-api/30-/346/227/245/345/216/206.md +417 -0
  50. package/dist/skills/doubao-plugin-app/references/frontend/doubao-agentic-service-api/31-/347/224/265/350/257/235.md +144 -0
  51. package/dist/skills/doubao-plugin-app/references/frontend/doubao-agentic-service-api/32-/346/211/253/347/240/201.md +236 -0
  52. package/dist/skills/doubao-plugin-app/references/frontend/doubao-agentic-service-api/33-/345/261/217/345/271/225.md +747 -0
  53. package/dist/skills/doubao-plugin-app/references/frontend/doubao-agentic-service-api/34-/351/234/207/345/212/250.md +277 -0
  54. package/dist/skills/doubao-plugin-app/references/frontend/doubao-agentic-service-api/35-/346/226/207/344/273/266/347/263/273/347/273/237.md +431 -0
  55. package/dist/skills/doubao-plugin-app/references/frontend/doubao-agentic-service-api/common-errors.md +69 -0
  56. package/dist/skills/doubao-plugin-app/references/frontend/doubao-agentic-service-api/groups.md +43 -0
  57. package/dist/skills/doubao-plugin-app/references/frontend/doubao-agentic-service-api/quick-reference.md +436 -0
  58. package/dist/skills/doubao-plugin-app/references/frontend/examples/common-patterns.md +590 -0
  59. package/dist/skills/doubao-plugin-app/references/frontend/examples/doubao-agentic-service-api-recipes.md +209 -0
  60. package/dist/skills/doubao-plugin-app/references/frontend/examples/page-widget-basics.md +368 -0
  61. package/dist/skills/doubao-plugin-app/references/frontend/examples/page-widget-recipes.md +65 -0
  62. package/dist/skills/doubao-plugin-app/references/frontend/framework/core.md +283 -0
  63. package/dist/skills/doubao-plugin-app/references/frontend/guides/auth.md +277 -0
  64. package/dist/skills/doubao-plugin-app/references/frontend/guides/best-practices.md +574 -0
  65. package/dist/skills/doubao-plugin-app/references/frontend/guides/client-tools-and-events.md +209 -0
  66. package/dist/skills/doubao-plugin-app/references/frontend/guides/component-development.md +832 -0
  67. package/dist/skills/doubao-plugin-app/references/frontend/guides/debugger-mcp.md +537 -0
  68. package/dist/skills/doubao-plugin-app/references/frontend/guides/expired-widget.md +101 -0
  69. package/dist/skills/doubao-plugin-app/references/frontend/guides/performance-optimization.md +417 -0
  70. package/dist/skills/doubao-plugin-app/references/frontend/guides/troubleshooting.md +278 -0
  71. package/dist/skills/doubao-plugin-app/references/frontend/lynx/best-practices.md +720 -0
  72. package/dist/skills/doubao-plugin-app/references/frontend/lynx/css/pseudo-classes.md +149 -0
  73. package/dist/skills/doubao-plugin-app/references/frontend/lynx/css/selectors.md +224 -0
  74. package/dist/skills/doubao-plugin-app/references/frontend/lynx/css/supported-properties.md +269 -0
  75. package/dist/skills/doubao-plugin-app/references/frontend/lynx/css/values-and-units.md +314 -0
  76. package/dist/skills/doubao-plugin-app/references/frontend/lynx/layout/flex-layout.md +334 -0
  77. package/dist/skills/doubao-plugin-app/references/frontend/lynx/layout/grid-layout.md +408 -0
  78. package/dist/skills/doubao-plugin-app/references/frontend/lynx/layout/linear-layout.md +355 -0
  79. package/dist/skills/doubao-plugin-app/references/frontend/lynx/layout/relative-layout.md +189 -0
  80. package/dist/skills/doubao-plugin-app/references/frontend/lynx/lynx-vs-web/css-differences.md +737 -0
  81. package/dist/skills/doubao-plugin-app/references/frontend/lynx/lynx-vs-web/migration-guide.md +669 -0
  82. package/dist/skills/doubao-plugin-app/references/frontend/lynx/lynx-vs-web/unsupported-features.md +290 -0
  83. package/dist/skills/doubao-plugin-app/references/frontend/lynx/overview.md +60 -0
  84. package/dist/skills/doubao-plugin-app/references/frontend/lynx/patterns/animation.md +243 -0
  85. package/dist/skills/doubao-plugin-app/references/frontend/lynx/patterns/responsive.md +194 -0
  86. package/dist/skills/doubao-plugin-app/references/frontend/lynx/patterns/theming.md +143 -0
  87. package/dist/skills/doubao-plugin-app/references/frontend/lynx/quick-reference.md +229 -0
  88. package/dist/skills/doubao-plugin-app/references/frontend/rules/dos-and-donts.md +479 -0
  89. package/dist/skills/doubao-plugin-app/references/frontend/widget-templates/design-boundary.md +46 -0
  90. package/dist/skills/doubao-plugin-app/references/frontend/widget-templates/overview.md +118 -0
  91. package/dist/skills/doubao-plugin-app/references/frontend/widget-templates/props.md +301 -0
  92. package/dist/skills/doubao-plugin-app/references/mcp-and-cards.md +38 -0
  93. package/dist/templates/README.md.template +11 -0
  94. package/dist/templates/com.doubao/app/manifest.yaml +41 -0
  95. package/dist/templates/com.doubao/app/package.json.template +13 -0
  96. package/dist/templates/com.doubao/app/src/app.config.ts.template +5 -0
  97. package/dist/templates/com.doubao/app/src/app.ts.template +3 -0
  98. package/dist/templates/com.doubao/app/src/pages/home/index.css +14 -0
  99. package/dist/templates/com.doubao/app/src/pages/home/index.tsx.template +14 -0
  100. package/dist/templates/com.doubao/app/src/widgets/example/index.tsx.template +29 -0
  101. package/dist/templates/com.doubao/app/tsconfig.json +19 -0
  102. package/dist/templates/mcp.json +9 -0
  103. package/dist/templates/plugin.json.template +29 -0
  104. package/dist/templates/skills/example/SKILL.md.template +14 -0
  105. package/dist/upload.d.ts +44 -0
  106. package/dist/upload.js +38 -0
  107. package/package.json +60 -3
@@ -0,0 +1,590 @@
1
+ # 常用开发模式
2
+
3
+ API 集成、状态管理、页面导航的常用开发模式和最佳实践。
4
+
5
+ ---
6
+
7
+ ## 📋 目录
8
+
9
+ 1. [API 集成模式](#api-集成模式)
10
+ 2. [状态管理模式](#状态管理模式)
11
+ 3. [页面导航模式](#页面导航模式)
12
+
13
+ ---
14
+
15
+ ## 🌐 API 集成模式
16
+
17
+ ### 豆包应用插件的端能力 API 调用
18
+
19
+ 使用豆包应用插件的端能力 API 访问系统能力时,先确定调用位置和状态反馈。这些 API 也称 Open API,代码统一从
20
+ `@doubao-dev/framework/api` 导入;具体参数和返回类型以 [豆包应用插件的端能力 API 目录](../doubao-agentic-service-api/groups.md) 为准。
21
+ `request` 本身不是泛型函数,不要写 `request<T>()`;如果需要业务返回类型,先接收 `response`,再对
22
+ `response.data` 做类型收窄或断言。
23
+
24
+ ```tsx
25
+ import { useState } from '@doubao-dev/framework';
26
+ import { request } from '@doubao-dev/framework/api';
27
+
28
+ function getErrorMessage(error: unknown, fallback: string) {
29
+ return error instanceof Error ? error.message : fallback;
30
+ }
31
+
32
+ function DataFetchExample() {
33
+ const [data, setData] = useState<Record<string, unknown> | string | ArrayBuffer | null>(null);
34
+ const [loading, setLoading] = useState(false);
35
+ const [error, setError] = useState('');
36
+
37
+ const fetchData = async () => {
38
+ try {
39
+ setLoading(true);
40
+ setError('');
41
+
42
+ const response = await request({
43
+ url: 'https://api.example.com/data',
44
+ method: 'GET',
45
+ header: {
46
+ 'Content-Type': 'application/json'
47
+ }
48
+ });
49
+
50
+ const responseData = response.data;
51
+ setData(responseData ?? null);
52
+ } catch (err) {
53
+ setError(getErrorMessage(err, '获取数据失败'));
54
+ } finally {
55
+ setLoading(false);
56
+ }
57
+ };
58
+
59
+ return (
60
+ <view>
61
+ <button onClick={fetchData}>获取数据</button>
62
+ {loading && <text>加载中...</text>}
63
+ {error && <text>错误: {error}</text>}
64
+ {data && <text>数据: {JSON.stringify(data)}</text>}
65
+ </view>
66
+ );
67
+ }
68
+ ```
69
+
70
+ ### POST 请求示例
71
+
72
+ ```tsx
73
+ const submitForm = async (formData: Record<string, unknown>) => {
74
+ try {
75
+ const response = await request({
76
+ url: 'https://api.example.com/submit',
77
+ method: 'POST',
78
+ header: {
79
+ 'Content-Type': 'application/json'
80
+ },
81
+ data: formData
82
+ });
83
+
84
+ if (response.statusCode >= 200 && response.statusCode < 300) {
85
+ console.log('提交成功');
86
+ }
87
+ } catch (err) {
88
+ console.error('提交失败:', err);
89
+ }
90
+ };
91
+ ```
92
+
93
+ ### 请求拦截和错误处理
94
+
95
+ ```tsx
96
+ interface ApiError {
97
+ code: number;
98
+ message: string;
99
+ }
100
+
101
+ interface ApiRequestOptions {
102
+ method?: 'GET' | 'POST' | 'PUT' | 'DELETE';
103
+ header?: Record<string, string>;
104
+ data?: Record<string, unknown> | string | ArrayBuffer;
105
+ dataType?: 'json' | 'string';
106
+ }
107
+
108
+ function getResponseMessage(data: unknown) {
109
+ if (typeof data === 'object' && data !== null && 'message' in data) {
110
+ return String(data.message);
111
+ }
112
+ return '请求失败';
113
+ }
114
+
115
+ function isApiError(error: unknown): error is ApiError {
116
+ return typeof error === 'object' && error !== null && 'code' in error && 'message' in error;
117
+ }
118
+
119
+ async function apiRequest<T>(url: string, options: ApiRequestOptions): Promise<T> {
120
+ try {
121
+ const response = await request({
122
+ url,
123
+ ...options
124
+ });
125
+
126
+ // 检查响应状态
127
+ if (response.statusCode >= 400) {
128
+ throw {
129
+ code: response.statusCode,
130
+ message: getResponseMessage(response.data)
131
+ } as ApiError;
132
+ }
133
+
134
+ return response.data as T;
135
+ } catch (err) {
136
+ // 统一错误处理
137
+ if (isApiError(err) && err.code === 401) {
138
+ console.error('未授权,请登录');
139
+ } else if (isApiError(err) && err.code === 404) {
140
+ console.error('资源不存在');
141
+ } else {
142
+ console.error('请求错误:', getErrorMessage(err, '请求失败'));
143
+ }
144
+ throw err;
145
+ }
146
+ }
147
+
148
+ // 使用示例
149
+ async function fetchUserData(userId: string) {
150
+ try {
151
+ const data = await apiRequest<User>(`https://api.example.com/users/${userId}`, {
152
+ method: 'GET'
153
+ });
154
+ return data;
155
+ } catch (err) {
156
+ // 业务逻辑错误处理
157
+ return null;
158
+ }
159
+ }
160
+ ```
161
+
162
+ ### 豆包应用插件的端能力 API 使用配方
163
+
164
+ `common-patterns.md` 只保留通用调用结构。`getLocation`、Storage 等具体端能力的组合示例见
165
+ [doubao-agentic-service-api-recipes.md](./doubao-agentic-service-api-recipes.md);完整参数和返回类型见 [豆包应用插件的端能力 API 目录](../doubao-agentic-service-api/groups.md)。
166
+
167
+ ## 📊 状态管理模式
168
+
169
+ ### 1. 本地状态 (useState)
170
+
171
+ 适用于组件内部状态管理。
172
+
173
+ ```tsx
174
+ import { useState } from '@doubao-dev/framework';
175
+
176
+ function Counter() {
177
+ const [count, setCount] = useState(0);
178
+
179
+ return (
180
+ <view>
181
+ <text>计数: {count}</text>
182
+ <button onClick={() => setCount(count + 1)}>增加</button>
183
+ <button onClick={() => setCount(count - 1)}>减少</button>
184
+ <button onClick={() => setCount(0)}>重置</button>
185
+ </view>
186
+ );
187
+ }
188
+ ```
189
+
190
+ ### 2. 副作用管理 (useEffect)
191
+
192
+ 适用于数据获取、订阅、定时器等副作用。
193
+
194
+ ```tsx
195
+ import { useState, useEffect } from '@doubao-dev/framework';
196
+ import { request } from '@doubao-dev/framework/api';
197
+
198
+ function DataLoader() {
199
+ const [data, setData] = useState<Record<string, unknown> | string | ArrayBuffer | null>(null);
200
+ const [error, setError] = useState('');
201
+
202
+ useEffect(() => {
203
+ // 数据获取
204
+ const fetchData = async () => {
205
+ try {
206
+ setError('');
207
+ const response = await request({
208
+ url: 'https://api.example.com/data',
209
+ method: 'GET'
210
+ });
211
+ setData(response.data ?? null);
212
+ } catch (error) {
213
+ setError(error instanceof Error ? error.message : '获取数据失败');
214
+ }
215
+ };
216
+
217
+ void fetchData();
218
+
219
+ // 清理函数
220
+ return () => {
221
+ console.log('组件卸载,清理资源');
222
+ };
223
+ }, []); // 空依赖数组表示只在挂载时执行一次
224
+
225
+ if (error) {
226
+ return <view>{error}</view>;
227
+ }
228
+
229
+ return <view>{data ? <text>{JSON.stringify(data)}</text> : <text>加载中...</text>}</view>;
230
+ }
231
+ ```
232
+
233
+ ### 3. 复杂状态 (useReducer)
234
+
235
+ 适用于复杂状态逻辑。
236
+
237
+ ```tsx
238
+ import { useReducer } from '@doubao-dev/framework';
239
+
240
+ // 定义状态和动作类型
241
+ interface State {
242
+ count: number;
243
+ step: number;
244
+ }
245
+
246
+ type Action =
247
+ | { type: 'increment' }
248
+ | { type: 'decrement' }
249
+ | { type: 'setStep'; step: number }
250
+ | { type: 'reset' };
251
+
252
+ // Reducer 函数
253
+ function reducer(state: State, action: Action): State {
254
+ switch (action.type) {
255
+ case 'increment':
256
+ return { ...state, count: state.count + state.step };
257
+ case 'decrement':
258
+ return { ...state, count: state.count - state.step };
259
+ case 'setStep':
260
+ return { ...state, step: action.step };
261
+ case 'reset':
262
+ return { count: 0, step: 1 };
263
+ default:
264
+ return state;
265
+ }
266
+ }
267
+
268
+ function ComplexCounter() {
269
+ const [state, dispatch] = useReducer(reducer, { count: 0, step: 1 });
270
+
271
+ return (
272
+ <view>
273
+ <text>计数: {state.count}</text>
274
+ <text>步长: {state.step}</text>
275
+ <button onClick={() => dispatch({ type: 'increment' })}>增加</button>
276
+ <button onClick={() => dispatch({ type: 'decrement' })}>减少</button>
277
+ <button onClick={() => dispatch({ type: 'setStep', step: 5 })}>
278
+ 设置步长为 5
279
+ </button>
280
+ <button onClick={() => dispatch({ type: 'reset' })}>重置</button>
281
+ </view>
282
+ );
283
+ }
284
+ ```
285
+
286
+ ### 4. 跨组件状态共享 (Context)
287
+
288
+ 适用于全局或跨组件状态。
289
+
290
+ ```tsx
291
+ import { createContext, useContext, useState } from '@doubao-dev/framework';
292
+
293
+ // 1. 创建 Context
294
+ interface ThemeContextValue {
295
+ theme: 'light' | 'dark';
296
+ toggleTheme: () => void;
297
+ }
298
+
299
+ const ThemeContext = createContext<ThemeContextValue | null>(null);
300
+
301
+ // 2. Provider 组件
302
+ function ThemeProvider({ children }) {
303
+ const [theme, setTheme] = useState<'light' | 'dark'>('light');
304
+
305
+ const toggleTheme = () => {
306
+ setTheme(prev => (prev === 'light' ? 'dark' : 'light'));
307
+ };
308
+
309
+ return (
310
+ <ThemeContext.Provider value={{ theme, toggleTheme }}>
311
+ {children}
312
+ </ThemeContext.Provider>
313
+ );
314
+ }
315
+
316
+ // 3. 使用 Context
317
+ function ThemedButton() {
318
+ const context = useContext(ThemeContext);
319
+ if (!context) throw new Error('必须在 ThemeProvider 内使用');
320
+
321
+ const { theme, toggleTheme } = context;
322
+
323
+ return (
324
+ <button
325
+ className={theme === 'light' ? 'light-button' : 'dark-button'}
326
+ onClick={toggleTheme}
327
+ >
328
+ 切换主题
329
+ </button>
330
+ );
331
+ }
332
+
333
+ // 4. 应用中使用
334
+ function App() {
335
+ return (
336
+ <ThemeProvider>
337
+ <view>
338
+ <ThemedButton />
339
+ </view>
340
+ </ThemeProvider>
341
+ );
342
+ }
343
+ ```
344
+
345
+ ### 5. 自定义 Hook
346
+
347
+ 封装可复用的状态逻辑。
348
+
349
+ ```tsx
350
+ import { useState, useEffect } from '@doubao-dev/framework';
351
+ import { request } from '@doubao-dev/framework/api';
352
+
353
+ // 自定义 Hook:数据获取
354
+ function useFetch<T>(url: string) {
355
+ const [data, setData] = useState<T | null>(null);
356
+ const [loading, setLoading] = useState(true);
357
+ const [error, setError] = useState('');
358
+
359
+ useEffect(() => {
360
+ const fetchData = async () => {
361
+ try {
362
+ setLoading(true);
363
+ setError('');
364
+ const response = await request({ url, method: 'GET' });
365
+ setData(response.data as T);
366
+ } catch (err) {
367
+ setError(err instanceof Error ? err.message : '请求失败');
368
+ } finally {
369
+ setLoading(false);
370
+ }
371
+ };
372
+
373
+ void fetchData();
374
+ }, [url]);
375
+
376
+ return { data, loading, error };
377
+ }
378
+
379
+ // 使用自定义 Hook
380
+ function UserProfile({ userId }: { userId: string }) {
381
+ const { data: user, loading, error } = useFetch<User>(`https://api.example.com/users/${userId}`);
382
+
383
+ if (loading) return <text>加载中...</text>;
384
+ if (error) return <text>错误: {error}</text>;
385
+ if (!user) return <text>无数据</text>;
386
+
387
+ return (
388
+ <view>
389
+ <text>{user.name}</text>
390
+ <text>{user.email}</text>
391
+ </view>
392
+ );
393
+ }
394
+ ```
395
+
396
+ ---
397
+
398
+ ## 🧭 页面导航模式
399
+
400
+ ### 1. 打开新页面
401
+
402
+ ```tsx
403
+ import { navigateTo, redirectTo, reLaunch } from '@doubao-dev/framework/api';
404
+
405
+ // 保留当前页面,打开详情页
406
+ function openFullPage() {
407
+ navigateTo({
408
+ url: '/pages/user-profile/index?userId=12345'
409
+ });
410
+ }
411
+
412
+ // 替换当前页面
413
+ function openSettingsPage() {
414
+ redirectTo({
415
+ url: '/pages/settings/index'
416
+ });
417
+ }
418
+
419
+ // 清空页面栈并回到首页
420
+ function relaunchHome() {
421
+ reLaunch({
422
+ url: '/pages/home/index'
423
+ });
424
+ }
425
+ ```
426
+
427
+ 这里的 `url` 使用目标 Page 路径,通常和 `src/pages/<page-name>/index.tsx` 对应,例如
428
+ `/pages/detail/index`。如需传参,可继续拼接 query string。
429
+
430
+ ### 2. 页面间传参
431
+
432
+ ```tsx
433
+ import { navigateTo } from '@doubao-dev/framework/api';
434
+
435
+ function buildPageUrl(pagePath: string, params: Record<string, string | number | boolean>) {
436
+ const query = Object.entries(params)
437
+ .map(([key, value]) => `${encodeURIComponent(key)}=${encodeURIComponent(String(value))}`)
438
+ .join('&');
439
+
440
+ return query ? `${pagePath}?${query}` : pagePath;
441
+ }
442
+
443
+ // 发送方
444
+ function navigateWithParams() {
445
+ navigateTo({
446
+ url: buildPageUrl('/pages/detail/index', {
447
+ id: '123',
448
+ name: '商品名称',
449
+ price: 99.99
450
+ })
451
+ });
452
+ }
453
+
454
+ // 接收方 (src/pages/detail/index.tsx)
455
+ import { useViewData } from '@doubao-dev/framework';
456
+
457
+ interface DetailPageData {
458
+ id: string;
459
+ name: string;
460
+ price: number;
461
+ }
462
+
463
+ export default function DetailPage() {
464
+ const { id, name, price } = useViewData<DetailPageData>();
465
+
466
+ return (
467
+ <view>
468
+ <text>ID: {id}</text>
469
+ <text>名称: {name}</text>
470
+ <text>价格: {price}</text>
471
+ </view>
472
+ );
473
+ }
474
+ ```
475
+
476
+ ### 3. 返回上一页
477
+
478
+ ```tsx
479
+ import { navigateBack } from '@doubao-dev/framework/api';
480
+
481
+ function closeCurrentPage() {
482
+ navigateBack();
483
+ }
484
+ ```
485
+
486
+ ### 4. 页面栈管理
487
+
488
+ ```tsx
489
+ import { navigateBack } from '@doubao-dev/framework/api';
490
+
491
+ // 场景 1: 返回上一页
492
+ function goBack() {
493
+ navigateBack();
494
+ }
495
+
496
+ // 场景 2: 返回多级页面
497
+ function goBackTwoPages() {
498
+ navigateBack({ delta: 2 });
499
+ }
500
+ ```
501
+
502
+ ### 5. 页面生命周期导航处理
503
+
504
+ ```tsx
505
+ import { useDestroy, useHide, useShow } from '@doubao-dev/framework';
506
+
507
+ export default function Page() {
508
+ useShow(() => {
509
+ console.log('页面显示');
510
+ });
511
+ useHide(() => {
512
+ console.log('页面隐藏');
513
+ });
514
+ useDestroy(() => {
515
+ console.log('页面销毁');
516
+ });
517
+
518
+ return <view>页面内容</view>;
519
+ }
520
+ ```
521
+
522
+ ### 6. 九宫格页面导航
523
+
524
+ ```tsx
525
+ import { navigateTo } from '@doubao-dev/framework/api';
526
+
527
+ // 打开九宫格页面
528
+ function openGridPage() {
529
+ navigateTo({
530
+ url: '/pages/app-grid/index'
531
+ });
532
+ }
533
+
534
+ // 九宫格页面定义
535
+ export default function GridPage() {
536
+ const apps = [
537
+ { id: 'app1', name: '应用1', icon: '🎯', path: '/pages/app1/index' },
538
+ { id: 'app2', name: '应用2', icon: '📱', path: '/pages/app2/index' },
539
+ { id: 'app3', name: '应用3', icon: '⚡', path: '/pages/app3/index' }
540
+ ];
541
+
542
+ return (
543
+ <view className="grid-container">
544
+ {apps.map(app => (
545
+ <view key={app.id} className="grid-item" onClick={() => navigateTo({ url: app.path })}>
546
+ <text className="icon">{app.icon}</text>
547
+ <text className="name">{app.name}</text>
548
+ </view>
549
+ ))}
550
+ </view>
551
+ );
552
+ }
553
+ ```
554
+
555
+ ---
556
+
557
+ ## 🎯 最佳实践
558
+
559
+ ### API 集成
560
+
561
+ 1. **统一错误处理** - 封装 API 请求函数,统一处理错误
562
+ 2. **请求取消** - 组件卸载时取消未完成的请求
563
+ 3. **缓存策略** - 合理使用缓存减少网络请求
564
+ 4. **加载状态** - 始终提供加载和错误状态反馈
565
+
566
+ ### 状态管理
567
+
568
+ 1. **最小化状态** - 只存储必要的状态,能计算的不存储
569
+ 2. **状态提升** - 共享状态提升到最近的公共父组件
570
+ 3. **避免过度渲染** - 使用 useMemo、useCallback 优化性能
571
+ 4. **状态持久化** - 重要状态考虑持久化到本地存储
572
+
573
+ ### 页面导航
574
+
575
+ 1. **合理的页面层级** - 避免页面栈过深(建议不超过 3-4 层)
576
+ 2. **参数验证** - 接收页面参数时进行验证和默认值处理
577
+ 3. **返回结果** - 关闭页面时返回必要的结果数据
578
+ 4. **生命周期管理** - 合理使用生命周期钩子管理资源
579
+
580
+ ---
581
+
582
+ ## 📚 延伸阅读
583
+
584
+ - **Page/Widget 基础** → [./page-widget-basics.md](./page-widget-basics.md)
585
+ - **组件开发完整指南** → [../guides/component-development.md](../guides/component-development.md)
586
+ - **豆包应用插件的端能力 API 使用配方** → [./doubao-agentic-service-api-recipes.md](./doubao-agentic-service-api-recipes.md)
587
+ - **Page 组件配方** → [./page-widget-recipes.md](./page-widget-recipes.md)
588
+ - **Framework 核心入口、生命周期和 Hooks** → [../framework/core.md](../framework/core.md)
589
+ - **豆包应用插件的端能力 API 速查** → [../doubao-agentic-service-api/quick-reference.md](../doubao-agentic-service-api/quick-reference.md)
590
+ - **最佳实践** → [../guides/best-practices.md](../guides/best-practices.md)