最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

HarmonyOS服務(wù)卡片開發(fā)之JS卡片開發(fā)實(shí)例代碼

 更新時(shí)間:2026年07月09日 09:40:15   作者:大師兄6668  
服務(wù)卡片是一種界面展示形式,可以將應(yīng)用的重要信息或操作前置到卡片,以達(dá)到服務(wù)直達(dá)、減少體驗(yàn)層級的目的,這篇文章主要介紹了HarmonyOS服務(wù)卡片開發(fā)之JS卡片開發(fā)的相關(guān)資料,需要的朋友可以參考下

前言

ArkTS 卡片是主流,但還有一種更老的方案——JS 卡片,基于 HML + CSS + JS 開發(fā),風(fēng)格跟前端三件套很像。雖然華為推薦用 ArkTS,但一些老項(xiàng)目還在用 JS 卡片,理解它有必要。

今天基于 JSForm 項(xiàng)目,把 JS 卡片的開發(fā)方式講清楚。

JS 卡片 vs ArkTS 卡片

先說區(qū)別,免得搞混:

對比項(xiàng)JS 卡片ArkTS 卡片
卡片 UI 語法HML + CSS + JSArkTS(.ets 文件)
數(shù)據(jù)綁定{{變量名}} 模板語法@LocalStorageProp
交互事件@click="funcName"postCardAction()
文件位置js/卡片名/pages/widget/pages/
uiSyntax 配置"hml""arkts"
推薦程度老項(xiàng)目維護(hù)新項(xiàng)目首選

項(xiàng)目結(jié)構(gòu)

JSForm/
└── entry/src/main/
    ├── ets/
    │   ├── entryability/
    │   │   └── EntryAbility.ets         ← 主 UIAbility,處理 router 跳轉(zhuǎn)
    │   └── jscardformability/
    │       └── JsCardFormAbility.ets    ← 卡片提供方 FormExtensionAbility
    ├── js/
    │   └── jscard/                      ← JS 卡片目錄(名稱要和配置一致)
    │       └── pages/
    │           └── index/
    │               ├── index.hml        ← 卡片 UI(類似 HTML)
    │               ├── index.css        ← 卡片樣式
    │               └── index.js         ← 卡片邏輯
    └── module.json5

第一步:配置 module.json5

JS 卡片的 type 和 ArkTS 卡片一樣,都是 "form",區(qū)別在卡片配置文件里:

// entry/src/main/module.json5
{
  "module": {
    "extensionAbilities": [
      {
        "name": "JsCardFormAbility",
        "srcEntry": "./ets/jscardformability/JsCardFormAbility.ets",
        "description": "$string:JSCardFormAbility_desc",
        "label": "$string:JSCardFormAbility_label",
        "type": "form",
        "metadata": [
          {
            "name": "ohos.extension.form",
            "resource": "$profile:form_jscard_config"  // 指向 JS 卡片配置文件
          }
        ]
      }
    ]
  }
}

JS 卡片配置文件 resources/base/profile/form_jscard_config.json

{
  "forms": [
    {
      "name": "jscard",
      "displayName": "$string:jscard_display_name",
      "description": "$string:jscard_desc",
      "src": "./js/jscard/pages/index/index.hml",  // JS 卡片入口文件
      "uiSyntax": "hml",                            // 關(guān)鍵:JS 卡片填 "hml"
      "window": {
        "designWidth": 720,
        "autoDesignWidth": true
      },
      "isDefault": true,
      "updateEnabled": true,
      "updateDuration": 1,             // 每30分鐘刷新一次
      "supportDimensions": ["2*2"],
      "defaultDimension": "2*2"
    }
  ]
}

第二步:寫 HML 卡片頁面

HML 類似簡化版 HTML,支持?jǐn)?shù)據(jù)綁定和事件綁定:

<!-- entry/src/main/js/jscard/pages/index/index.hml -->
<div class="container">
  <!-- 雙花括號綁定數(shù)據(jù) -->
  <text class="title">{{title}}</text>
  <text class="detail">{{detail}}</text>

  <!-- click 事件,觸發(fā) JS 里的函數(shù) -->
  <div class="btn-area" @click="onClickRouter">
    <text class="btn-text">打開應(yīng)用</text>
  </div>

  <!-- message 事件按鈕 -->
  <div class="btn-area" @click="onClickMessage">
    <text class="btn-text">發(fā)送消息</text>
  </div>
</div>

第三步:寫 CSS 樣式

/* entry/src/main/js/jscard/pages/index/index.css */
.container {
  width: 100%;
  height: 100%;
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  padding: 12px 16px;
  background-color: #1A1A2E;
}

.title {
  font-size: 16px;
  color: #FFFFFF;
  opacity: 0.9;
  max-lines: 1;
  text-overflow: ellipsis;
  margin-bottom: 6px;
}

