1# 开发基于JS UI的卡片 2 3 4以下内容介绍基于类Web范式的JS UI卡片开发指南。 5 6 7## 运作机制 8 9卡片框架的运作机制如图1所示。 10 11**图1** 卡片框架运作机制(Stage模型) 12 13 14 15卡片使用方包含以下模块: 16 17- 卡片使用:包含卡片的创建、删除、请求更新等操作。 18 19- 通信适配层:由OpenHarmony SDK提供,负责与卡片管理服务通信,用于将卡片的相关操作到卡片管理服务。 20 21卡片管理服务包含以下模块: 22 23- 周期性刷新:在卡片添加后,根据卡片的刷新策略启动定时任务周期性触发卡片的刷新。 24 25- 卡片缓存管理:在卡片添加到卡片管理服务后,对卡片的视图信息进行缓存,以便下次获取卡片时可以直接返回缓存数据,降低时延。 26 27- 卡片生命周期管理:对于卡片切换到后台或者被遮挡时,暂停卡片的刷新;以及卡片的升级/卸载场景下对卡片数据的更新和清理。 28 29- 卡片使用方对象管理:对卡片使用方的RPC对象进行管理,用于使用方请求进行校验以及对卡片更新后的回调处理。 30 31- 通信适配层:负责与卡片使用方和提供方进行RPC通信。 32 33卡片提供方包含以下模块: 34 35- 卡片服务:由卡片提供方开发者实现,开发者实现生命周期处理创建卡片、更新卡片以及删除卡片等请求,提供相应的卡片服务。 36 37- 卡片提供方实例管理模块:由卡片提供方开发者实现,负责对卡片管理服务分配的卡片实例进行持久化管理。 38 39- 通信适配层:由OpenHarmony SDK提供,负责与卡片管理服务通信,用于将卡片的更新数据主动推送到卡片管理服务。 40 41> **说明:** 42> 43> 实际开发时只需要作为卡片提供方进行卡片内容的开发,卡片使用方和卡片管理服务由系统自动处理。 44 45 46## 接口说明 47 48FormExtensionAbility类拥有如下API接口,具体的API介绍详见[接口文档](../reference/apis-form-kit/js-apis-app-form-formExtensionAbility.md)。 49 50| 接口名 | 描述 | 51| -------- | -------- | 52| onAddForm(want: Want): formBindingData.FormBindingData | 卡片提供方接收创建卡片的通知接口。 | 53| onCastToNormalForm(formId: string): void | 卡片提供方接收临时卡片转常态卡片的通知接口。 | 54| onUpdateForm(formId: string): void | 卡片提供方接收更新卡片的通知接口。 | 55| onChangeFormVisibility(newStatus: Record<string, number>): void | 卡片提供方接收修改可见性的通知接口。 | 56| onFormEvent(formId: string, message: string): void | 卡片提供方接收处理卡片事件的通知接口。 | 57| onRemoveForm(formId: string): void | 卡片提供方接收销毁卡片的通知接口。 | 58| onConfigurationUpdate(newConfig: Configuration): void | 当系统配置更新时调用。 | 59| onShareForm?(formId: string): Record<string, Object> | 卡片提供方接收卡片分享的通知接口。 | 60 61formProvider类有如下API接口,具体的API介绍详见[接口文档](../reference/apis-form-kit/js-apis-app-form-formProvider.md)。 62 63| 接口名 | 描述 | 64| -------- | -------- | 65| setFormNextRefreshTime(formId: string, minute: number, callback: AsyncCallback<void>): void | 设置指定卡片的下一次更新时间。 | 66| setFormNextRefreshTime(formId: string, minute: number): Promise<void> | 设置指定卡片的下一次更新时间,以promise方式返回。 | 67| updateForm(formId: string, formBindingData: formBindingData.FormBindingData, callback: AsyncCallback<void>): void | 更新指定的卡片。 | 68| updateForm(formId: string, formBindingData: formBindingData.FormBindingData): Promise<void> | 更新指定的卡片,以promise方式返回。 | 69 70formBindingData类有如下API接口,具体的API介绍详见[接口文档](../reference/apis-form-kit/js-apis-app-form-formBindingData.md)。 71 72| 接口名 | 描述 | 73| -------- | -------- | 74| createFormBindingData(obj?: Object \| string): FormBindingData | 创建一个FormBindingData对象。 | 75 76 77## 开发步骤 78 79Stage卡片开发,即基于[Stage模型](../application-models/stage-model-development-overview.md)的卡片提供方开发,主要涉及如下关键步骤: 80 81- [创建卡片FormExtensionAbility](#创建卡片formextensionability):卡片生命周期回调函数FormExtensionAbility开发。 82 83- [配置卡片配置文件](#配置卡片配置文件):配置应用配置文件module.json5和profile配置文件。 84 85- [卡片信息的持久化](#卡片信息的持久化):对卡片信息进行持久化管理。 86 87- [卡片数据交互](#卡片数据交互):通过updateForm更新卡片显示的信息。 88 89- [开发卡片页面](#开发卡片页面):使用HML+CSS+JSON开发JS卡片页面。 90 91- [开发卡片事件](#开发卡片事件):为卡片添加router事件和message事件。 92 93 94### 创建卡片FormExtensionAbility 95 96创建Stage模型的卡片,需实现FormExtensionAbility生命周期接口。先参考<!--RP1-->[DevEco Studio服务卡片开发指南](https://developer.huawei.com/consumer/cn/doc/harmonyos-guides-V5/ide-service-widget-V5)<!--RP1End-->生成服务卡片模板。 97 981. 在EntryFormAbility.ets中,导入相关模块。 99 ```ts 100 import { Want } from '@kit.AbilityKit'; 101 import { formBindingData, FormExtensionAbility, formInfo, formProvider } from '@kit.FormKit'; 102 import { hilog } from '@kit.PerformanceAnalysisKit'; 103 import { BusinessError } from '@kit.BasicServicesKit'; 104 105 const TAG: string = 'JsCardFormAbility'; 106 const DOMAIN_NUMBER: number = 0xFF00; 107 ``` 108 1092. 在EntryFormAbility.ets中,实现FormExtension生命周期接口。 110 111 ```ts 112 export default class EntryFormAbility extends FormExtensionAbility { 113 onAddForm(want: Want): formBindingData.FormBindingData { 114 hilog.info(DOMAIN_NUMBER, TAG, '[EntryFormAbility] onAddForm'); 115 // 使用方创建卡片时触发,提供方需要返回卡片数据绑定类 116 let obj: Record<string, string> = { 117 'title': 'titleOnCreate', 118 'detail': 'detailOnCreate' 119 }; 120 let formData: formBindingData.FormBindingData = formBindingData.createFormBindingData(obj); 121 return formData; 122 } 123 onCastToNormalForm(formId: string): void { 124 // 使用方将临时卡片转换为常态卡片触发,提供方需要做相应的处理 125 hilog.info(DOMAIN_NUMBER, TAG, '[EntryFormAbility] onCastToNormalForm'); 126 } 127 onUpdateForm(formId: string): void { 128 // 若卡片支持定时更新/定点更新/卡片使用方主动请求更新功能,则提供方需要重写该方法以支持数据更新 129 hilog.info(DOMAIN_NUMBER, TAG, '[EntryFormAbility] onUpdateForm'); 130 let obj: Record<string, string> = { 131 'title': 'titleOnUpdate', 132 'detail': 'detailOnUpdate' 133 }; 134 let formData: formBindingData.FormBindingData = formBindingData.createFormBindingData(obj); 135 formProvider.updateForm(formId, formData).catch((error: BusinessError) => { 136 hilog.info(DOMAIN_NUMBER, TAG, '[EntryFormAbility] updateForm, error:' + JSON.stringify(error)); 137 }); 138 } 139 onChangeFormVisibility(newStatus: Record<string, number>): void { 140 // 使用方发起可见或者不可见通知触发,提供方需要做相应的处理,仅系统应用生效 141 hilog.info(DOMAIN_NUMBER, TAG, '[EntryFormAbility] onChangeFormVisibility'); 142 //... 143 } 144 onFormEvent(formId: string, message: string): void { 145 // 若卡片支持触发事件,则需要重写该方法并实现对事件的触发 146 hilog.info(DOMAIN_NUMBER, TAG, '[EntryFormAbility] onFormEvent'); 147 } 148 onRemoveForm(formId: string): void { 149 // 删除卡片实例数据 150 hilog.info(DOMAIN_NUMBER, TAG, '[EntryFormAbility] onRemoveForm'); 151 //... 152 } 153 onAcquireFormState(want: Want): formInfo.FormState { 154 return formInfo.FormState.READY; 155 } 156 } 157 ``` 158 159> **说明:** 160> FormExtensionAbility不能常驻后台,即在卡片生命周期回调函数中无法处理长时间的任务。 161 162 163### 配置卡片配置文件 164 1651. 卡片需要在[module.json5配置文件](../quick-start/module-configuration-file.md)中的extensionAbilities标签下,配置ExtensionAbility相关信息。FormExtensionAbility需要填写metadata元信息标签,其中键名称为固定字符串"ohos.extension.form",资源为卡片的具体配置信息的索引。 166 配置示例如下: 167 168 169 ```json 170 { 171 "module": { 172 // ... 173 "extensionAbilities": [ 174 { 175 "name": "JsCardFormAbility", 176 "srcEntry": "./ets/jscardformability/JsCardFormAbility.ts", 177 "description": "$string:JSCardFormAbility_desc", 178 "label": "$string:JSCardFormAbility_label", 179 "type": "form", 180 "metadata": [ 181 { 182 "name": "ohos.extension.form", 183 "resource": "$profile:form_jscard_config" 184 } 185 ] 186 } 187 ] 188 } 189 } 190 ``` 191 1922. 卡片的具体配置信息。在上述FormExtensionAbility的元信息("metadata"配置项)中,可以指定卡片具体配置信息的资源索引。例如当resource指定为$profile:form_config时,会使用开发视图的resources/base/profile/目录下的form_config.json作为卡片profile配置文件。内部字段结构说明如下表所示。 193 194 **表1** 卡片profile配置文件 195 196 | 属性名称 | 含义 | 数据类型 | 是否可缺省 | 197 | -------- | -------- | -------- | -------- | 198 | name | 表示卡片的类名,字符串最大长度为127字节。 | 字符串 | 否 | 199 | description | 表示卡片的描述。取值可以是描述性内容,也可以是对描述性内容的资源索引,以支持多语言。字符串最大长度为255字节。 | 字符串 | 可缺省,缺省为空。 | 200 | src | 表示卡片对应的UI代码的完整路径。 | 字符串 | 否 | 201 | window | 用于定义与显示窗口相关的配置。 | 对象 | 可缺省。 | 202 | isDefault | 表示该卡片是否为默认卡片,每个UIAbility有且只有一个默认卡片。<br/>- true:默认卡片。<br/>- false:非默认卡片。 | 布尔值 | 否 | 203 | colorMode | 表示卡片的主题样式,取值范围如下:<br/>- auto:自适应。<br/>- dark:深色主题。<br/>- light:浅色主题。 | 字符串 | 可缺省,缺省值为“auto”。 | 204 | supportDimensions | 表示卡片支持的外观规格,取值范围:<br/>- 1 \* 2:表示1行2列的二宫格。<br/>- 2 \* 2:表示2行2列的四宫格。<br/>- 2 \* 4:表示2行4列的八宫格。<br/>- 4 \* 4:表示4行4列的十六宫格。 | 字符串数组 | 否 | 205 | defaultDimension | 表示卡片的默认外观规格,取值必须在该卡片supportDimensions配置的列表中。 | 字符串 | 否 | 206 | updateEnabled | 表示卡片是否支持周期性刷新,取值范围:<br/>- true:表示支持周期性刷新,可以在定时刷新(updateDuration)和定点刷新(scheduledUpdateTime)两种方式任选其一,优先选择定时刷新。<br/>- false:表示不支持周期性刷新。 | 布尔类型 | 否 | 207 | scheduledUpdateTime | 表示卡片的定点刷新的时刻,采用24小时制,精确到分钟。<br/>updateDuration参数优先级高于scheduledUpdateTime,两者同时配置时,以updateDuration配置的刷新时间为准。 | 字符串 | 可缺省,缺省值为“0:0”。 | 208 | updateDuration | 表示卡片定时刷新的更新周期,单位为30分钟,取值为自然数。<br/>当取值为0时,表示该参数不生效。<br/>当取值为正整数N时,表示刷新周期为30\*N分钟。<br/>updateDuration参数优先级高于scheduledUpdateTime,两者同时配置时,以updateDuration配置的刷新时间为准。 | 数值 | 可缺省,缺省值为“0”。 | 209 | formConfigAbility | 表示卡片的配置跳转链接,采用URI格式。 | 字符串 | 可缺省,缺省值为空。 | 210 | formVisibleNotify | 标识是否允许卡片使用卡片可见性通知。 | 字符串 | 可缺省,缺省值为空。 | 211 | metaData | 表示卡片的自定义信息,包含customizeData数组标签。 | 对象 | 可缺省,缺省值为空。 | 212 213 配置示例如下: 214 215 216 ```json 217 { 218 "forms": [ 219 { 220 "name": "WidgetJS", 221 "description": "$string:JSCardEntryAbility_desc", 222 "src": "./js/WidgetJS/pages/index/index", 223 "window": { 224 "designWidth": 720, 225 "autoDesignWidth": true 226 }, 227 "colorMode": "auto", 228 "isDefault": true, 229 "updateEnabled": true, 230 "scheduledUpdateTime": "10:30", 231 "updateDuration": 1, 232 "defaultDimension": "2*2", 233 "supportDimensions": [ 234 "2*2" 235 ] 236 } 237 ] 238 } 239 ``` 240 241 242### 卡片信息的持久化 243 244因大部分卡片提供方都不是常驻服务,只有在需要使用时才会被拉起获取卡片信息,且卡片管理服务支持对卡片进行多实例管理,卡片ID对应实例ID,因此若卡片提供方支持对卡片数据进行配置,则需要对卡片的业务数据按照卡片ID进行持久化管理,以便在后续获取、更新以及拉起时能获取到正确的卡片业务数据。 245 246 247```ts 248import { common, Want } from '@kit.AbilityKit'; 249import { hilog } from '@kit.PerformanceAnalysisKit'; 250import { formBindingData, FormExtensionAbility } from '@kit.FormKit'; 251import { BusinessError } from '@kit.BasicServicesKit'; 252import { preferences } from '@kit.ArkData'; 253 254const TAG: string = 'JsCardFormAbility'; 255const DATA_STORAGE_PATH: string = '/data/storage/el2/base/haps/form_store'; 256const DOMAIN_NUMBER: number = 0xFF00; 257 258let storeFormInfo = async (formId: string, formName: string, tempFlag: boolean, context: common.FormExtensionContext): Promise<void> => { 259 // 此处仅对卡片ID:formId,卡片名:formName和是否为临时卡片:tempFlag进行了持久化 260 let formInfo: Record<string, string | boolean | number> = { 261 'formName': formName, 262 'tempFlag': tempFlag, 263 'updateCount': 0 264 }; 265 try { 266 const storage: preferences.Preferences = await preferences.getPreferences(context, DATA_STORAGE_PATH); 267 // put form info 268 await storage.put(formId, JSON.stringify(formInfo)); 269 hilog.info(DOMAIN_NUMBER, TAG, `[EntryFormAbility] storeFormInfo, put form info successfully, formId: ${formId}`); 270 await storage.flush(); 271 } catch (err) { 272 hilog.error(DOMAIN_NUMBER, TAG, `[EntryFormAbility] failed to storeFormInfo, err: ${JSON.stringify(err as BusinessError)}`); 273 } 274} 275 276export default class JsCardFormAbility extends FormExtensionAbility { 277 onAddForm(want: Want): formBindingData.FormBindingData { 278 hilog.info(DOMAIN_NUMBER, TAG, '[JsCardFormAbility] onAddForm'); 279 280 if (want.parameters) { 281 let formId = JSON.stringify(want.parameters['ohos.extra.param.key.form_identity']); 282 let formName = JSON.stringify(want.parameters['ohos.extra.param.key.form_name']); 283 let tempFlag = want.parameters['ohos.extra.param.key.form_temporary'] as boolean; 284 // 将创建的卡片信息持久化,以便在下次获取/更新该卡片实例时进行使用 285 // 此接口请根据实际情况实现,具体请参考:FormExtAbility Stage模型卡片实例 286 storeFormInfo(formId, formName, tempFlag, this.context); 287 } 288 289 let obj: Record<string, string> = { 290 'title': 'titleOnCreate', 291 'detail': 'detailOnCreate' 292 }; 293 let formData: formBindingData.FormBindingData = formBindingData.createFormBindingData(obj); 294 return formData; 295 } 296} 297``` 298 299且需要适配onRemoveForm卡片删除通知接口,在其中实现卡片实例数据的删除。 300 301 302```ts 303import { common } from '@kit.AbilityKit'; 304import { hilog } from '@kit.PerformanceAnalysisKit'; 305import { FormExtensionAbility } from '@kit.FormKit'; 306import { BusinessError } from '@kit.BasicServicesKit'; 307import { preferences } from '@kit.ArkData'; 308 309const TAG: string = 'JsCardFormAbility'; 310const DATA_STORAGE_PATH: string = '/data/storage/el2/base/haps/form_store'; 311const DOMAIN_NUMBER: number = 0xFF00; 312 313let deleteFormInfo = async (formId: string, context: common.FormExtensionContext): Promise<void> => { 314 try { 315 const storage: preferences.Preferences = await preferences.getPreferences(context, DATA_STORAGE_PATH); 316 // del form info 317 await storage.delete(formId); 318 hilog.info(DOMAIN_NUMBER, TAG, `[EntryFormAbility] deleteFormInfo, del form info successfully, formId: ${formId}`); 319 await storage.flush(); 320 } catch (err) { 321 hilog.error(DOMAIN_NUMBER, TAG, `[EntryFormAbility] failed to deleteFormInfo, err: ${JSON.stringify(err as BusinessError)}`); 322 }; 323}; 324 325export default class JsCardFormAbility extends FormExtensionAbility { 326 onRemoveForm(formId: string): void { 327 // 删除卡片实例数据 328 hilog.info(DOMAIN_NUMBER, TAG, '[EntryFormAbility] onRemoveForm'); 329 // 删除之前持久化的卡片实例数据 330 // 此接口请根据实际情况实现,具体请参考:FormExtAbility Stage模型卡片实例 331 deleteFormInfo(formId, this.context); 332 } 333} 334``` 335 336具体的持久化方法可以参考[轻量级数据存储开发指导](../database/app-data-persistence-overview.md)。 337 338需要注意的是,卡片使用方在请求卡片时传递给提供方应用的Want数据中存在临时标记字段,表示此次请求的卡片是否为临时卡片: 339 340- 常态卡片:卡片使用方会持久化的卡片。 341 342- 临时卡片:卡片使用方不会持久化的卡片。 343 344由于临时卡片的数据具有非持久化的特殊性,某些场景例如卡片服务框架死亡重启,此时临时卡片数据在卡片管理服务中已经删除,且对应的卡片ID不会通知到提供方,所以卡片提供方需要自己负责清理长时间未删除的临时卡片数据。同时对应的卡片使用方可能会将之前请求的临时卡片转换为常态卡片。如果转换成功,卡片提供方也需要对对应的临时卡片ID进行处理,把卡片提供方记录的临时卡片数据转换为常态卡片数据,防止提供方在清理长时间未删除的临时卡片时,把已经转换为常态卡片的临时卡片信息删除,导致卡片信息丢失。 345 346 347### 卡片数据交互 348 349当卡片应用需要更新数据时(如触发了定时更新或定点更新),卡片应用获取最新数据,并调用updateForm()接口主动触发卡片的更新。 350 351 352```ts 353import { hilog } from '@kit.PerformanceAnalysisKit'; 354import { formBindingData, FormExtensionAbility, formProvider } from '@kit.FormKit'; 355import { BusinessError } from '@kit.BasicServicesKit'; 356 357const TAG: string = 'JsCardFormAbility'; 358const DOMAIN_NUMBER: number = 0xFF00; 359 360export default class EntryFormAbility extends FormExtensionAbility { 361 onUpdateForm(formId: string): void { 362 // 若卡片支持定时更新/定点更新/卡片使用方主动请求更新功能,则提供方需要重写该方法以支持数据更新 363 hilog.info(DOMAIN_NUMBER, TAG, '[EntryFormAbility] onUpdateForm'); 364 let obj: Record<string, string> = { 365 'title': 'titleOnUpdate', 366 'detail': 'detailOnUpdate' 367 }; 368 let formData: formBindingData.FormBindingData = formBindingData.createFormBindingData(obj); 369 formProvider.updateForm(formId, formData).catch((error: BusinessError) => { 370 hilog.info(DOMAIN_NUMBER, TAG, '[EntryFormAbility] updateForm, error:' + JSON.stringify(error)); 371 }); 372 } 373} 374``` 375 376 377### 开发卡片页面 378 379开发者可以使用类Web范式(HML+CSS+JSON)开发JS卡片页面。生成如下卡片页面,可以这样配置卡片页面文件: 380 381 382 383- HML:使用类Web范式的组件描述卡片的页面信息。 384 385 386 ```html 387 <div class="container"> 388 <stack> 389 <div class="container-img"> 390 <image src="/common/widget.png" class="bg-img"></image> 391 </div> 392 <div class="container-inner"> 393 <text class="title">{{title}}</text> 394 <text class="detail_text" onclick="routerEvent">{{detail}}</text> 395 </div> 396 </stack> 397 </div> 398 ``` 399 400- CSS:HML中类Web范式组件的样式信息。 401 402 403 ```css 404 .container { 405 flex-direction: column; 406 justify-content: center; 407 align-items: center; 408 } 409 410 .bg-img { 411 flex-shrink: 0; 412 height: 100%; 413 } 414 415 .container-inner { 416 flex-direction: column; 417 justify-content: flex-end; 418 align-items: flex-start; 419 height: 100%; 420 width: 100%; 421 padding: 12px; 422 } 423 424 .title { 425 font-size: 19px; 426 font-weight: bold; 427 color: white; 428 text-overflow: ellipsis; 429 max-lines: 1; 430 } 431 432 .detail_text { 433 font-size: 16px; 434 color: white; 435 opacity: 0.66; 436 text-overflow: ellipsis; 437 max-lines: 1; 438 margin-top: 6px; 439 } 440 ``` 441 442- JSON:卡片页面中的数据和事件交互。 443 444 445 ```json 446 { 447 "data": { 448 "title": "TitleDefault", 449 "detail": "TextDefault" 450 }, 451 "actions": { 452 "routerEvent": { 453 "action": "router", 454 "abilityName": "EntryAbility", 455 "params": { 456 "message": "add detail" 457 } 458 } 459 } 460 } 461 ``` 462 463 464### 开发卡片事件 465 466卡片支持为组件设置交互事件(action),包括router事件和message事件,其中router事件用于UIAbility跳转,message事件用于卡片开发人员自定义点击事件。 467 468关键步骤说明如下: 469 4701. 在HML中为组件设置onclick属性,其值对应到JSON文件的actions字段中。 471 4722. 设置router事件: 473 474 - action属性值为"router"。 475 - abilityName为跳转目标的UIAbility名(支持跳转FA模型的PageAbility组件和Stage模型的UIAbility组件),如目前DevEco Studio创建的Stage模型的UIAbility默认名为EntryAbility。 476 - params为传递给跳转目标UIAbility的自定义参数,可以按需填写。其值可以在目标UIAbility启动时的want中的parameters里获取。如Stage模型MainAbility的onCreate生命周期里的入参want的parameters字段下获取到配置的参数。 477 4783. 设置message事件: 479 480 - action属性值为"message"。 481 - params为message事件的用户自定义参数,可以按需填写。其值可以在卡片生命周期函数onFormEvent()中的message里获取。 482 483示例如下。 484 485- HML文件 486 487 488 ```html 489 <div class="container"> 490 <stack> 491 <div class="container-img"> 492 <image src="/common/CardWebImg.png" class="bg-img"></image> 493 <image src="/common/CardWebImgMatrix.png" 494 class="bottom-img"/> 495 </div> 496 <div class="container-inner"> 497 <text class="title" onclick="routerEvent">{{ title }}</text> 498 <text class="detail_text" onclick="messageEvent">{{ detail }}</text> 499 </div> 500 </stack> 501 </div> 502 ``` 503 504- CSS文件 505 506 507 ```css 508 .container { 509 flex-direction: column; 510 justify-content: center; 511 align-items: center; 512 } 513 514 .bg-img { 515 flex-shrink: 0; 516 height: 100%; 517 z-index: 1; 518 } 519 520 .bottom-img { 521 position: absolute; 522 width: 150px; 523 height: 56px; 524 top: 63%; 525 background-color: rgba(216, 216, 216, 0.15); 526 filter: blur(20px); 527 z-index: 2; 528 } 529 530 .container-inner { 531 flex-direction: column; 532 justify-content: flex-end; 533 align-items: flex-start; 534 height: 100%; 535 width: 100%; 536 padding: 12px; 537 } 538 539 .title { 540 font-family: HarmonyHeiTi-Medium; 541 font-size: 14px; 542 color: rgba(255, 255, 255, 0.90); 543 letter-spacing: 0.6px; 544 font-weight: 500; 545 width: 100%; 546 text-overflow: ellipsis; 547 max-lines: 1; 548 } 549 550 .detail_text { 551 ffont-family: HarmonyHeiTi; 552 font-size: 12px; 553 color: rgba(255, 255, 255, 0.60); 554 letter-spacing: 0.51px; 555 font-weight: 400; 556 text-overflow: ellipsis; 557 max-lines: 1; 558 margin-top: 6px; 559 width: 100%; 560 } 561 ``` 562 563- JSON文件 564 565 566 ```json 567 { 568 "data": { 569 "title": "TitleDefault", 570 "detail": "TextDefault" 571 }, 572 "actions": { 573 "routerEvent": { 574 "action": "router", 575 "abilityName": "JSCardEntryAbility", 576 "params": { 577 "info": "router info", 578 "message": "router message" 579 } 580 }, 581 "messageEvent": { 582 "action": "message", 583 "params": { 584 "detail": "message detail" 585 } 586 } 587 } 588 } 589 ``` 590 591 说明: 592 593 "data"中JSON Value支持多级嵌套数据,在更新数据时,需要注意携带完整数据。 594 595 例如:当前卡片显示07.18日Mr.Zhang的课程信息,示例如下。 596 ```ts 597 "data": { 598 "Day": "07.18", 599 "teacher": { 600 "name": "Mr.Zhang", 601 "course": "Math" 602 } 603 } 604 ``` 605 当卡片内容需要更新为07.18日Mr.Li的课程信息时,需要传递待更新的完整数据,不能只传递单个数据项,如只传name或只传course,示例如下。 606 ```ts 607 "teacher": { 608 "name": "Mr.Li", 609 "course": "English" 610 } 611 ``` 612 613 614- 在UIAbility中接收router事件并获取参数 615 616 617 ```ts 618 import UIAbility from '@ohos.app.ability.UIAbility'; 619 import AbilityConstant from '@ohos.app.ability.AbilityConstant'; 620 import Want from '@ohos.app.ability.Want'; 621 import hilog from '@ohos.hilog'; 622 623 const TAG: string = 'EtsCardEntryAbility'; 624 const DOMAIN_NUMBER: number = 0xFF00; 625 626 export default class EtsCardEntryAbility extends UIAbility { 627 onCreate(want: Want, launchParam: AbilityConstant.LaunchParam): void { 628 if (want.parameters) { 629 let params: Record<string, Object> = JSON.parse(JSON.stringify(want.parameters.params)); 630 // 获取router事件中传递的info参数 631 if (params.info === 'router info') { 632 // 执行业务逻辑 633 hilog.info(DOMAIN_NUMBER, TAG, `router info: ${params.info}`); 634 } 635 // 获取router事件中传递的message参数 636 if (params.message === 'router message') { 637 // 执行业务逻辑 638 hilog.info(DOMAIN_NUMBER, TAG, `router message: ${params.message}`); 639 } 640 } 641 } 642 }; 643 ``` 644 645- 在FormExtensionAbility中接收message事件并获取参数 646 647 648 ```ts 649 import FormExtension from '@ohos.app.form.FormExtensionAbility'; 650 import hilog from '@ohos.hilog'; 651 652 const TAG: string = 'FormAbility'; 653 const DOMAIN_NUMBER: number = 0xFF00; 654 655 export default class FormAbility extends FormExtension { 656 onFormEvent(formId: string, message: string): void { 657 // 若卡片支持触发事件,则需要重写该方法并实现对事件的触发 658 hilog.info(DOMAIN_NUMBER, TAG, '[EntryFormAbility] onFormEvent'); 659 // 获取message事件中传递的detail参数 660 let msg: Record<string, string> = JSON.parse(message); 661 if (msg.detail === 'message detail') { 662 // 执行业务逻辑 663 hilog.info(DOMAIN_NUMBER, TAG, 'message info:' + msg.detail); 664 } 665 } 666 }; 667 ``` 668<!--Del--> 669## 相关实例 670 671针对卡片开发,有以下相关实例可供参考: 672 673- [JS多设备自适应服务卡片(JS)(API9)](https://gitee.com/openharmony/applications_app_samples/tree/master/code/SuperFeature/Widget/AdaptiveServiceWidget) 674 675- [电影卡片(JS)(API9)](https://gitee.com/openharmony/codelabs/tree/master/Card/MovieCard) 676 677- [计步器卡片(JS)(API9)](https://gitee.com/openharmony/codelabs/tree/master/Card/StepsCardJS) 678<!--DelEnd-->