1# 开发基于JS UI的卡片
2
3
4以下内容介绍基于类Web范式的JS UI卡片开发指南。
5
6
7## 运作机制
8
9卡片框架的运作机制如图1所示。
10
11**图1** 卡片框架运作机制(Stage模型)
12
13![JSCardPrinciple](figures/JSCardPrinciple.png)
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/>-&nbsp;true:默认卡片。<br/>-&nbsp;false:非默认卡片。 | 布尔值 | 否 |
203   | colorMode | 表示卡片的主题样式,取值范围如下:<br/>-&nbsp;auto:自适应。<br/>-&nbsp;dark:深色主题。<br/>-&nbsp;light:浅色主题。 | 字符串 | 可缺省,缺省值为“auto”。 |
204   | supportDimensions | 表示卡片支持的外观规格,取值范围:<br/>-&nbsp;1&nbsp;\*&nbsp;2:表示1行2列的二宫格。<br/>-&nbsp;2&nbsp;\*&nbsp;2:表示2行2列的四宫格。<br/>-&nbsp;2&nbsp;\*&nbsp;4:表示2行4列的八宫格。<br/>-&nbsp;4&nbsp;\*&nbsp;4:表示4行4列的十六宫格。 | 字符串数组 | 否 |
205   | defaultDimension | 表示卡片的默认外观规格,取值必须在该卡片supportDimensions配置的列表中。 | 字符串 | 否 |
206   | updateEnabled | 表示卡片是否支持周期性刷新,取值范围:<br/>-&nbsp;true:表示支持周期性刷新,可以在定时刷新(updateDuration)和定点刷新(scheduledUpdateTime)两种方式任选其一,优先选择定时刷新。<br/>-&nbsp;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![WidgetCardPage](figures/WidgetCardPage.png)
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-->