.detail {
  font-size: 12px;
  color: #FFFFFF;
  opacity: 0.6;
  max-lines: 2;
  text-overflow: ellipsis;
}

.btn-area {
  width: 120px;
  height: 32px;
  background-color: #FFFFFF;
  border-radius: 16px;
  margin-top: 12px;
  display: flex;
  align-items: center;
  justify-content: center;
}

.btn-text {
  font-size: 12px;
  color: #45A6F4;
}

第四步:寫 JS 邏輯

JS 卡片里觸發(fā)事件用的是 this.$app.$def.postCardAction,語法和 ArkTS 的 postCardAction 不同:

// entry/src/main/js/jscard/pages/index/index.js
export default {
  // 初始數(shù)據(jù)
  data: {
    title: 'titleOnCreate',   // 和 FormAbility 傳的字段名對應(yīng)
    detail: 'detailOnCreate'
  },

  // 點(diǎn)擊觸發(fā) router 事件,跳轉(zhuǎn)到應(yīng)用
  onClickRouter() {
    this.$app.$def.postCardAction({
      action: 'router',                  // 跳轉(zhuǎn)到 UIAbility
      abilityName: 'EntryAbility',       // 目標(biāo) UIAbility
      params: {
        info: 'router info',             // EntryAbility.onCreate 里能拿到
        message: 'router message'
      }
    });
  },

  // 點(diǎn)擊觸發(fā) message 事件,讓 FormAbility 處理
  onClickMessage() {
    this.$app.$def.postCardAction({
      action: 'message',
      params: {
        detail: 'message detail'         // JsCardFormAbility.onFormEvent 里能拿到
      }
    });
  }
}

第五步:FormAbility 處理生命周期

JS 卡片和 ArkTS 卡片共用同一個(gè) FormExtensionAbility,生命周期回調(diào)完全一樣:

// entry/src/main/ets/jscardformability/JsCardFormAbility.ets
import { common, Want } from '@kit.AbilityKit';
import { hilog } from '@kit.PerformanceAnalysisKit';
import { formBindingData, FormExtensionAbility, formProvider } from '@kit.FormKit';
import { BusinessError } from '@kit.BasicServicesKit';
import { preferences } from '@kit.ArkData';

const TAG = 'JsCardFormAbility';
const DOMAIN_NUMBER = 0xFF00;
const DATA_STORAGE_PATH = '/data/storage/el2/base/haps/form_store';

// 持久化卡片信息(formId -> formName)
let storeFormInfo = async (
  formId: string,
  formName: string,
  tempFlag: boolean,
  context: common.FormExtensionContext
): Promise<void> => {
  const formInfo: Record<string, string | boolean | number> = {
    'formName': formName,
    'tempFlag': tempFlag,
    'updateCount': 0
  };
  try {
    const storage: preferences.Preferences =
      await preferences.getPreferences(context, DATA_STORAGE_PATH);
    await storage.put(formId, JSON.stringify(formInfo));
    await storage.flush();
    hilog.info(DOMAIN_NUMBER, TAG, `卡片信息已持久化, formId: ${formId}`);
  } catch (err) {
    hilog.error(DOMAIN_NUMBER, TAG, `持久化失敗: ${JSON.stringify(err as BusinessError)}`);
  }
};

// 刪除持久化的卡片信息
let deleteFormInfo = async (
  formId: string,
  context: common.FormExtensionContext
): Promise<void> => {
  try {
    const storage = await preferences.getPreferences(context, DATA_STORAGE_PATH);
    await storage.delete(formId);
    await storage.flush();
    hilog.info(DOMAIN_NUMBER, TAG, `卡片信息已刪除, formId: ${formId}`);
  } catch (err) {
    hilog.error(DOMAIN_NUMBER, TAG, `刪除失敗: ${JSON.stringify(err as BusinessError)}`);
  }
};

export default class JsCardFormAbility extends FormExtensionAbility {

  // 卡片創(chuàng)建時(shí)調(diào)用
  onAddForm(want: Want): formBindingData.FormBindingData {
    hilog.info(DOMAIN_NUMBER, TAG, 'onAddForm');

    if (want.parameters) {
      const formId = JSON.stringify(want.parameters['ohos.extra.param.key.form_identity']);
      const formName = JSON.stringify(want.parameters['ohos.extra.param.key.form_name']);
      const tempFlag = want.parameters['ohos.extra.param.key.form_temporary'] as boolean;

      // 持久化,以便后續(xù) updateForm 時(shí)用到 formId
      storeFormInfo(formId, formName, tempFlag, this.context);
    }

    // 返回初始數(shù)據(jù),字段名和 HML 里 {{title}} {{detail}} 對應(yīng)
    const obj: Record<string, string> = {
      'title': 'titleOnCreate',
      'detail': 'detailOnCreate'
    };
    return formBindingData.createFormBindingData(obj);
  }

