@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.
- package/README.md +10 -2
- package/dist/147.js +9 -0
- package/dist/assets.d.ts +5 -0
- package/dist/assets.js +4 -0
- package/dist/index.d.ts +43 -0
- package/dist/index.js +1378 -0
- package/dist/plugin.d.ts +102 -0
- package/dist/plugin.js +4995 -0
- package/dist/preview.js +16 -0
- package/dist/rslib-runtime.js +33 -0
- package/dist/skills/doubao-plugin-app/SKILL.md +21 -0
- package/dist/skills/doubao-plugin-app/references/app-development.md +85 -0
- package/dist/skills/doubao-plugin-app/references/frontend/components/container-overlay.md +131 -0
- package/dist/skills/doubao-plugin-app/references/frontend/components/form-controls.md +146 -0
- package/dist/skills/doubao-plugin-app/references/frontend/components/interactive-controls.md +120 -0
- package/dist/skills/doubao-plugin-app/references/frontend/components/map-canvas.md +107 -0
- package/dist/skills/doubao-plugin-app/references/frontend/components/overview.md +43 -0
- package/dist/skills/doubao-plugin-app/references/frontend/components/scroll-list.md +149 -0
- package/dist/skills/doubao-plugin-app/references/frontend/components/text-media.md +209 -0
- package/dist/skills/doubao-plugin-app/references/frontend/doubao-agentic-service-api/01-/345/237/272/347/241/200.md +1389 -0
- package/dist/skills/doubao-plugin-app/references/frontend/doubao-agentic-service-api/02-/347/263/273/347/273/237.md +1376 -0
- 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
- package/dist/skills/doubao-plugin-app/references/frontend/doubao-agentic-service-api/04-/345/256/232/344/275/215.md +784 -0
- package/dist/skills/doubao-plugin-app/references/frontend/doubao-agentic-service-api/05-/345/255/230/345/202/250.md +1176 -0
- package/dist/skills/doubao-plugin-app/references/frontend/doubao-agentic-service-api/06-/350/267/257/347/224/261.md +839 -0
- package/dist/skills/doubao-plugin-app/references/frontend/doubao-agentic-service-api/07-/347/225/214/351/235/242.md +376 -0
- package/dist/skills/doubao-plugin-app/references/frontend/doubao-agentic-service-api/08-/344/272/244/344/272/222.md +1319 -0
- package/dist/skills/doubao-plugin-app/references/frontend/doubao-agentic-service-api/09-/350/276/223/345/205/245.md +192 -0
- package/dist/skills/doubao-plugin-app/references/frontend/doubao-agentic-service-api/10-/347/275/221/347/273/234.md +900 -0
- package/dist/skills/doubao-plugin-app/references/frontend/doubao-agentic-service-api/11-/345/252/222/344/275/223.md +1496 -0
- 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
- package/dist/skills/doubao-plugin-app/references/frontend/doubao-agentic-service-api/13-/347/231/273/345/275/225.md +511 -0
- package/dist/skills/doubao-plugin-app/references/frontend/doubao-agentic-service-api/14-/346/224/257/344/273/230.md +943 -0
- 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
- package/dist/skills/doubao-plugin-app/references/frontend/doubao-agentic-service-api/16-/350/223/235/347/211/231.md +3364 -0
- package/dist/skills/doubao-plugin-app/references/frontend/doubao-agentic-service-api/17-wi-fi.md +1028 -0
- 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
- package/dist/skills/doubao-plugin-app/references/frontend/doubao-agentic-service-api/19-ibeacon.md +508 -0
- package/dist/skills/doubao-plugin-app/references/frontend/doubao-agentic-service-api/20-/347/275/227/347/233/230.md +320 -0
- 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
- 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
- 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
- package/dist/skills/doubao-plugin-app/references/frontend/doubao-agentic-service-api/24-/347/237/255/344/277/241.md +155 -0
- 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
- 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
- package/dist/skills/doubao-plugin-app/references/frontend/doubao-agentic-service-api/27-/347/224/265/346/261/240.md +235 -0
- 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
- package/dist/skills/doubao-plugin-app/references/frontend/doubao-agentic-service-api/29-/345/212/240/345/257/206.md +126 -0
- package/dist/skills/doubao-plugin-app/references/frontend/doubao-agentic-service-api/30-/346/227/245/345/216/206.md +417 -0
- package/dist/skills/doubao-plugin-app/references/frontend/doubao-agentic-service-api/31-/347/224/265/350/257/235.md +144 -0
- package/dist/skills/doubao-plugin-app/references/frontend/doubao-agentic-service-api/32-/346/211/253/347/240/201.md +236 -0
- package/dist/skills/doubao-plugin-app/references/frontend/doubao-agentic-service-api/33-/345/261/217/345/271/225.md +747 -0
- package/dist/skills/doubao-plugin-app/references/frontend/doubao-agentic-service-api/34-/351/234/207/345/212/250.md +277 -0
- 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
- package/dist/skills/doubao-plugin-app/references/frontend/doubao-agentic-service-api/common-errors.md +69 -0
- package/dist/skills/doubao-plugin-app/references/frontend/doubao-agentic-service-api/groups.md +43 -0
- package/dist/skills/doubao-plugin-app/references/frontend/doubao-agentic-service-api/quick-reference.md +436 -0
- package/dist/skills/doubao-plugin-app/references/frontend/examples/common-patterns.md +590 -0
- package/dist/skills/doubao-plugin-app/references/frontend/examples/doubao-agentic-service-api-recipes.md +209 -0
- package/dist/skills/doubao-plugin-app/references/frontend/examples/page-widget-basics.md +368 -0
- package/dist/skills/doubao-plugin-app/references/frontend/examples/page-widget-recipes.md +65 -0
- package/dist/skills/doubao-plugin-app/references/frontend/framework/core.md +283 -0
- package/dist/skills/doubao-plugin-app/references/frontend/guides/auth.md +277 -0
- package/dist/skills/doubao-plugin-app/references/frontend/guides/best-practices.md +574 -0
- package/dist/skills/doubao-plugin-app/references/frontend/guides/client-tools-and-events.md +209 -0
- package/dist/skills/doubao-plugin-app/references/frontend/guides/component-development.md +832 -0
- package/dist/skills/doubao-plugin-app/references/frontend/guides/debugger-mcp.md +537 -0
- package/dist/skills/doubao-plugin-app/references/frontend/guides/expired-widget.md +101 -0
- package/dist/skills/doubao-plugin-app/references/frontend/guides/performance-optimization.md +417 -0
- package/dist/skills/doubao-plugin-app/references/frontend/guides/troubleshooting.md +278 -0
- package/dist/skills/doubao-plugin-app/references/frontend/lynx/best-practices.md +720 -0
- package/dist/skills/doubao-plugin-app/references/frontend/lynx/css/pseudo-classes.md +149 -0
- package/dist/skills/doubao-plugin-app/references/frontend/lynx/css/selectors.md +224 -0
- package/dist/skills/doubao-plugin-app/references/frontend/lynx/css/supported-properties.md +269 -0
- package/dist/skills/doubao-plugin-app/references/frontend/lynx/css/values-and-units.md +314 -0
- package/dist/skills/doubao-plugin-app/references/frontend/lynx/layout/flex-layout.md +334 -0
- package/dist/skills/doubao-plugin-app/references/frontend/lynx/layout/grid-layout.md +408 -0
- package/dist/skills/doubao-plugin-app/references/frontend/lynx/layout/linear-layout.md +355 -0
- package/dist/skills/doubao-plugin-app/references/frontend/lynx/layout/relative-layout.md +189 -0
- package/dist/skills/doubao-plugin-app/references/frontend/lynx/lynx-vs-web/css-differences.md +737 -0
- package/dist/skills/doubao-plugin-app/references/frontend/lynx/lynx-vs-web/migration-guide.md +669 -0
- package/dist/skills/doubao-plugin-app/references/frontend/lynx/lynx-vs-web/unsupported-features.md +290 -0
- package/dist/skills/doubao-plugin-app/references/frontend/lynx/overview.md +60 -0
- package/dist/skills/doubao-plugin-app/references/frontend/lynx/patterns/animation.md +243 -0
- package/dist/skills/doubao-plugin-app/references/frontend/lynx/patterns/responsive.md +194 -0
- package/dist/skills/doubao-plugin-app/references/frontend/lynx/patterns/theming.md +143 -0
- package/dist/skills/doubao-plugin-app/references/frontend/lynx/quick-reference.md +229 -0
- package/dist/skills/doubao-plugin-app/references/frontend/rules/dos-and-donts.md +479 -0
- package/dist/skills/doubao-plugin-app/references/frontend/widget-templates/design-boundary.md +46 -0
- package/dist/skills/doubao-plugin-app/references/frontend/widget-templates/overview.md +118 -0
- package/dist/skills/doubao-plugin-app/references/frontend/widget-templates/props.md +301 -0
- package/dist/skills/doubao-plugin-app/references/mcp-and-cards.md +38 -0
- package/dist/templates/README.md.template +11 -0
- package/dist/templates/com.doubao/app/manifest.yaml +41 -0
- package/dist/templates/com.doubao/app/package.json.template +13 -0
- package/dist/templates/com.doubao/app/src/app.config.ts.template +5 -0
- package/dist/templates/com.doubao/app/src/app.ts.template +3 -0
- package/dist/templates/com.doubao/app/src/pages/home/index.css +14 -0
- package/dist/templates/com.doubao/app/src/pages/home/index.tsx.template +14 -0
- package/dist/templates/com.doubao/app/src/widgets/example/index.tsx.template +29 -0
- package/dist/templates/com.doubao/app/tsconfig.json +19 -0
- package/dist/templates/mcp.json +9 -0
- package/dist/templates/plugin.json.template +29 -0
- package/dist/templates/skills/example/SKILL.md.template +14 -0
- package/dist/upload.d.ts +44 -0
- package/dist/upload.js +38 -0
- package/package.json +60 -3
|
@@ -0,0 +1,479 @@
|
|
|
1
|
+
# 开发规则 - Do's and Don'ts
|
|
2
|
+
|
|
3
|
+
> 项目配置:下文 `defineAppConfig` 和 `appId` 示例适用于独立应用项目,沿用其配置要求。Plugin CLI 项目以根目录的 `plugin.json` 为标识,`src/` 位于 `com.doubao/app/` 下;`app.config.ts` 默认导出普通对象,不填写 `appId`,由 CLI 查询注入。配置示例以 `doubao-plugin-app` Skill 的应用开发指南为准,本文的组件、Hooks 和入口 metadata 用法共用。
|
|
4
|
+
|
|
5
|
+
Doubao Apps SDK 框架的开发规则和最佳实践。
|
|
6
|
+
|
|
7
|
+
新 Page / Widget 直接导出组件函数,并在组件内使用生命周期 Hooks。
|
|
8
|
+
|
|
9
|
+
---
|
|
10
|
+
|
|
11
|
+
## ✅ 推荐做法(Do's)
|
|
12
|
+
|
|
13
|
+
### 项目管理
|
|
14
|
+
|
|
15
|
+
#### ✅ 使用 pnpm 包管理器
|
|
16
|
+
```bash
|
|
17
|
+
# 推荐
|
|
18
|
+
pnpm install
|
|
19
|
+
pnpm add @doubao-dev/framework
|
|
20
|
+
|
|
21
|
+
# 不推荐(除非项目已使用 npm)
|
|
22
|
+
npm install
|
|
23
|
+
npm install @doubao-dev/framework
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
### 组件开发
|
|
28
|
+
|
|
29
|
+
#### ✅ 在 app.config.ts 配置 App 元信息
|
|
30
|
+
```ts
|
|
31
|
+
import { defineAppConfig } from '@doubao-dev/framework/config';
|
|
32
|
+
|
|
33
|
+
export default defineAppConfig({
|
|
34
|
+
appId: 'db_xxxxxx', // 独立应用项目填写;Plugin CLI 项目不填写
|
|
35
|
+
name: '我的豆包应用'
|
|
36
|
+
});
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
#### ✅ 需要稳定首页时在 app.config.ts 明确入口
|
|
40
|
+
```ts
|
|
41
|
+
// ✅ pages 数组第一项会作为首页(appletEntry)
|
|
42
|
+
import { defineAppConfig } from '@doubao-dev/framework/config';
|
|
43
|
+
|
|
44
|
+
export default defineAppConfig({
|
|
45
|
+
appId: 'db_xxxxxx', // 独立应用项目填写;Plugin CLI 项目不填写
|
|
46
|
+
name: '我的豆包应用',
|
|
47
|
+
pages: [
|
|
48
|
+
{
|
|
49
|
+
entry: 'pages/home/index',
|
|
50
|
+
title: '首页',
|
|
51
|
+
description: '应用默认打开的页面'
|
|
52
|
+
}
|
|
53
|
+
]
|
|
54
|
+
});
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
一级页面目录不写进 `pages` 也会自动发现;如果首页不是默认入口 `index`,或需要固定首页顺序,建议显式配置
|
|
58
|
+
`pages` 数组第一项。entry 必须写到 `index`,例如 `pages/home/index`。
|
|
59
|
+
|
|
60
|
+
#### ✅ 需要补充展示信息时在 app.config.ts 定义 metadata
|
|
61
|
+
```ts
|
|
62
|
+
// ✅ 好的做法
|
|
63
|
+
import { defineAppConfig } from '@doubao-dev/framework/config';
|
|
64
|
+
|
|
65
|
+
export default defineAppConfig({
|
|
66
|
+
appId: 'db_xxxxxx', // 独立应用项目填写;Plugin CLI 项目不填写
|
|
67
|
+
name: '我的豆包应用',
|
|
68
|
+
pages: [
|
|
69
|
+
{
|
|
70
|
+
entry: 'pages/user-profile/index',
|
|
71
|
+
title: '用户资料',
|
|
72
|
+
description: '展示和编辑用户个人资料'
|
|
73
|
+
}
|
|
74
|
+
]
|
|
75
|
+
});
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
```ts
|
|
79
|
+
// ❌ 不好的做法:缺少 title、description 等信息
|
|
80
|
+
import { defineAppConfig } from '@doubao-dev/framework/config';
|
|
81
|
+
|
|
82
|
+
export default defineAppConfig({
|
|
83
|
+
appId: 'db_xxxxxx', // 独立应用项目填写;Plugin CLI 项目不填写
|
|
84
|
+
name: '我的豆包应用',
|
|
85
|
+
pages: [
|
|
86
|
+
{
|
|
87
|
+
entry: 'pages/user-profile/index'
|
|
88
|
+
}
|
|
89
|
+
]
|
|
90
|
+
});
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
#### ✅ 多级目录必须显式声明 entry
|
|
94
|
+
```ts
|
|
95
|
+
// src/pages/account/demo/index.tsx
|
|
96
|
+
// src/widgets/order/detail/index.tsx
|
|
97
|
+
import { defineAppConfig } from '@doubao-dev/framework/config';
|
|
98
|
+
|
|
99
|
+
export default defineAppConfig({
|
|
100
|
+
appId: 'db_xxxxxx', // 独立应用项目填写;Plugin CLI 项目不填写
|
|
101
|
+
name: '我的豆包应用',
|
|
102
|
+
pages: [
|
|
103
|
+
// Page 只声明入口、不补 metadata 时,可以直接写字符串
|
|
104
|
+
'pages/account/demo/index',
|
|
105
|
+
{
|
|
106
|
+
entry: 'pages/account/settings/index',
|
|
107
|
+
title: '账号设置页'
|
|
108
|
+
}
|
|
109
|
+
],
|
|
110
|
+
widgets: [
|
|
111
|
+
{
|
|
112
|
+
entry: 'widgets/order/detail/index',
|
|
113
|
+
titleType: 'none'
|
|
114
|
+
},
|
|
115
|
+
{
|
|
116
|
+
entry: 'widgets/order/summary/index',
|
|
117
|
+
id: 'order-summary',
|
|
118
|
+
name: '订单摘要卡片',
|
|
119
|
+
titleType: 'none'
|
|
120
|
+
}
|
|
121
|
+
]
|
|
122
|
+
});
|
|
123
|
+
```
|
|
124
|
+
|
|
125
|
+
Page 使用由完整 entry 派生的 URL,例如 `pages/account/demo/index` 对应 `/pages/account/demo/index`。
|
|
126
|
+
Widget 如果不配置 `id`,默认取入口最后一级目录名,例如 `widgets/order/detail/index` 默认为 `detail`;该 ID
|
|
127
|
+
必须在应用内全局唯一。
|
|
128
|
+
|
|
129
|
+
#### ✅ 分离样式文件
|
|
130
|
+
```tsx
|
|
131
|
+
// ✅ 好的做法
|
|
132
|
+
// index.tsx
|
|
133
|
+
import './index.scss';
|
|
134
|
+
|
|
135
|
+
export default function Page() {
|
|
136
|
+
return <view className="container">内容</view>;
|
|
137
|
+
}
|
|
138
|
+
```
|
|
139
|
+
|
|
140
|
+
```scss
|
|
141
|
+
// index.scss
|
|
142
|
+
.container {
|
|
143
|
+
padding: 16px;
|
|
144
|
+
background: #fff;
|
|
145
|
+
}
|
|
146
|
+
```
|
|
147
|
+
|
|
148
|
+
```tsx
|
|
149
|
+
// ❌ 不好的做法
|
|
150
|
+
export default function Page() {
|
|
151
|
+
return <view style={{ padding: '16px', background: '#fff' }}>内容</view>;
|
|
152
|
+
}
|
|
153
|
+
```
|
|
154
|
+
|
|
155
|
+
#### ✅ Page 默认使用可滚动安全区布局
|
|
156
|
+
|
|
157
|
+
Page 默认按沉浸式全屏承载,内容会从顶部开始铺满。除地图、相机、视频、沉浸式大屏等明确不滚动的场景外,
|
|
158
|
+
普通全页默认使用垂直 `scroll-view` 作为根滚动容器,由内容区负责顶部安全距离和页面内边距,避免被状态栏和右上角胶囊按钮遮挡。
|
|
159
|
+
|
|
160
|
+
```tsx
|
|
161
|
+
// ✅ 好的做法:Page 根节点提供垂直滚动,内容区负责安全区和页面内边距
|
|
162
|
+
import './index.scss';
|
|
163
|
+
|
|
164
|
+
export default function DemoPage() {
|
|
165
|
+
return (
|
|
166
|
+
<scroll-view className="demo-page" scrollOrientation="vertical" enableScroll>
|
|
167
|
+
<view className="demo-page__content">
|
|
168
|
+
<view className="demo-page__header">
|
|
169
|
+
<text className="demo-page__title">页面标题</text>
|
|
170
|
+
</view>
|
|
171
|
+
<view className="demo-page__body">页面内容</view>
|
|
172
|
+
</view>
|
|
173
|
+
</scroll-view>
|
|
174
|
+
);
|
|
175
|
+
}
|
|
176
|
+
```
|
|
177
|
+
|
|
178
|
+
```scss
|
|
179
|
+
.demo-page {
|
|
180
|
+
height: 100vh;
|
|
181
|
+
background: #f7f8fa;
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
.demo-page__content {
|
|
185
|
+
min-height: 100%;
|
|
186
|
+
box-sizing: border-box;
|
|
187
|
+
padding: 88px 24px 32px;
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
.demo-page__header {
|
|
191
|
+
// 右上角通常有宿主胶囊按钮;标题或自定义操作区不要贴到右上角。
|
|
192
|
+
padding-right: 160px;
|
|
193
|
+
}
|
|
194
|
+
```
|
|
195
|
+
|
|
196
|
+
全页布局先串清三件事:谁占满视口、谁承接滚动、谁负责安全区和页面内边距。
|
|
197
|
+
内容超过首屏,或存在固定头部、大尺寸业务区时,先检查这条链路,再处理具体模块样式。
|
|
198
|
+
不要依赖内容自然撑高、普通 `view` 的 `overflow: scroll`,或让多个节点隐式争夺滚动和裁剪职责。
|
|
199
|
+
|
|
200
|
+
#### ✅ 复杂布局先定义边界和收缩语义
|
|
201
|
+
|
|
202
|
+
Page / Widget 中出现多层容器、固定尺寸模块、横向 grid / flex、卡片底部操作区或内置组件组合时,
|
|
203
|
+
都要先定义边界和收缩语义:哪个容器给出可用空间,哪个节点可以增长,哪个节点可以收缩、换行或独占一行,哪个节点不能越界。
|
|
204
|
+
元素被挤出、重叠或裁剪时,不要只给最里层补样式;通常要沿父子链路同时检查容器边界、盒模型、间距、固定尺寸和收缩能力。
|
|
205
|
+
|
|
206
|
+
- `button`、`switch`、`slider`、`input` 等内置组件通常自带最小尺寸、内边距和交互态样式;放入横向布局时,要按有固有尺寸的内容处理。
|
|
207
|
+
- 固定尺寸的业务模块要和外层可用空间一起设计,避免尺寸、边距和边框叠加后把父容器撑出。
|
|
208
|
+
- 多列、多按钮或图文混排时,优先明确容器和子项的收缩、换行或独占一行策略,再处理视觉细节。
|
|
209
|
+
|
|
210
|
+
#### ✅ 使用 TypeScript 类型定义
|
|
211
|
+
```tsx
|
|
212
|
+
// ✅ 好的做法
|
|
213
|
+
interface UserInfo {
|
|
214
|
+
name: string;
|
|
215
|
+
age: number;
|
|
216
|
+
avatar?: string;
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
export default function UserWidget() {
|
|
220
|
+
const viewData = useViewData<UserInfo>();
|
|
221
|
+
return <view>{viewData.name}</view>;
|
|
222
|
+
}
|
|
223
|
+
```
|
|
224
|
+
|
|
225
|
+
```ts
|
|
226
|
+
// ✅ 把 metadata 写到 src/app.config.ts
|
|
227
|
+
import { defineAppConfig } from '@doubao-dev/framework/config';
|
|
228
|
+
|
|
229
|
+
export default defineAppConfig({
|
|
230
|
+
appId: 'db_xxxxxx', // 独立应用项目填写;Plugin CLI 项目不填写
|
|
231
|
+
name: '我的豆包应用',
|
|
232
|
+
widgets: [
|
|
233
|
+
{
|
|
234
|
+
entry: 'widgets/user-card/index',
|
|
235
|
+
id: 'user-card',
|
|
236
|
+
name: '用户卡片',
|
|
237
|
+
description: '用户信息卡片',
|
|
238
|
+
titleType: 'none'
|
|
239
|
+
}
|
|
240
|
+
]
|
|
241
|
+
});
|
|
242
|
+
```
|
|
243
|
+
|
|
244
|
+
```tsx
|
|
245
|
+
// ❌ 不好的做法
|
|
246
|
+
export default function UserWidget() {
|
|
247
|
+
// 错误:类型和实际任务字段不匹配
|
|
248
|
+
const viewData = useViewData<{ title: string }>();
|
|
249
|
+
return <view>{viewData.name}</view>;
|
|
250
|
+
}
|
|
251
|
+
```
|
|
252
|
+
|
|
253
|
+
#### ✅ 使用生命周期钩子
|
|
254
|
+
```tsx
|
|
255
|
+
// ✅ 好的做法
|
|
256
|
+
import { useDestroy, useHide, useShow } from '@doubao-dev/framework';
|
|
257
|
+
|
|
258
|
+
export default function Page() {
|
|
259
|
+
useShow(() => console.log('Page shown'));
|
|
260
|
+
useHide(() => console.log('Page hidden'));
|
|
261
|
+
useDestroy(() => console.log('Page destroyed'));
|
|
262
|
+
|
|
263
|
+
return <view>内容</view>;
|
|
264
|
+
}
|
|
265
|
+
```
|
|
266
|
+
|
|
267
|
+
|
|
268
|
+
#### ✅ 错误处理和边界情况
|
|
269
|
+
```tsx
|
|
270
|
+
// ✅ 好的做法
|
|
271
|
+
export default function ItemsWidget() {
|
|
272
|
+
const viewData = useViewData<{ items: string[] }>();
|
|
273
|
+
if (!viewData.items || viewData.items.length === 0) {
|
|
274
|
+
return <view>暂无数据</view>;
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
return (
|
|
278
|
+
<view>
|
|
279
|
+
{viewData.items.map((item, index) => (
|
|
280
|
+
<view key={index}>{item}</view>
|
|
281
|
+
))}
|
|
282
|
+
</view>
|
|
283
|
+
);
|
|
284
|
+
}
|
|
285
|
+
```
|
|
286
|
+
|
|
287
|
+
```tsx
|
|
288
|
+
// ❌ 不好的做法
|
|
289
|
+
export default function ItemsWidget() {
|
|
290
|
+
const viewData = useViewData<{ items?: string[] }>();
|
|
291
|
+
// 没有检查 viewData.items 是否存在
|
|
292
|
+
return <view>{viewData.items.map(item => <view>{item}</view>)}</view>;
|
|
293
|
+
}
|
|
294
|
+
```
|
|
295
|
+
|
|
296
|
+
|
|
297
|
+
|
|
298
|
+
## ❌ 禁止做法(Don'ts)
|
|
299
|
+
|
|
300
|
+
### 样式相关
|
|
301
|
+
|
|
302
|
+
#### ❌ 不在 TSX 中写 style 对象
|
|
303
|
+
|
|
304
|
+
样式统一写到 `index.scss`,TSX 中通过 `className` 切换状态。不要把 Web 写法里的内联 style 对象迁移过来。
|
|
305
|
+
|
|
306
|
+
```tsx
|
|
307
|
+
// ❌ 错误:内联 style 对象
|
|
308
|
+
<view style={{ width: 100, height: 56, fontSize: 14 }} />
|
|
309
|
+
|
|
310
|
+
// ✅ 正确:使用 className
|
|
311
|
+
<view className="profile-card" />
|
|
312
|
+
```
|
|
313
|
+
|
|
314
|
+
```scss
|
|
315
|
+
.profile-card {
|
|
316
|
+
width: 100px;
|
|
317
|
+
height: 56px;
|
|
318
|
+
font-size: 14px;
|
|
319
|
+
}
|
|
320
|
+
```
|
|
321
|
+
|
|
322
|
+
#### ❌ 不写内联样式
|
|
323
|
+
```tsx
|
|
324
|
+
// ❌ 错误
|
|
325
|
+
export default function Page() {
|
|
326
|
+
return <view style={{ padding: 16, background: '#fff' }}>内容</view>;
|
|
327
|
+
}
|
|
328
|
+
```
|
|
329
|
+
|
|
330
|
+
```tsx
|
|
331
|
+
// ✅ 正确
|
|
332
|
+
import './index.scss';
|
|
333
|
+
|
|
334
|
+
export default function Page() {
|
|
335
|
+
return <view className="container">内容</view>;
|
|
336
|
+
}
|
|
337
|
+
```
|
|
338
|
+
|
|
339
|
+
### 异步操作
|
|
340
|
+
|
|
341
|
+
#### ❌ 不在 render 中发起请求
|
|
342
|
+
```tsx
|
|
343
|
+
// ❌ 错误 - 每次渲染都会发请求
|
|
344
|
+
import { request } from '@doubao-dev/framework/api';
|
|
345
|
+
|
|
346
|
+
export default function Page() {
|
|
347
|
+
void request({ url: 'https://api.example.com/data', method: 'GET' });
|
|
348
|
+
return <view>内容</view>;
|
|
349
|
+
}
|
|
350
|
+
```
|
|
351
|
+
|
|
352
|
+
```tsx
|
|
353
|
+
// ✅ 推荐 - 使用 Hook 管理请求和状态
|
|
354
|
+
import { useEffect, useState } from '@doubao-dev/framework';
|
|
355
|
+
import { request } from '@doubao-dev/framework/api';
|
|
356
|
+
|
|
357
|
+
export default function UserPage() {
|
|
358
|
+
const [userData, setUserData] = useState<{ name?: string } | null>(null);
|
|
359
|
+
const [error, setError] = useState('');
|
|
360
|
+
|
|
361
|
+
useEffect(() => {
|
|
362
|
+
const loadUser = async () => {
|
|
363
|
+
try {
|
|
364
|
+
setError('');
|
|
365
|
+
const response = await request({ url: 'https://api.example.com/data', method: 'GET' });
|
|
366
|
+
setUserData(response.data as { name?: string });
|
|
367
|
+
} catch (caughtError) {
|
|
368
|
+
setError(caughtError instanceof Error ? caughtError.message : '请求失败');
|
|
369
|
+
}
|
|
370
|
+
};
|
|
371
|
+
|
|
372
|
+
void loadUser();
|
|
373
|
+
}, []);
|
|
374
|
+
|
|
375
|
+
if (error) {
|
|
376
|
+
return <view>{error}</view>;
|
|
377
|
+
}
|
|
378
|
+
|
|
379
|
+
return <view>{userData?.name}</view>;
|
|
380
|
+
}
|
|
381
|
+
```
|
|
382
|
+
|
|
383
|
+
### 组件结构
|
|
384
|
+
|
|
385
|
+
#### ❌ 不过度嵌套组件
|
|
386
|
+
```tsx
|
|
387
|
+
// ❌ 错误 - 过度嵌套
|
|
388
|
+
export default function Page() {
|
|
389
|
+
return (
|
|
390
|
+
<view>
|
|
391
|
+
<view>
|
|
392
|
+
<view>
|
|
393
|
+
<view>
|
|
394
|
+
<view>
|
|
395
|
+
<view>内容</view>
|
|
396
|
+
</view>
|
|
397
|
+
</view>
|
|
398
|
+
</view>
|
|
399
|
+
</view>
|
|
400
|
+
</view>
|
|
401
|
+
);
|
|
402
|
+
}
|
|
403
|
+
```
|
|
404
|
+
|
|
405
|
+
```tsx
|
|
406
|
+
// ✅ 正确 - 扁平结构
|
|
407
|
+
export default function Page() {
|
|
408
|
+
return (
|
|
409
|
+
<view className="page">
|
|
410
|
+
<view className="header">头部</view>
|
|
411
|
+
<view className="content">内容</view>
|
|
412
|
+
<view className="footer">底部</view>
|
|
413
|
+
</view>
|
|
414
|
+
);
|
|
415
|
+
}
|
|
416
|
+
```
|
|
417
|
+
|
|
418
|
+
### 类型使用
|
|
419
|
+
|
|
420
|
+
#### ❌ 不忽略 TypeScript 类型
|
|
421
|
+
```tsx
|
|
422
|
+
// ❌ 错误
|
|
423
|
+
export default function UserWidget() {
|
|
424
|
+
const viewData = useViewData<{ name: string }>();
|
|
425
|
+
// @ts-ignore
|
|
426
|
+
return <view>{viewData.unknownProperty}</view>;
|
|
427
|
+
}
|
|
428
|
+
```
|
|
429
|
+
|
|
430
|
+
```tsx
|
|
431
|
+
// ✅ 正确
|
|
432
|
+
interface UserInfo {
|
|
433
|
+
name: string;
|
|
434
|
+
age: number;
|
|
435
|
+
}
|
|
436
|
+
|
|
437
|
+
export default function UserWidget() {
|
|
438
|
+
const viewData = useViewData<UserInfo>();
|
|
439
|
+
return <view>{viewData.name}</view>;
|
|
440
|
+
}
|
|
441
|
+
```
|
|
442
|
+
|
|
443
|
+
### 状态管理
|
|
444
|
+
|
|
445
|
+
#### ❌ 不在全局作用域定义状态
|
|
446
|
+
```tsx
|
|
447
|
+
// ❌ 错误 - 全局变量会在多个实例间共享
|
|
448
|
+
let count = 0;
|
|
449
|
+
|
|
450
|
+
export default function CounterWidget() {
|
|
451
|
+
count++; // 所有实例共享这个 count
|
|
452
|
+
return <view>Count: {count}</view>;
|
|
453
|
+
}
|
|
454
|
+
```
|
|
455
|
+
|
|
456
|
+
```tsx
|
|
457
|
+
// ✅ 推荐 - 使用组件内状态,实例之间互不影响
|
|
458
|
+
import { useState } from '@doubao-dev/framework';
|
|
459
|
+
|
|
460
|
+
export default function CounterWidget() {
|
|
461
|
+
const [count, setCount] = useState(0);
|
|
462
|
+
|
|
463
|
+
return (
|
|
464
|
+
<view
|
|
465
|
+
onClick={() => {
|
|
466
|
+
setCount(prev => prev + 1);
|
|
467
|
+
}}
|
|
468
|
+
>
|
|
469
|
+
Count: {count}
|
|
470
|
+
</view>
|
|
471
|
+
);
|
|
472
|
+
}
|
|
473
|
+
```
|
|
474
|
+
|
|
475
|
+
## 📚 相关文档
|
|
476
|
+
|
|
477
|
+
- [组件开发指南](../guides/component-development.md)
|
|
478
|
+
- [最佳实践](../guides/best-practices.md)
|
|
479
|
+
- [性能优化](../guides/performance-optimization.md)
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
# Widget 模板定制边界
|
|
2
|
+
|
|
3
|
+
对话流 Widget 必须使用平台模板,最外层直接返回模板组件。模板不支持 `children`,不能自行实现卡片外壳。此约束针对 Widget,普通 Page 可按页面规范开发。
|
|
4
|
+
|
|
5
|
+
模板卡片由固定外壳、标题栏、内容区和操作区组成。回答“能否这样配”时,以当前 [props.md](props.md) 的公开 props 为准,不根据相近卡型或历史实现猜测字段。
|
|
6
|
+
|
|
7
|
+
## 判断顺序
|
|
8
|
+
|
|
9
|
+
1. 先按 [overview.md](overview.md) 的选型决策选择当前卡型。
|
|
10
|
+
2. 检查该卡型是否已有对应的 props、列表项字段或事件回调。
|
|
11
|
+
3. 现有 Props 无法表达内容时,通过开发者平台提交反馈;不要自行拼装模板结构。
|
|
12
|
+
4. 需要新增外壳结构、标题栏区域或底部操作区能力时,视为模板边界外需求,通过开发者平台反馈所需的新模板或设计能力。
|
|
13
|
+
|
|
14
|
+
## 允许的定制
|
|
15
|
+
|
|
16
|
+
- 通过 `header` 配置标题栏及右侧操作。
|
|
17
|
+
- 通过 `footer` 配置一个主按钮和一个次按钮;只传一个按钮时占据整行。
|
|
18
|
+
- 通过现有回调补充根节点或列表项的业务行为;不支持自定义 `className` / `style`。
|
|
19
|
+
- 使用模板已有的列表项类型表达重复数据,并传稳定 `key`。
|
|
20
|
+
|
|
21
|
+
## 具名内容槽位
|
|
22
|
+
|
|
23
|
+
- 文本槽位仅允许字符串、数字,或直接传 primitive `Tag` / `Title`。
|
|
24
|
+
- `action` 只接受模板定义的标准操作配置,不接受 ReactNode。
|
|
25
|
+
- `thumbnail` / `image` 优先使用对应 URL 字段;直接单个 `<image />` 或 `<svg />` 可用于媒体内容。
|
|
26
|
+
- 业务组件、fragment、原生布局容器、叠层及 primitive 外的业务包装属于自定义 UI,不作为绕过模板结构的方式。
|
|
27
|
+
- 跨业务复用的视觉单元应新增为 template primitive;可用组件以 `primitives` 实际导出为准。
|
|
28
|
+
|
|
29
|
+
ReactNode / ReactElement 只描述值的类别,不代表允许任意 JSX。Kit 的 Web / Lynx JSX 构建流程会检查可静态识别的槽位元素、样式入口和 widget 根节点,输出包含文件、行列和字段路径的 `[卡片检查]` warning,不改变运行时渲染,也不阻断构建。跨文件数据和无法解析的动态表达式存在检查盲区;没有 warning 不代表符合规范。
|
|
30
|
+
|
|
31
|
+
## 不应绕过的边界
|
|
32
|
+
|
|
33
|
+
- 不要在 Widget 或其依赖的业务组件中导入自定义 CSS、SCSS、Sass、Less、Stylus(含 CSS Modules)覆盖模板。构建检查会沿 Widget 模块依赖链输出 `widget.styles` warning;平台模板、组件和框架包自身的样式放行,普通 Page 独有样式不受此规则限制。构建器无法解析的运行时样式加载不在该检查范围内。
|
|
34
|
+
- 不要在模板外再包一层 `view` 或 `scroll-view` 来重建卡片外壳。
|
|
35
|
+
- 不要把底部操作区扩展为第三个按钮,或用绝对定位伪造额外区域。
|
|
36
|
+
- 不要通过未公开的类名、历史 props 或其他卡型字段改变模板结构。
|
|
37
|
+
- 不要为了展示更多内容自行假设模板会折叠、截断或重排行数;以对应 props 的行为说明为准。
|
|
38
|
+
|
|
39
|
+
## 处理结果
|
|
40
|
+
|
|
41
|
+
| 诉求 | 处理方式 |
|
|
42
|
+
|------|----------|
|
|
43
|
+
| 当前 props 可直接表达 | 直接使用对应字段,并遵循其类型和事件语义 |
|
|
44
|
+
| 当前 Props 无法表达内容 | 不额外包裹节点,通过开发者平台提交反馈 |
|
|
45
|
+
| 需要不同的卡片意图 | 回到选型决策,选择更匹配的现有模板 |
|
|
46
|
+
| 需要新的结构或操作区 | 明确说明当前模板不支持,通过开发者平台提交新模板或设计需求 |
|
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
# 豆包 Widget Template Library 参考
|
|
2
|
+
|
|
3
|
+
`@doubao-dev/template` 是面向 widget 开发的卡片模板库。模板已经把标题栏、内容区、信息区、价格和操作按钮等结构组合好,开发者只需要选模板并传业务数据。
|
|
4
|
+
|
|
5
|
+
## 核心规则
|
|
6
|
+
|
|
7
|
+
1. **一个 widget 一张卡片**:入口组件直接 return 模板组件,不要再包 `view` / `scroll-view`。
|
|
8
|
+
2. **统一从 `@doubao-dev/template` 导入**模板组件和类型;新 Widget 默认直接导出组件函数。
|
|
9
|
+
3. **必须使用模板**:先按选型表找模板并使用其公开 Props;匹配不上时按模板能力或新设计需求确认。
|
|
10
|
+
4. **使用模板公开字段**:只使用当前模板的结构化字段或已声明的具名内容字段(文本使用字符串、数字、Tag / Title,媒体使用 image / svg);一个业务语义需要多个已知模块时使用 `CompositeCard`,没有匹配字段时按模板能力或新设计需求确认。
|
|
11
|
+
5. **显式标注列表类型**:每个模板导出 `XxxProps` 和列表项类型,例如 `ContentCardItem`、`CheckoutCardProductItem`。
|
|
12
|
+
6. **header/footer 统一约定**:带标题栏和底部操作区的模板统一使用 `header` / `footer`。`header` 只控制标题栏,`footer` 只控制底部按钮,二者不影响内容区展示数量。
|
|
13
|
+
7. **底部按钮对象**:`footer.primaryActionButton` / `footer.secondaryActionButton` 内传 `text`、`onClick`、`disabled`、`loading`、`throttle`。只传一个按钮时占据整行。
|
|
14
|
+
8. **模板边界是强约束**:对话流 Widget 必须使用平台模板,否则无法通过审核。现有模板无法满足需求时,通过开发者平台提交反馈,不以业务诉求为由自行实现模板外的布局或样式。
|
|
15
|
+
9. **内容槽位受限并接受构建检查**:模板不支持 `children`。ReactNode / ReactElement 类型不代表可以传任意 JSX;具名内容槽位只允许对应白名单,详见 [design-boundary.md](design-boundary.md)。
|
|
16
|
+
|
|
17
|
+
`Title`、`Tag`、`Icon`、`OptionGroup` 和 `Price` 是卡片内容中的业务单元,不参与根卡片选型;需要标题、标签、图标、结构化选项集合或价格排版时从 `@doubao-dev/template/primitives` 导入使用。
|
|
18
|
+
|
|
19
|
+
## 选型决策顺序
|
|
20
|
+
|
|
21
|
+
按业务意图依次判断:
|
|
22
|
+
|
|
23
|
+
1. 一个业务语义需要组合多个模板已知模块,且没有完全匹配的具名模板:用 `CompositeCard`。
|
|
24
|
+
2. 核对并提交订单:通用商品、机票或出行票务订单都使用 `CheckoutCard`。
|
|
25
|
+
3. 展示地图、路线、位置或叫车状态:用 `MapCard`。
|
|
26
|
+
4. 展示多条交通行程:用 `TransitCard`。
|
|
27
|
+
5. 在多个报价、权益或服务方案中选择:用 `PriceActionCard`。
|
|
28
|
+
6. 展示并使用优惠券:用 `CouponCard`。
|
|
29
|
+
7. 让用户在候选项中确认或执行固定跳转:用 `AskHumanCard`;单个或两个全宽跳转项使用 `variant="jump"`。
|
|
30
|
+
8. 其余图文、商品或服务列表:用 `ContentCard`。
|
|
31
|
+
|
|
32
|
+
不能按以上意图选型时,不要直接拼新的卡片外壳。先查 `CompositeCard` 的 section 白名单;白名单仍无法表达时,将其作为模板能力或新设计需求确认。
|
|
33
|
+
|
|
34
|
+
## Widget 骨架
|
|
35
|
+
|
|
36
|
+
```tsx
|
|
37
|
+
import { ContentCard, type ContentCardItem } from '@doubao-dev/template';
|
|
38
|
+
|
|
39
|
+
const items: ContentCardItem[] = [
|
|
40
|
+
{
|
|
41
|
+
key: 'a',
|
|
42
|
+
title: '主标题',
|
|
43
|
+
subtitle: '4199 元 | 商品描述',
|
|
44
|
+
description: '补充描述',
|
|
45
|
+
thumbnailSrc: 'https://example.com/p.png'
|
|
46
|
+
}
|
|
47
|
+
];
|
|
48
|
+
|
|
49
|
+
export default function ProductCard() {
|
|
50
|
+
return (
|
|
51
|
+
<ContentCard
|
|
52
|
+
items={items}
|
|
53
|
+
footer={{
|
|
54
|
+
secondaryActionButton: {
|
|
55
|
+
text: '查看更多',
|
|
56
|
+
onClick: () => console.log('view more')
|
|
57
|
+
},
|
|
58
|
+
primaryActionButton: {
|
|
59
|
+
text: '立即下单',
|
|
60
|
+
onClick: () => console.log('submit')
|
|
61
|
+
}
|
|
62
|
+
}}
|
|
63
|
+
/>
|
|
64
|
+
);
|
|
65
|
+
}
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
## 选型指南
|
|
69
|
+
|
|
70
|
+
按“卡片要表达什么”选模板:
|
|
71
|
+
|
|
72
|
+
| 场景 | 模板 | 一句话 |
|
|
73
|
+
|------|------|--------|
|
|
74
|
+
| 地图路线/位置/叫车状态 | `MapCard` | 固定高度地图 + 来源标识,可配信息区、紧凑操作和底部操作区 |
|
|
75
|
+
| 商品/服务/内容列表 | `ContentCard` | 通用图文列表项,每项可带副标题、缩略内容和右侧操作 |
|
|
76
|
+
| 多条可操作报价/权益/结果 | `PriceActionCard` | 每行左价格 + 中信息 + 右按钮,可配底部操作区 |
|
|
77
|
+
| 优惠券展示与使用 | `CouponCard` | 根据券数量自动切换单券、双券或可横向滚动的多券布局 |
|
|
78
|
+
| 下单/支付确认(通用电商) | `CheckoutCard` | 商品摘要 + 提单信息 + 费用汇总 + 合计 + 操作按钮 |
|
|
79
|
+
| 机票/出行下单确认 | `CheckoutCard` | 商品或票务摘要 + 订单信息 + 费用明细 + 合计 + 操作按钮 |
|
|
80
|
+
| 交通票务推荐列表 | `TransitCard` | 多条出发/到达行程,全量展示 items |
|
|
81
|
+
| 车票预订等复合业务 | `CompositeCard` | 在一个标准卡片外壳中按顺序组合行程、选项组等已知模块 |
|
|
82
|
+
| 让用户在多个候选里人工确认 | `AskHumanCard` | 一组可点击选项,跳过入口也通过 items 表达 |
|
|
83
|
+
| 单个全宽操作按钮(任务态) | `AskHumanCard`(`variant="jump"`) | 一个可带右箭头的全宽按钮 |
|
|
84
|
+
|
|
85
|
+
## 通用约定
|
|
86
|
+
|
|
87
|
+
- **`header`**:标题栏配置,常用 `actionText` / `showAction` / `onActionClick`。
|
|
88
|
+
- **`footer`**:底部操作区配置,常用 `primaryActionButton` / `secondaryActionButton`。
|
|
89
|
+
- **`CompositeCard.sections`**:单层有序数组,只接受白名单 `type`,不接受任意 JSX;复用模块保留原有内容留白,`OptionGroup` 在组合卡内由专用容器补充左右 12px、下方 16px,上方不额外留白。
|
|
90
|
+
- **图片资源**:传运行时可访问的图片 URL;本地图片放到业务项目 `src/assets` 后静态 `import` 再传入,不要直接写 `'/assets/xxx.png'`。`ContentCard` 普通缩略图使用 `thumbnailSrc`,需要媒体节点时使用 `thumbnail`,且节点优先。
|
|
91
|
+
- **`onClick`**:作用在卡片根节点。卡片、列表项和 primitives 均不支持 `className` / `style`。
|
|
92
|
+
- **列表项 `key`**:不传默认用数组下标,建议显式传稳定 key。
|
|
93
|
+
- **行数限制**:`PriceActionCard.infoRows` 最多展示前 2 行;`ContentCard` 和 `TransitCard` 不再根据 footer 折叠内容。
|
|
94
|
+
- **地图布局**:`MapCard` 统一管理地图的 168px 高度;地图覆盖物通过 `mapProps.children` 传入,不使用卡片 `children`。
|
|
95
|
+
|
|
96
|
+
## 详细 Props 参考
|
|
97
|
+
|
|
98
|
+
每个模板完整 props、列表项字段、行为约束见 [props.md](props.md)。先查选型表锁定模板,再到该文件确认字段。
|
|
99
|
+
|
|
100
|
+
## 定制边界
|
|
101
|
+
|
|
102
|
+
回答“能否这样配置”时,先确认当前 props 是否支持。没有对应 props 或明确内容槽位的结构性需求,不要通过额外包裹节点或样式覆盖伪造,按模板能力或新设计需求处理。底部操作区最多包含一个主按钮和一个次按钮。
|
|
103
|
+
|
|
104
|
+
详见 [design-boundary.md](design-boundary.md)。
|
|
105
|
+
|
|
106
|
+
## 常见错误
|
|
107
|
+
|
|
108
|
+
| 错误 | 修正 |
|
|
109
|
+
|------|------|
|
|
110
|
+
| `render` 里把模板包在 `view` / `scroll-view` 里 | 直接 `return <XxxCard ... />` |
|
|
111
|
+
| 想做卡片却手写 `view`+`text`+`image` 拼布局 | 先查选型表和公开 Props;没有内容槽位时按新模板或设计需求确认 |
|
|
112
|
+
| 用 `children` 或额外 `view` 拼接行程和乘车人选择 | 使用 `CompositeCard`,配置 `transit`、`content` 与 `option-group` sections |
|
|
113
|
+
| 继续传 `moreText` / `primaryActionText` / `secondaryActionText` | 改为 `header.actionText` 和 `footer.primaryActionButton` / `footer.secondaryActionButton` |
|
|
114
|
+
| 需要单个全宽跳转操作 | 使用 `AskHumanCard variant="jump"` 和一个 `items` 项 |
|
|
115
|
+
| 列表项不传 `key` 导致更新错乱 | 给每个 item 传稳定 key |
|
|
116
|
+
| 用 `onClick` 当整卡和按钮的混用回调 | 底部按钮用 `footer.*ActionButton.onClick`,列表项右侧按钮用对应 action 的回调;`onClick` 是整卡或列表项点击 |
|
|
117
|
+
| 期望 `TransitCard` 自动折叠 4 条以上内容 | 模板全量展示 `items`,需要折叠时由业务先处理数据并通过 footer 提供入口 |
|
|
118
|
+
| 从 `react` import 模板/类型 | 模板组件与类型从 `@doubao-dev/template` 导入 |
|