  // 卡片被移除時(shí)調(diào)用
  onRemoveForm(formId: string): void {
    hilog.info(DOMAIN_NUMBER, TAG, 'onRemoveForm');
    deleteFormInfo(formId, this.context);
  }

  // 定時(shí)/主動(dòng)刷新時(shí)調(diào)用
  onUpdateForm(formId: string): void {
    hilog.info(DOMAIN_NUMBER, TAG, 'onUpdateForm');

    const obj: Record<string, string> = {
      'title': 'titleOnUpdate',   // 更新后的數(shù)據(jù)
      'detail': 'detailOnUpdate'
    };
    const formData = formBindingData.createFormBindingData(obj);

    formProvider.updateForm(formId, formData)
      .catch((error: BusinessError) => {
        hilog.error(DOMAIN_NUMBER, TAG, `updateForm 失敗: ${JSON.stringify(error)}`);
      });
  }

  // 卡片觸發(fā)事件時(shí)調(diào)用(來自 JS 里的 postCardAction message 事件)
  onFormEvent(formId: string, message: string): void {
    hilog.info(DOMAIN_NUMBER, TAG, 'onFormEvent');

    const msg: Record<string, string> = JSON.parse(message);
    if (msg.detail === 'message detail') {
      hilog.info(DOMAIN_NUMBER, TAG, `收到卡片消息: ${msg.detail}`);
      // 在這里處理業(yè)務(wù)邏輯,比如更新卡片數(shù)據(jù)
    }
  }
}

EntryAbility 處理 router 事件參數(shù)

JS 卡片的 router 事件觸發(fā)后,參數(shù)會通過 Want.parameters.params 傳給 EntryAbility

// entry/src/main/ets/entryability/EntryAbility.ets
import { AbilityConstant, UIAbility, Want } from '@kit.AbilityKit';
import { hilog } from '@kit.PerformanceAnalysisKit';

const TAG = 'EntryAbility';
const DOMAIN_NUMBER = 0xFF00;

export default class EntryAbility extends UIAbility {
  onCreate(want: Want, launchParam: AbilityConstant.LaunchParam): void {
    if (want?.parameters?.params) {
      // params 是一個(gè) JSON 字符串,要先 parse
      const params: Record<string, Object> =
        JSON.parse(JSON.stringify(want.parameters.params));

      // 讀取 JS 卡片傳來的參數(shù)
      if (params.info === 'router info') {
        hilog.info(DOMAIN_NUMBER, TAG, `收到 info: ${params.info}`);
        // 根據(jù)參數(shù)決定跳轉(zhuǎn)哪個(gè)頁面
      }

      if (params.message === 'router message') {
        hilog.info(DOMAIN_NUMBER, TAG, `收到 message: ${params.message}`);
      }
    }
  }
}

完整生命周期和數(shù)據(jù)流

JS 卡片常見坑

坑1:uiSyntax 必須填 "hml" 而不是 "arkts"

這兩個(gè)值不能混,寫錯(cuò)了系統(tǒng)找不到卡片 UI,添加時(shí)直接報(bào)錯(cuò)。

坑2:HML 文件路徑要和配置里的 src 完全一致

配置文件里 "src": "./js/jscard/pages/index/index.hml",就要在這個(gè)路徑建文件,一個(gè)字母都不能錯(cuò)。

坑3:JS 卡片不支持 import 語法

JS 卡片運(yùn)行在一個(gè)受限環(huán)境里,不支持 ES6 的 import/export,也不支持 node_modules,只能用原生 JS。

坑4:postCardAction 在 HML 里的寫法不同

ArkTS 卡片直接調(diào) postCardAction(this, {...}),JS 卡片要用 this.$app.$def.postCardAction({...}),少了 this 參數(shù)。

寫在最后

JS 卡片說實(shí)話有點(diǎn)年代感了,能用 ArkTS 就別用 JS 卡片。但如果你接手了一個(gè)老項(xiàng)目,或者需要維護(hù) JS 卡片代碼,理解 HML + CSS + JS 這套模式是必要的。

最核心的一點(diǎn):數(shù)據(jù)綁定從 FormBindingData 到 HML 的 {{變量}} 是完全同步的,formProvider.updateForm 推數(shù)據(jù),HML 模板自動(dòng)響應(yīng),這點(diǎn)和 ArkTS 的 @LocalStorageProp 邏輯是一樣的。

到此這篇關(guān)于HarmonyOS服務(wù)卡片開發(fā)之JS卡片開發(fā)的文章就介紹到這了,更多相關(guān)HarmonyOS JS卡片開發(fā)內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • elasticsearch.yml配置文件解讀(ES配置詳解)

    elasticsearch.yml配置文件解讀(ES配置詳解)

    elasticsearch的config文件夾里面有一個(gè)主配置文件:elasticsearch.yml是es的基本配置文件,下面主要講解下elasticsearch.yml這個(gè)文件中可配置文件,感興趣的朋友一起看看吧
    2024-08-08
  • 全網(wǎng)最強(qiáng)下載神器IDM使用教程之利用IDM加速下載百度網(wǎng)盤大文件的方法

    全網(wǎng)最強(qiáng)下載神器IDM使用教程之利用IDM加速下載百度網(wǎng)盤大文件的方法

    自從不限速度盤下載工具Pandownload被封殺后,有些網(wǎng)友紛紛表示:幸好我們還有IDM,但是很多朋友對IDM不是多了解,下面小編給大家介紹下下載神器IDM使用教程之利用IDM加速下載百度網(wǎng)盤大文件的方法,感興趣的朋友跟隨小編一起看看吧
    2023-01-01
  • 如何使用postman(新手入門)

    如何使用postman(新手入門)

    Postman是google開發(fā)的一款功能強(qiáng)大的網(wǎng)頁調(diào)試與發(fā)送網(wǎng)頁HTTP請求,本文主要介紹了如何使用postman,具有一定的參考價(jià)值,感興趣的可以了解一下
    2022-01-01
  • SSO單點(diǎn)登錄和OAuth2.0區(qū)別小結(jié)

    SSO單點(diǎn)登錄和OAuth2.0區(qū)別小結(jié)

    很多時(shí)候我們會使用單點(diǎn)登錄SSO或者OAuth2.0等身份驗(yàn)證和授權(quán)來實(shí)現(xiàn)登錄,本文主要介紹了SSO單點(diǎn)登錄和OAuth2.0區(qū)別小結(jié),具有一定的參考價(jià)值,感興趣的可以了解一下
    2024-06-06
  • 2022編程語言需求排名出爐:第一不是Python,也不是Java

    2022編程語言需求排名出爐:第一不是Python,也不是Java

    編程語言的流行程度、發(fā)展前景、就業(yè)市場這些一直都是程序員們非常關(guān)注的話題,需求排名是程序員們關(guān)注學(xué)習(xí)的風(fēng)向標(biāo),畢竟是市場經(jīng)濟(jì),學(xué)以致用,如果熱門編程不了解,都不好意思告訴別人你是程序員。編程語言的種類有超過200+,但還有很多不為人知。
    2022-12-12
  • MATLAB?plot函數(shù)功能及用法詳解

    MATLAB?plot函數(shù)功能及用法詳解

    plot 函數(shù)語法使用plot繪制二維線圖,這篇文章主要介紹了MATLAB?plot函數(shù)詳解,本文給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2023-01-01
  • 淺析mmdetection在windows10系統(tǒng)環(huán)境中搭建過程

    淺析mmdetection在windows10系統(tǒng)環(huán)境中搭建過程

    這篇文章主要介紹了mmdetection在windows10系統(tǒng)環(huán)境中搭建過程,本文圖文并茂通過實(shí)例代碼給大家介紹的非常詳細(xì),具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2020-01-01
  • CSDN 博客的代碼高亮問題自己修復(fù)

    CSDN 博客的代碼高亮問題自己修復(fù)

    這幾天 CSDN 博客的代碼高亮功能突然不行了,而且論壇上有人提出 BUG,沒有得到回應(yīng)。
    2009-05-05
  • Git Submodule管理項(xiàng)目子模塊的使用

    Git Submodule管理項(xiàng)目子模塊的使用

    這篇文章主要介紹了Git Submodule管理項(xiàng)目子模塊的使用,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2020-08-08
  • Hadoop環(huán)境搭建過程中遇到的問題及解決方法

    Hadoop環(huán)境搭建過程中遇到的問題及解決方法

    這篇文章主要介紹了Hadoop環(huán)境搭建過程中遇到的問題及解決方法,本文給大家介紹的非常詳細(xì),具有一定的參考借鑒價(jià)值,需要的朋友參考下吧
    2019-08-08

最新評論

阿拉尔市| 台南县| 汕头市| 会东县| 萍乡市| 霍城县| 淳安县| 马公市| 浦东新区| 扶沟县| 诏安县| 唐山市| 海宁市| 洞口县| 深泽县| 青冈县| 常山县| 迁西县| 皮山县| 响水县| 浦江县| 河间市| 正蓝旗| 孟村| 兰西县| 奈曼旗| 砚山县| 大足县| 邵武市| 中西区| 兰州市| 鹤庆县| 顺昌县| 中卫市| 永宁县| 开江县| 新乡市| 绥棱县| 洛宁县| 阿巴嘎旗| 茌平县|