主頁 > 前端設計 > HarmonyOS 實戰——萬字分析并學習 JsFACard 專案

HarmonyOS 實戰——萬字分析并學習 JsFACard 專案

2021-07-31 08:29:07 前端設計

HarmonyOS 實戰——萬字分析并學習 JsFACard 專案

    • 專案結構
    • 原始碼學習
      • config.json
        • module
          • abilities
          • js
      • Java 部分
        • 成員變數
        • 方法
      • JavaScript 部分
        • jsmusictemplate
          • hml
          • css
          • json
    • 總結

在上一篇中學習原子化服務的文 HarmonyOS 實戰——認識服務卡片及運行第一個服務卡片 的后半部分學習了如何運行官方提供的案例,運行效果如下:

這篇文就官方提供的 JsFACard 原始碼進行學習,JsFACard 的命名是因為這個專案主要是基于 JavaScript 進行實作的 FA(Feature Ability,元服務,代表有界面的 Ability,用于與用戶進行互動) 卡片服務(Card 的由來),

完成了 JsFACard 案例學習應該能夠掌握以下技能:

  • 了解原子服務的基礎結構

    即 src 的專案結構

  • 了解基礎的卡片服務的配置

    即通過修改 config.json 完成卡片服務的配置

  • 了解卡片服務的結構

  • 實作卡片服務的資料交換和狀態更新

    通過 json/js 實作狀態管理,以及通過 Java 代碼中的 onTriggerFormEvent方法 實作卡片狀態的更新

專案結構

主要的內容,即 src 目錄下的內容如下:

也就是下面的結構:

|- src
|  |- main # 主要內容
|  |  |- java # java 依舊會別用做為主要的實體管理模塊
|  |  |  |- 存盤其他相關物件的目錄
|  |  |  |  |- ...
|  |  |  |- MainAbility # 主程式入口,DevEco Studio生成
|  |  |  |- MyApplication # DevEco Studio生成,不需變更
|  |  |- js # 主要的呈現部分
|  |  |  |- card # 卡片1號
|  |  |  |  |- common # 存放公共資源檔案
|  |  |  |  |- i18n # 多語言支持
|  |  |  |  |- pages # 存放所有組件頁面
|  |  |  |  |  |- index # 入口,包含對應檔案
|  |  |  |  |  |  |- index.css
|  |  |  |  |  |  |- index.hml
|  |  |  |  |  |  |- index.json
|  |  |  |- default # 主程式,非 卡片
|  |  |  |  |- ... # 結構基本一致,除了沒有 index.json 檔案,取而代之的是 index.js
|  |  |  |  |- app.js # 用于全域JavaScript邏輯和應用生命周期管理
|  |  |  |- jscardtemplate # 卡片2號
|  |  |  |  |- 結構一樣
|  |  |  |- jsmusictemplate # 卡片3號
|  |  |  |  |- 結構一樣
|  |  |- resources # 共享資源
|  |  |- config.json # 組態檔
|  |- ohosTest # 測驗部分,這里不會贅述

基礎結構相對而言還是比較簡單,理解起來也不是非常的復雜,不過剛開始看的時候不知道還需要寫 java 就有些蒙逼,不過最侄訓是下載了 JsFACard 才算搞明白,原來使用 JavaScript 開發不代表純 JavaScript 開發這個道理,

上文內容所包含的參考資料有:

  • app.js

    這篇文章講述了 app.js 的用處

  • JS FA 概述

    卡片服務始侄訓是依賴于 FA 而進行實作,換言之,不了解 FA 就無法實作卡片服務

  • 代碼結構解讀

    這個案例是 JS 計步器卡片 這個案例,代碼更加復雜一些,所以剛開始沒有選擇這個案例進行學習

  • 檔案組織

    服務卡片的檔案組織

原始碼學習

這是官方提供的案例,下載地址在:https://gitee.com/openharmony/app_samples/tree/master/UI/JsFACard,

config.json

完整的組態檔可以在案例中的 JsFACard / entry / src / main / config.json 看到網址在:https://gitee.com/openharmony/app_samples/blob/master/UI/JsFACard/entry/src/main/config.json,

config.json 的大體結構如下:

config.json

可以看出來,config.json 有三個最大的,不可預設 的模塊:

  • app

    表示應用的全域配置資訊,同一個應用程式中,app 中的資訊必須保持一致,

    這里不會贅述,

  • deviceConfig

    應用在具體設備上的配置資訊,這里不會贅述,

  • module

    這塊是重點,會結合檔案詳細學習一下,

module

這是重點,module 部分管理所有當前 HAP(HarmonyOS Ability Package) 的配置資訊,每個 HAP 是 Ability 的部署包,Ability 為 應用/服務 的基本組成單位,我的理解是某個功能的具體實作,

這里會結合專案結構對 module 中的內容進行分析和學習,

  • package,不可預設

    package 是 HAP 的包結構名稱,在應用內應保證唯一性,建議與 HAP 的工程目錄保持一致,

    例如說這個專案的 package 值是 ohos.samples.jsfacard,與 HAP 的工程目錄是保持一致的(畢竟官方自己建議這么實施),

    package

  • name,不可預設

    HAP 的類名,前綴需要與同級的 package 標簽指定的包名一致,也可采用 . 開頭的命名方式,

    也就是使用絕對定位和相對定位的關系,原本的值使用的是相對定位,也就是采用 . 開頭的命名方式:.MainAbility,這種情況下,系統運行時回去尋找 package 下的類名進行打包,

    本機測驗采用絕對定位的方式,也就是 ohos.samples.jsfacard.MainAbility 一樣可以運行,

  • mainAbility

    表示 HAP 包的入口 ability 名稱,如果存在 page 型別的 ability 就不可預設,

    案例情況下,name 和 mainAbility 指向的是同一個類——ohos.samples.jsfacard.MainAbility

  • deviceType,不可預設

    當前 應用/服務 可運行的設備,接受的引數為字串型別,預設的時候只勾選了手機,所以這里的值是 ["phone"]

  • distro,不可預設

    HAP 發布的具體描述,包含的資訊有:

    • deliveryWithInstall,不可預設,建議設定為 true

      當前 HAP 是否支持隨應用安裝,

      設定 false 就代表了安裝應用不會安裝當前 HAP 的意思?不是很明白這個特性是什么意思,

    • moduleName

      模塊名稱,這點抬頭看最上面即可:

      module-name

      值是 entry

    • moduleType

      表示 HAP 的型別,目前只能在 entry 和 feature 中選擇,

    • installationFree

      免安裝特性,JsFACard 默認值是 false,感覺設定為 true 也可以吧,

  • abilities,可預設

    陣列格式,其中每個元素表示一個提供的服務,整個陣列代表著所有提供的服務,

  • js,可預設

    陣列格式,表示基于 JS UI 框架開發的 JS 模塊集合,其中的每個元素代表一個 JS 模塊的資訊,

    在 JsFACard 之中,除了 default 是默認程式的 UI 之外,其余每一個 JS 物件所對應的都是一個 forms,也就是卡片服務:

    forms-js

abilities

JsFACard 專案里值包含了一個物件,物件的中的鍵值對包含:

  • skills

    表示 Ability 能夠接收的 Intent 的特征,一般使用的時候系統預定義內容,JsFACard 中的配置使用的就是系統預定義內容,具體配置如下:

    {
      "skills": [
        {
          "entities": ["entity.system.home"],
          "actions": ["action.system.home"]
        }
      ]
    }
    
  • name

    表示 ability 的名稱,

    鑒于這只是一個 Demo 專案,并且專案的入口和服務的入口是一樣的,所以這里的值依舊是 .MainAbility

  • icon

    圖示,注意這里的值使用的是 $media:icon,注意看提示:

    icon

    icon 接受值的格式就是 $media:some-value 這樣一個格式,

    資源(resources) 下存放資源是有一定程度上的固定格式的,例如說 resources 下存放資源是需要有兩級目錄,一級子目錄為 base 目錄限定詞目錄,二級子目錄為資源目錄,圖解如下:

    resources
    |---base  // 默認存在的目錄
    |   |---element
    |   |   |---string.json
    |   |---media
    |   |   |---icon.png
    |---en_GB-vertical-car-mdpi // 限定詞目錄示例,需要  開發者自行創建
    |   |---element
    |   |   |---string.json
    |   |---media
    |   |   |---icon.png
    |---rawfile  // 默認存在的目錄
    

    因為 base 是系統默認存在的目錄,當資源目錄中沒有與設備狀態匹配的限定詞目錄時,會自動參考該目錄中的資源檔案,以 $media:some-value 為例,系統會自動匹配名為 some-value 的多媒體檔案,如果出現多個名字相同的資源,則會默認匹配第一個資源,

    更多細節可以參考:資源檔案的分類 中的具體條款,

  • description

    特性和 icon 相似,格式依舊是 $string:some-value,并且會自動匹配第一條資料,

  • formsEnabled

    表示服務是否支持 卡片(forms) 功能,僅是用一 page 類

  • label

    特性和 icon 和 description 相似,格式依舊是 $string:some-value,并且會自動匹配第一條資料,

  • type

    表示服務的型別:

    • page,基于 page 模板開發的 FA,用于提供與用戶互動的能力,

      也是這里用到的服務,其余的服務型別不多贅述,

  • forms

    服務卡片的屬性,僅在 "formsEnabled": true 時才會起效,接受資料為陣列,陣列中的每一個物件就是一個服務卡片的屬性,

    卡片的屬性就比較直截了當,沒有什么特別難理解的地方:

    {
      "jsComponentName": "jsmusictemplate",
      "isDefault": true,
      "formConfigAbility": "ability://ohos.samples.jsfacard.MainAbility",
      "scheduledUpdateTime": "10:30",
      "defaultDimension": "2*4",
      "name": "jsmusictemplate",
      "description": "This is a service widget",
      "colorMode": "auto",
      "type": "JS",
      "supportDimensions": ["2*4"],
      "updateEnabled": true,
      "updateDuration": 1
    }
    
  • launchType

    這里的值是 standard,表明服務可以有多個實體,適用于大多數應用場景

jsmusictemplate 的渲染效果如下:

卡片的 UI 暫且不論,上面的資料,如 This is a service widget(forms > description) 和 Js卡片(abilities > label) 均來源于配置,

js

js 接受的也是陣列型別,每個陣列里面是一個物件:

{
  "pages": ["pages/index/index"],
  "name": "jsmusictemplate",
  "window": {
    "designWidth": 720,
    "autoDesignWidth": true
  },
  "type": "form"
}

滾過一遍 module 和 abilities 就差不多知道這些配置都代表什么意思了,

js 陣列中提供的是卡片的 UI 布局,物件中的 nameforms 包含物件中的 jsComponentName

至此,配置內容已經了解的差不多了,更多更具體的內容可以查看 應用組態檔 接下來可以開始著手了解實作的部分,

Java 部分

Java 部分的代碼量不是很多,畢竟這個服務卡片的內容其實不是很多,主要的結構如下:

java

MainAbility 是主程式入口,可以選擇繼承 AceAbilityAbility,這里選擇繼承的是 AceAbility,應該是可以方便一些,畢竟根據官方檔案來說,AceAbility 繼承了 Ability

public class AceAbility
extends Ability
implements IAbilityContinuation

實作 MainAbility 主要是為了對服務的生命周期進行管理,官方提供的生命周期為:

life-cycle

成員變數

MainAbility 中宣告的幾個成員變數有:

public class MainAbility extends AceAbility {
    private static final HiLogLabel TAG = new HiLogLabel(HiLog.DEBUG, 0x0, MainAbility.class.getName());

    private static final String STATUS = "status";

    private static final String PLAY = "play";

    private static final String PAUSE = "pause";

    private static boolean isStatus = true;
}

其中包含:

  • HiLogLabel

    日志類的輔助工具,用于定義日志型別、服務域名和標簽

  • STATUS,PLAY,PAUSE

    三個是靜態常量,用于定義狀態

  • isStatus

    定義當前組件的狀態,結合其他幾個常量,應該是用來控制音樂的播放,

方法

JsFACard 中多載的方法不是很多,大部分都是呼叫 super.method() 去呼叫父類中已經實作的方法,而非多載,直接呼叫父類實作的方法包含:

  • void onStart(Intent intent)

    必須呼叫這個函式去設定 UI,在整個服務的生命周期中只能被呼叫一次

  • ProviderFormInfo onCreateForm(Intent intent)

    呼叫這個函式會回傳一個 ProviderFormInfo 物件,用于在 UI 上顯示基礎的卡片資訊,以及向用戶提供一個卡片服務

  • void onUpdateForm(long formId)

    呼叫函式去通知卡片服務提供商去更新特定的卡片

  • void onDeleteForm(long formId)

    呼叫函式去通知卡片服務提供商去洗掉特定的卡片

多載的方法有:

  • void onTriggerFormEvent(long formId, String message)

    代碼如下:

    public class MainAbility extends AceAbility {
          @Override
          protected void onTriggerFormEvent(long formId, String message) {
              super.onTriggerFormEvent(formId, message);
              ZSONObject zsonObject = new ZSONObject();
              // 主要目的就是為了更新 isStatus 的狀態 和更新 zsonObject
              if (isStatus) {
                  zsonObject.put(STATUS, PAUSE);
                  isStatus = false;
              } else {
                  zsonObject.put(STATUS, PLAY);
                  isStatus = true;
              }
              FormBindingData formBindingData = new FormBindingData(zsonObject);
              try {
                  updateForm(formId, formBindingData);
              } catch (FormException e) {
                  HiLog.info(TAG, "onTriggerFormEvent:" + e.getMessage());
              }
          }
      }
    

    這個函式會根據觸發的事件要操作的行為去進行下面的操作:

    1. 創建新的 ZSONObject 物件

    2. 將對應的狀態存盤到 ZSONObject 物件中

    3. 更新成員變數 isStatus

    4. 將 ZSONObject 物件 寫入 FormBindingData 物件 中去

    5. 呼叫更新卡片的功能去將 FormBindingData 寫入對應的卡片服務中去,從而實作卡片服務

    這一步實作了卡片資料的互動,寫入進卡片的資料有兩種:

    "status": "play""status": "pause",這兩個值在之后的 JS 部分中會有用,

在 JS 卡片開發指導 中對呼叫的 API 以及對實作有更具體的描寫,

所以說 Ability 到底是不是 Controller 的一種來著,感覺有點像啊……

JavaScript 部分

JavaScript 部分內容分為兩塊:

  • 模塊入口

    注意,這不是主程式入口,主程式入口依舊是 Java 中的 MainAbility,模塊目錄結構如下:

    appjs

    還是比較直觀的,pages 負責頁面的不同組件,其下 hml 檔案是 HML 的模板檔案,負責框架;css 檔案負責樣式;js 檔案負責行為,

    app.js 負責應用級別的生命周期管理,

    具體程式內容這里不會詳細學習,簡單的了解一下內容即可,

  • 卡片服務應用

    這里以 jsmusictemplate 為例,主要是因為 jsmusictemplate 實作的功能比其他兩個卡片服務更多一些,

    jsmusictemplate 的目錄結構如下:

    jsmusic-temp

    可以看到,卡片服務和 FA 服務的結構是非常相似的,最大的區別在于 pages 下存在一個 .json檔案,而非 .js檔案,

    這大概是因為這個頁面的邏輯比較簡單,不需要其他一些默認值和函式,所以使用 .json檔案 實作會簡單一些,在另一個更加復雜的專案——JS 計步器卡片中,使用的依舊是 .js檔案:

    step-counter

jsmusictemplate

這里主要學習的依舊是 jsmusictemplate,先來看看這個頁面長什么樣的:

music-card

可以看出頁面被規劃成了 左邊的音樂播放 和 右邊的常用功能 兩個部分,.hml, .css.json 應該就是基于這兩個模塊進行實作的,

hml

鑒于 .hml檔案 是 HTML 的模板檔案,基于之前的分析,實作起來應該是這樣的結構:

|- container
|  |- play-music
|  |- shortcuts

實作的結構也是這樣的:

hml

  • 音樂播放功能

    其中,播放音樂的功能使用了 stack標簽 去實作,根據 檔案-stack 上所描述,這個標簽起到的是讓元素堆疊的效果,也就是讓 svg 檔案堆疊在背景圖片上,

    stack標簽 會讓后面的元素堆疊到前面的元素上,因此結構里第一個元素是背景圖片,第二個元素才是播放的 icon,

    注意看一下 icon 的實作代碼:

    <image
      src="/common/{{ status }}.svg"
      onclick="messageEvent"
      class="status-image"
    ></image>
    

    這里的功能其實與 Java 部分的代碼和 json 功能都有聯動,{{}} 應該是 Mustache Syntax,中間的 status 屬于變數名,可以獲得 status 這個變數,回想一下 Java 代碼中會通過 updateForm 更新的狀態:"status": "play""status": "pause",所以這里 src 的資料有兩種:"/common/play.svg""/common/pause.svg",common 檔案夾中的確存在這兩個檔案:

    狀態的變更則由 messageEvent 進行觸發,這里的引數是由 json 提供的,等到 json 部分再去具體化,

  • 快捷鍵功能

    即右邊的搜索、播放等功能,基本結構如下:

    <div class="main-div medium-display-index">
      <div class="wrap-div medium-display-index">
        <image src="/common/ic_search.svg" class="image-div"></image>
        <text class="image-text">{{ $t('strings.search') }}</text>
      </div>
      <div class="wrap-div medium-display-index">
        <image src="/common/ic_favor.svg" class="image-div"></image>
        <text class="image-text">{{ $t('strings.favor') }}</text>
      </div>
      <div class="wrap-div small-display-index">
        <image src="/common/ic_ranking.svg" class="image-div"></image>
        <text class="image-text">{{ $t('strings.ranking') }}</text>
      </div>
      <div class="wrap-div small-display-index">
        <image src="/common/ic_recommend.svg" class="image-div"></image>
        <text class="image-text">{{ $t('strings.recommend') }}</text>
      </div>
    </div>
    
    <div class="main-div small-display-index">
      <div class="wrap-div medium-display-index">
        <image src="/common/ic_ranking.svg" class="image-div"></image>
        <text class="image-text">{{ $t('strings.ranking') }}</text>
      </div>
      <div class="wrap-div medium-display-index">
        <image src="/common/ic_recommend.svg" class="image-div"></image>
        <text class="image-text">{{ $t('strings.recommend') }}</text>
      </div>
      <div class="wrap-div small-display-index">
        <image src="/common/ic_favor.svg" class="image-div"></image>
        <text class="image-text">{{ $t('strings.favor') }}</text>
      </div>
      <div class="wrap-div small-display-index">
        <image src="/common/ic_search.svg" class="image-div"></image>
        <text class="image-text">{{ $t('strings.search') }}</text>
      </div>
    </div>
    

    這里分別使用了兩個 div 去實作不同的功能,而在不同 div 之間,元素的類名是不一樣的,這是通過 CSS 去控制顯示的內容,去進行布局,

    只顯示一個 div 和同時顯示兩個 div 的效果如下:

    • 保留父元素為 medium-display-index

      即,保留第一個 div

      med-display-index

    • 保留父元素為 small-display-index

      即,保留第二個 div

      sm-display-index

    • 保留兩個元素

      both-index

可以看到元素中都是 small-display-index 的元素被隱藏了,這是由 CSS 控制的,

css

CSS 的大部分內容都是比較常見的,除了 small-display-indexmedium-display-index 中使用的 display-index 之前是沒有見過的,

display-index 是 原子布局 中的新特性,檔案中的說明是:

該適用于 div 等支持 flex 布局的容器組件中的子組件上,當容器組件在 flex 主軸上尺寸不足以顯示下全部內容時,按照 display-index 值從小到大的順序進行隱藏,具有相同 display-index 值的組件同時隱藏,默認值為 Infinity,表示不隱藏,

更具另外一份檔案,也就是 通用樣式 中可以得知,display 的默認值是 flex,所以當空間不夠的時候,small-display-index 的值就會被隱藏掉,

至于官方為什么這么實作,我覺得和多端適配有關系,下面是平板上顯示的效果,能看到和手機上的效果完全不一樣:

pad-music

這個布局看起來是完全隱藏了 small-display-index,只顯示 medium-display-index 中內容,因為在平板上的高度足夠的關系,所以 medium-display-index 中的 4 個元素可以全都顯示出來,

至于 small-display-indexmedium-display-index 加起來的寬度,則通過 音樂播放 的界面去控制的,

關于布局這方面真的還需要好好學習一下,

json

json 相對而言是三個部分中最簡單的部分,因為這里沒有什么特別復雜的邏輯,完整的代碼只有 13 行:

{
  "data": {
    "status": "play"
  },
  "actions": {
    "messageEvent": {
      "action": "message",
      "params": {
        "message": "music change status"
      }
    }
  }
}

可以看到,在結構體中有 dataactions 兩大模塊,data 負責的就是資料,它所匯出的資料被 src="/common/{{ status }}.svg" 所獲取;actions 則負責事件,它所匯出的資料被 onclick="messageEvent" 所獲取,結合 Java 中的代碼,音樂播放器中的事件流程就是這樣的:

<style>#mermaid-svg-J65WbxpJtCZ9sRtG .label{font-family:'trebuchet ms', verdana, arial;font-family:var(--mermaid-font-family);fill:#333;color:#333}#mermaid-svg-J65WbxpJtCZ9sRtG .label text{fill:#333}#mermaid-svg-J65WbxpJtCZ9sRtG .node rect,#mermaid-svg-J65WbxpJtCZ9sRtG .node circle,#mermaid-svg-J65WbxpJtCZ9sRtG .node ellipse,#mermaid-svg-J65WbxpJtCZ9sRtG .node polygon,#mermaid-svg-J65WbxpJtCZ9sRtG .node path{fill:#ECECFF;stroke:#9370db;stroke-width:1px}#mermaid-svg-J65WbxpJtCZ9sRtG .node .label{text-align:center;fill:#333}#mermaid-svg-J65WbxpJtCZ9sRtG .node.clickable{cursor:pointer}#mermaid-svg-J65WbxpJtCZ9sRtG .arrowheadPath{fill:#333}#mermaid-svg-J65WbxpJtCZ9sRtG .edgePath .path{stroke:#333;stroke-width:1.5px}#mermaid-svg-J65WbxpJtCZ9sRtG .flowchart-link{stroke:#333;fill:none}#mermaid-svg-J65WbxpJtCZ9sRtG .edgeLabel{background-color:#e8e8e8;text-align:center}#mermaid-svg-J65WbxpJtCZ9sRtG .edgeLabel rect{opacity:0.9}#mermaid-svg-J65WbxpJtCZ9sRtG .edgeLabel span{color:#333}#mermaid-svg-J65WbxpJtCZ9sRtG .cluster rect{fill:#ffffde;stroke:#aa3;stroke-width:1px}#mermaid-svg-J65WbxpJtCZ9sRtG .cluster text{fill:#333}#mermaid-svg-J65WbxpJtCZ9sRtG div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:'trebuchet ms', verdana, arial;font-family:var(--mermaid-font-family);font-size:12px;background:#ffffde;border:1px solid #aa3;border-radius:2px;pointer-events:none;z-index:100}#mermaid-svg-J65WbxpJtCZ9sRtG .actor{stroke:#ccf;fill:#ECECFF}#mermaid-svg-J65WbxpJtCZ9sRtG text.actor>tspan{fill:#000;stroke:none}#mermaid-svg-J65WbxpJtCZ9sRtG .actor-line{stroke:grey}#mermaid-svg-J65WbxpJtCZ9sRtG .messageLine0{stroke-width:1.5;stroke-dasharray:none;stroke:#333}#mermaid-svg-J65WbxpJtCZ9sRtG .messageLine1{stroke-width:1.5;stroke-dasharray:2, 2;stroke:#333}#mermaid-svg-J65WbxpJtCZ9sRtG #arrowhead path{fill:#333;stroke:#333}#mermaid-svg-J65WbxpJtCZ9sRtG .sequenceNumber{fill:#fff}#mermaid-svg-J65WbxpJtCZ9sRtG #sequencenumber{fill:#333}#mermaid-svg-J65WbxpJtCZ9sRtG #crosshead path{fill:#333;stroke:#333}#mermaid-svg-J65WbxpJtCZ9sRtG .messageText{fill:#333;stroke:#333}#mermaid-svg-J65WbxpJtCZ9sRtG .labelBox{stroke:#ccf;fill:#ECECFF}#mermaid-svg-J65WbxpJtCZ9sRtG .labelText,#mermaid-svg-J65WbxpJtCZ9sRtG .labelText>tspan{fill:#000;stroke:none}#mermaid-svg-J65WbxpJtCZ9sRtG .loopText,#mermaid-svg-J65WbxpJtCZ9sRtG .loopText>tspan{fill:#000;stroke:none}#mermaid-svg-J65WbxpJtCZ9sRtG .loopLine{stroke-width:2px;stroke-dasharray:2, 2;stroke:#ccf;fill:#ccf}#mermaid-svg-J65WbxpJtCZ9sRtG .note{stroke:#aa3;fill:#fff5ad}#mermaid-svg-J65WbxpJtCZ9sRtG .noteText,#mermaid-svg-J65WbxpJtCZ9sRtG .noteText>tspan{fill:#000;stroke:none}#mermaid-svg-J65WbxpJtCZ9sRtG .activation0{fill:#f4f4f4;stroke:#666}#mermaid-svg-J65WbxpJtCZ9sRtG .activation1{fill:#f4f4f4;stroke:#666}#mermaid-svg-J65WbxpJtCZ9sRtG .activation2{fill:#f4f4f4;stroke:#666}#mermaid-svg-J65WbxpJtCZ9sRtG .mermaid-main-font{font-family:"trebuchet ms", verdana, arial;font-family:var(--mermaid-font-family)}#mermaid-svg-J65WbxpJtCZ9sRtG .section{stroke:none;opacity:0.2}#mermaid-svg-J65WbxpJtCZ9sRtG .section0{fill:rgba(102,102,255,0.49)}#mermaid-svg-J65WbxpJtCZ9sRtG .section2{fill:#fff400}#mermaid-svg-J65WbxpJtCZ9sRtG .section1,#mermaid-svg-J65WbxpJtCZ9sRtG .section3{fill:#fff;opacity:0.2}#mermaid-svg-J65WbxpJtCZ9sRtG .sectionTitle0{fill:#333}#mermaid-svg-J65WbxpJtCZ9sRtG .sectionTitle1{fill:#333}#mermaid-svg-J65WbxpJtCZ9sRtG .sectionTitle2{fill:#333}#mermaid-svg-J65WbxpJtCZ9sRtG .sectionTitle3{fill:#333}#mermaid-svg-J65WbxpJtCZ9sRtG .sectionTitle{text-anchor:start;font-size:11px;text-height:14px;font-family:'trebuchet ms', verdana, arial;font-family:var(--mermaid-font-family)}#mermaid-svg-J65WbxpJtCZ9sRtG .grid .tick{stroke:#d3d3d3;opacity:0.8;shape-rendering:crispEdges}#mermaid-svg-J65WbxpJtCZ9sRtG .grid .tick text{font-family:'trebuchet ms', verdana, arial;font-family:var(--mermaid-font-family)}#mermaid-svg-J65WbxpJtCZ9sRtG .grid path{stroke-width:0}#mermaid-svg-J65WbxpJtCZ9sRtG .today{fill:none;stroke:red;stroke-width:2px}#mermaid-svg-J65WbxpJtCZ9sRtG .task{stroke-width:2}#mermaid-svg-J65WbxpJtCZ9sRtG .taskText{text-anchor:middle;font-family:'trebuchet ms', verdana, arial;font-family:var(--mermaid-font-family)}#mermaid-svg-J65WbxpJtCZ9sRtG .taskText:not([font-size]){font-size:11px}#mermaid-svg-J65WbxpJtCZ9sRtG .taskTextOutsideRight{fill:#000;text-anchor:start;font-size:11px;font-family:'trebuchet ms', verdana, arial;font-family:var(--mermaid-font-family)}#mermaid-svg-J65WbxpJtCZ9sRtG .taskTextOutsideLeft{fill:#000;text-anchor:end;font-size:11px}#mermaid-svg-J65WbxpJtCZ9sRtG .task.clickable{cursor:pointer}#mermaid-svg-J65WbxpJtCZ9sRtG .taskText.clickable{cursor:pointer;fill:#003163 !important;font-weight:bold}#mermaid-svg-J65WbxpJtCZ9sRtG .taskTextOutsideLeft.clickable{cursor:pointer;fill:#003163 !important;font-weight:bold}#mermaid-svg-J65WbxpJtCZ9sRtG .taskTextOutsideRight.clickable{cursor:pointer;fill:#003163 !important;font-weight:bold}#mermaid-svg-J65WbxpJtCZ9sRtG .taskText0,#mermaid-svg-J65WbxpJtCZ9sRtG .taskText1,#mermaid-svg-J65WbxpJtCZ9sRtG .taskText2,#mermaid-svg-J65WbxpJtCZ9sRtG .taskText3{fill:#fff}#mermaid-svg-J65WbxpJtCZ9sRtG .task0,#mermaid-svg-J65WbxpJtCZ9sRtG .task1,#mermaid-svg-J65WbxpJtCZ9sRtG .task2,#mermaid-svg-J65WbxpJtCZ9sRtG .task3{fill:#8a90dd;stroke:#534fbc}#mermaid-svg-J65WbxpJtCZ9sRtG .taskTextOutside0,#mermaid-svg-J65WbxpJtCZ9sRtG .taskTextOutside2{fill:#000}#mermaid-svg-J65WbxpJtCZ9sRtG .taskTextOutside1,#mermaid-svg-J65WbxpJtCZ9sRtG .taskTextOutside3{fill:#000}#mermaid-svg-J65WbxpJtCZ9sRtG .active0,#mermaid-svg-J65WbxpJtCZ9sRtG .active1,#mermaid-svg-J65WbxpJtCZ9sRtG .active2,#mermaid-svg-J65WbxpJtCZ9sRtG .active3{fill:#bfc7ff;stroke:#534fbc}#mermaid-svg-J65WbxpJtCZ9sRtG .activeText0,#mermaid-svg-J65WbxpJtCZ9sRtG .activeText1,#mermaid-svg-J65WbxpJtCZ9sRtG .activeText2,#mermaid-svg-J65WbxpJtCZ9sRtG .activeText3{fill:#000 !important}#mermaid-svg-J65WbxpJtCZ9sRtG .done0,#mermaid-svg-J65WbxpJtCZ9sRtG .done1,#mermaid-svg-J65WbxpJtCZ9sRtG .done2,#mermaid-svg-J65WbxpJtCZ9sRtG .done3{stroke:grey;fill:#d3d3d3;stroke-width:2}#mermaid-svg-J65WbxpJtCZ9sRtG .doneText0,#mermaid-svg-J65WbxpJtCZ9sRtG .doneText1,#mermaid-svg-J65WbxpJtCZ9sRtG .doneText2,#mermaid-svg-J65WbxpJtCZ9sRtG .doneText3{fill:#000 !important}#mermaid-svg-J65WbxpJtCZ9sRtG .crit0,#mermaid-svg-J65WbxpJtCZ9sRtG .crit1,#mermaid-svg-J65WbxpJtCZ9sRtG .crit2,#mermaid-svg-J65WbxpJtCZ9sRtG .crit3{stroke:#f88;fill:red;stroke-width:2}#mermaid-svg-J65WbxpJtCZ9sRtG .activeCrit0,#mermaid-svg-J65WbxpJtCZ9sRtG .activeCrit1,#mermaid-svg-J65WbxpJtCZ9sRtG .activeCrit2,#mermaid-svg-J65WbxpJtCZ9sRtG .activeCrit3{stroke:#f88;fill:#bfc7ff;stroke-width:2}#mermaid-svg-J65WbxpJtCZ9sRtG .doneCrit0,#mermaid-svg-J65WbxpJtCZ9sRtG .doneCrit1,#mermaid-svg-J65WbxpJtCZ9sRtG .doneCrit2,#mermaid-svg-J65WbxpJtCZ9sRtG .doneCrit3{stroke:#f88;fill:#d3d3d3;stroke-width:2;cursor:pointer;shape-rendering:crispEdges}#mermaid-svg-J65WbxpJtCZ9sRtG .milestone{transform:rotate(45deg) scale(0.8, 0.8)}#mermaid-svg-J65WbxpJtCZ9sRtG .milestoneText{font-style:italic}#mermaid-svg-J65WbxpJtCZ9sRtG .doneCritText0,#mermaid-svg-J65WbxpJtCZ9sRtG .doneCritText1,#mermaid-svg-J65WbxpJtCZ9sRtG .doneCritText2,#mermaid-svg-J65WbxpJtCZ9sRtG .doneCritText3{fill:#000 !important}#mermaid-svg-J65WbxpJtCZ9sRtG .activeCritText0,#mermaid-svg-J65WbxpJtCZ9sRtG .activeCritText1,#mermaid-svg-J65WbxpJtCZ9sRtG .activeCritText2,#mermaid-svg-J65WbxpJtCZ9sRtG .activeCritText3{fill:#000 !important}#mermaid-svg-J65WbxpJtCZ9sRtG .titleText{text-anchor:middle;font-size:18px;fill:#000;font-family:'trebuchet ms', verdana, arial;font-family:var(--mermaid-font-family)}#mermaid-svg-J65WbxpJtCZ9sRtG g.classGroup text{fill:#9370db;stroke:none;font-family:'trebuchet ms', verdana, arial;font-family:var(--mermaid-font-family);font-size:10px}#mermaid-svg-J65WbxpJtCZ9sRtG g.classGroup text .title{font-weight:bolder}#mermaid-svg-J65WbxpJtCZ9sRtG g.clickable{cursor:pointer}#mermaid-svg-J65WbxpJtCZ9sRtG g.classGroup rect{fill:#ECECFF;stroke:#9370db}#mermaid-svg-J65WbxpJtCZ9sRtG g.classGroup line{stroke:#9370db;stroke-width:1}#mermaid-svg-J65WbxpJtCZ9sRtG .classLabel .box{stroke:none;stroke-width:0;fill:#ECECFF;opacity:0.5}#mermaid-svg-J65WbxpJtCZ9sRtG .classLabel .label{fill:#9370db;font-size:10px}#mermaid-svg-J65WbxpJtCZ9sRtG .relation{stroke:#9370db;stroke-width:1;fill:none}#mermaid-svg-J65WbxpJtCZ9sRtG .dashed-line{stroke-dasharray:3}#mermaid-svg-J65WbxpJtCZ9sRtG #compositionStart{fill:#9370db;stroke:#9370db;stroke-width:1}#mermaid-svg-J65WbxpJtCZ9sRtG #compositionEnd{fill:#9370db;stroke:#9370db;stroke-width:1}#mermaid-svg-J65WbxpJtCZ9sRtG #aggregationStart{fill:#ECECFF;stroke:#9370db;stroke-width:1}#mermaid-svg-J65WbxpJtCZ9sRtG #aggregationEnd{fill:#ECECFF;stroke:#9370db;stroke-width:1}#mermaid-svg-J65WbxpJtCZ9sRtG #dependencyStart{fill:#9370db;stroke:#9370db;stroke-width:1}#mermaid-svg-J65WbxpJtCZ9sRtG #dependencyEnd{fill:#9370db;stroke:#9370db;stroke-width:1}#mermaid-svg-J65WbxpJtCZ9sRtG #extensionStart{fill:#9370db;stroke:#9370db;stroke-width:1}#mermaid-svg-J65WbxpJtCZ9sRtG #extensionEnd{fill:#9370db;stroke:#9370db;stroke-width:1}#mermaid-svg-J65WbxpJtCZ9sRtG .commit-id,#mermaid-svg-J65WbxpJtCZ9sRtG .commit-msg,#mermaid-svg-J65WbxpJtCZ9sRtG .branch-label{fill:lightgrey;color:lightgrey;font-family:'trebuchet ms', verdana, arial;font-family:var(--mermaid-font-family)}#mermaid-svg-J65WbxpJtCZ9sRtG .pieTitleText{text-anchor:middle;font-size:25px;fill:#000;font-family:'trebuchet ms', verdana, arial;font-family:var(--mermaid-font-family)}#mermaid-svg-J65WbxpJtCZ9sRtG .slice{font-family:'trebuchet ms', verdana, arial;font-family:var(--mermaid-font-family)}#mermaid-svg-J65WbxpJtCZ9sRtG g.stateGroup text{fill:#9370db;stroke:none;font-size:10px;font-family:'trebuchet ms', verdana, arial;font-family:var(--mermaid-font-family)}#mermaid-svg-J65WbxpJtCZ9sRtG g.stateGroup text{fill:#9370db;fill:#333;stroke:none;font-size:10px}#mermaid-svg-J65WbxpJtCZ9sRtG g.statediagram-cluster .cluster-label text{fill:#333}#mermaid-svg-J65WbxpJtCZ9sRtG g.stateGroup .state-title{font-weight:bolder;fill:#000}#mermaid-svg-J65WbxpJtCZ9sRtG g.stateGroup rect{fill:#ECECFF;stroke:#9370db}#mermaid-svg-J65WbxpJtCZ9sRtG g.stateGroup line{stroke:#9370db;stroke-width:1}#mermaid-svg-J65WbxpJtCZ9sRtG .transition{stroke:#9370db;stroke-width:1;fill:none}#mermaid-svg-J65WbxpJtCZ9sRtG .stateGroup .composit{fill:white;border-bottom:1px}#mermaid-svg-J65WbxpJtCZ9sRtG .stateGroup .alt-composit{fill:#e0e0e0;border-bottom:1px}#mermaid-svg-J65WbxpJtCZ9sRtG .state-note{stroke:#aa3;fill:#fff5ad}#mermaid-svg-J65WbxpJtCZ9sRtG .state-note text{fill:black;stroke:none;font-size:10px}#mermaid-svg-J65WbxpJtCZ9sRtG .stateLabel .box{stroke:none;stroke-width:0;fill:#ECECFF;opacity:0.7}#mermaid-svg-J65WbxpJtCZ9sRtG .edgeLabel text{fill:#333}#mermaid-svg-J65WbxpJtCZ9sRtG .stateLabel text{fill:#000;font-size:10px;font-weight:bold;font-family:'trebuchet ms', verdana, arial;font-family:var(--mermaid-font-family)}#mermaid-svg-J65WbxpJtCZ9sRtG .node circle.state-start{fill:black;stroke:black}#mermaid-svg-J65WbxpJtCZ9sRtG .node circle.state-end{fill:black;stroke:white;stroke-width:1.5}#mermaid-svg-J65WbxpJtCZ9sRtG #statediagram-barbEnd{fill:#9370db}#mermaid-svg-J65WbxpJtCZ9sRtG .statediagram-cluster rect{fill:#ECECFF;stroke:#9370db;stroke-width:1px}#mermaid-svg-J65WbxpJtCZ9sRtG .statediagram-cluster rect.outer{rx:5px;ry:5px}#mermaid-svg-J65WbxpJtCZ9sRtG .statediagram-state .divider{stroke:#9370db}#mermaid-svg-J65WbxpJtCZ9sRtG .statediagram-state .title-state{rx:5px;ry:5px}#mermaid-svg-J65WbxpJtCZ9sRtG .statediagram-cluster.statediagram-cluster .inner{fill:white}#mermaid-svg-J65WbxpJtCZ9sRtG .statediagram-cluster.statediagram-cluster-alt .inner{fill:#e0e0e0}#mermaid-svg-J65WbxpJtCZ9sRtG .statediagram-cluster .inner{rx:0;ry:0}#mermaid-svg-J65WbxpJtCZ9sRtG .statediagram-state rect.basic{rx:5px;ry:5px}#mermaid-svg-J65WbxpJtCZ9sRtG .statediagram-state rect.divider{stroke-dasharray:10,10;fill:#efefef}#mermaid-svg-J65WbxpJtCZ9sRtG .note-edge{stroke-dasharray:5}#mermaid-svg-J65WbxpJtCZ9sRtG .statediagram-note rect{fill:#fff5ad;stroke:#aa3;stroke-width:1px;rx:0;ry:0}:root{--mermaid-font-family: '"trebuchet ms", verdana, arial';--mermaid-font-family: "Comic Sans MS", "Comic Sans", cursive}#mermaid-svg-J65WbxpJtCZ9sRtG .error-icon{fill:#522}#mermaid-svg-J65WbxpJtCZ9sRtG .error-text{fill:#522;stroke:#522}#mermaid-svg-J65WbxpJtCZ9sRtG .edge-thickness-normal{stroke-width:2px}#mermaid-svg-J65WbxpJtCZ9sRtG .edge-thickness-thick{stroke-width:3.5px}#mermaid-svg-J65WbxpJtCZ9sRtG .edge-pattern-solid{stroke-dasharray:0}#mermaid-svg-J65WbxpJtCZ9sRtG .edge-pattern-dashed{stroke-dasharray:3}#mermaid-svg-J65WbxpJtCZ9sRtG .edge-pattern-dotted{stroke-dasharray:2}#mermaid-svg-J65WbxpJtCZ9sRtG .marker{fill:#333}#mermaid-svg-J65WbxpJtCZ9sRtG .marker.cross{stroke:#333} :root { --mermaid-font-family: "trebuchet ms", verdana, arial;}</style> <style>#mermaid-svg-J65WbxpJtCZ9sRtG { color: rgba(0, 0, 0, 0.75); font: ; }</style>
點擊事件
java內部更新
觸發JS狀態更新
初始化
渲染
onTriggerFormEvent
更新Status
更新卡片

觸發效果是這樣的:

總結

至此,JsFACard 這個專案就已經掌握得差不多了,下一步學習的目標就打算學習一下另一個更加復雜的案例:JS 計步器卡片,


本文正在參與“有獎征文 | HarmonyOS 征文大賽”活動,活動鏈接為:https://marketing.csdn.net/p/ad3879b53f4b8b31db27382b5fc65bbc

轉載請註明出處,本文鏈接:https://www.uj5u.com/qianduan/291062.html

標籤:其他

上一篇:都說WEB前端飽和了,但我自學找到了11K的作業,就是掌握了這些技術堆疊

下一篇:SSM整合案例

標籤雲
其他(157675) Python(38076) JavaScript(25376) Java(17977) C(15215) 區塊鏈(8255) C#(7972) AI(7469) 爪哇(7425) MySQL(7132) html(6777) 基礎類(6313) sql(6102) 熊猫(6058) PHP(5869) 数组(5741) R(5409) Linux(5327) 反应(5209) 腳本語言(PerlPython)(5129) 非技術區(4971) Android(4554) 数据框(4311) css(4259) 节点.js(4032) C語言(3288) json(3245) 列表(3129) 扑(3119) C++語言(3117) 安卓(2998) 打字稿(2995) VBA(2789) Java相關(2746) 疑難問題(2699) 细绳(2522) 單片機工控(2479) iOS(2429) ASP.NET(2402) MongoDB(2323) 麻木的(2285) 正则表达式(2254) 字典(2211) 循环(2198) 迅速(2185) 擅长(2169) 镖(2155) 功能(1967) .NET技术(1958) Web開發(1951) python-3.x(1918) HtmlCss(1915) 弹簧靴(1913) C++(1909) xml(1889) PostgreSQL(1872) .NETCore(1853) 谷歌表格(1846) Unity3D(1843) for循环(1842)

熱門瀏覽
  • vue移動端上拉加載

    可能做得過于簡單或者比較low,請各位大佬留情,一起探討技術 ......

    uj5u.com 2020-09-10 04:38:07 more
  • 優美網站首頁,頂部多層導航

    一個個人用的瀏覽器首頁,可以把一下常用的網站放在這里,平常打開會比較方便。 第一步,HTML代碼 <script src=https://www.cnblogs.com/szharf/p/"js/jquery-3.4.1.min.js"></script> <div id="navigate"> <ul> <li class="labels labels_1"> ......

    uj5u.com 2020-09-10 04:38:47 more
  • 頁面為要加<!DOCTYPE html>

    最近因為寫一個js函式,需要用到$(window).height(); 由于手寫demo的時候,過于自信,其實對前端方面的認識也不夠體系,用文本檔案直接敲出來的html代碼,第一行沒有加上<!DOCTYPE html> 導致了$(window).height();的結果直接是整個document的高 ......

    uj5u.com 2020-09-10 04:38:52 more
  • WordPress網站程式手動升級要做好資料備份

    WordPress博客網站程式在進行升級前,必須要做好網站資料的備份,這個問題良家佐言是遇見過的;在剛開始接觸WordPress博客程式的時候,因為升級問題和博客網站的修改的一些嘗試,良家佐言是吃盡了苦頭。因為購買的是西部數碼的空間和域名,每當佐言把自己的WordPress博客網站搞到一塌糊涂的時候 ......

    uj5u.com 2020-09-10 04:39:30 more
  • WordPress程式不能升級為5.4.2版本的原因

    WordPress是一款個人博客系統,受到英文博客愛好者和中文博客愛好者的追捧,并逐步演化成一款內容管理系統軟體;它是使用PHP語言和MySQL資料庫開發的,用戶可以在支持PHP和MySQL資料庫的服務器上使用自己的博客。每一次WordPress程式的更新,就會牽動無數WordPress愛好者的心, ......

    uj5u.com 2020-09-10 04:39:49 more
  • 使用CSS3的偽元素進行首字母下沉和首行改變樣式

    網頁中常見的一種效果,首字改變樣式或者首行改變樣式,效果如下圖。 代碼: <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, ......

    uj5u.com 2020-09-10 04:40:09 more
  • 關于a標簽的講解

    什么是a標簽? <a> 標簽定義超鏈接,用于從一個頁面鏈接到另一個頁面。 <a> 元素最重要的屬性是 href 屬性,它指定鏈接的目標。 a標簽的語法格式:<a href=https://www.cnblogs.com/summerxbc/p/"指定要跳轉的目標界面的鏈接">需要展示給用戶看見的內容</a> a標簽 在所有瀏覽器中,鏈接的默認外觀如下: 未被訪問的鏈接帶 ......

    uj5u.com 2020-09-10 04:40:11 more
  • 前端輪播圖

    在需要輪播的頁面是引入swiper.min.js和swiper.min.css swiper.min.js地址: 鏈接:https://pan.baidu.com/s/15Uh516YHa4CV3X-RyjEIWw 提取碼:4aks swiper.min.css地址 鏈接:https://pan.b ......

    uj5u.com 2020-09-10 04:40:13 more
  • 如何設定html中的背景圖片(全屏顯示,且不拉伸)

    1 <style>2 body{background-image:url(https://uploadbeta.com/api/pictures/random/?key=BingEverydayWallpaperPicture); 3 background-size:cover;background ......

    uj5u.com 2020-09-10 04:40:16 more
  • Java學習——HTML詳解(上)

    HTML詳解 初識HTML Hyper Text Markup Language(超文本標記語言) 1 <!--DOCTYPE:告訴瀏覽器我們要使用什么規范--> 2 <!DOCTYPE html> 3 <html lang="en"> 4 <head> 5 <!--meta 描述性的標簽,描述一些 ......

    uj5u.com 2020-09-10 04:40:33 more
最新发布
  • 我的第一個NPM包:panghu-planebattle-esm(胖虎飛機大戰)使用說明

    好家伙,我的包終于開發完啦 歡迎使用胖虎的飛機大戰包!! 為你的主頁添加色彩 這是一個有趣的網頁小游戲包,使用canvas和js開發 使用ES6模塊化開發 效果圖如下: (覺得圖片太sb的可以自己改) 代碼已開源!! Git: https://gitee.com/tang-and-han-dynas ......

    uj5u.com 2023-04-20 07:59:23 more
  • 生產事故-走近科學之消失的JWT

    入職多年,面對生產環境,盡管都是小心翼翼,慎之又慎,還是難免捅出簍子。輕則滿頭大汗,面紅耳赤。重則系統停擺,損失資金。每一個生產事故的背后,都是寶貴的經驗和教訓,都是專案成員的血淚史。為了更好地防范和遏制今后的各類事故,特開此專題,長期更新和記錄大大小小的各類事故。有些是親身經歷,有些是經人耳傳口授 ......

    uj5u.com 2023-04-18 07:55:04 more
  • 記錄--Canvas實作打飛字游戲

    這里給大家分享我在網上總結出來的一些知識,希望對大家有所幫助 打開游戲界面,看到一個畫面簡潔、卻又富有挑戰性的游戲。螢屏上,有一個白色的矩形框,里面不斷下落著各種單詞,而我需要迅速地輸入這些單詞。如果我輸入的單詞與螢屏上的單詞匹配,那么我就可以獲得得分;如果我輸入的單詞錯誤或者時間過長,那么我就會輸 ......

    uj5u.com 2023-04-04 08:35:30 more
  • 了解 HTTP 看這一篇就夠

    在學習網路之前,了解它的歷史能夠幫助我們明白為何它會發展為如今這個樣子,引發探究網路的興趣。下面的這張圖片就展示了“互聯網”誕生至今的發展歷程。 ......

    uj5u.com 2023-03-16 11:00:15 more
  • 藍牙-低功耗中心設備

    //11.開啟藍牙配接器 openBluetoothAdapter //21.開始搜索藍牙設備 startBluetoothDevicesDiscovery //31.開啟監聽搜索藍牙設備 onBluetoothDeviceFound //30.停止監聽搜索藍牙設備 offBluetoothDevi ......

    uj5u.com 2023-03-15 09:06:45 more
  • canvas畫板(滑鼠和觸摸)

    <!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title>canves</title> <style> #canvas { cursor:url(../images/pen.png),crosshair; } #canvasdiv{ bo ......

    uj5u.com 2023-02-15 08:56:31 more
  • 手機端H5 實作自定義拍照界面

    手機端 H5 實作自定義拍照界面也可以使用 MediaDevices API 和 <video> 標簽來實作,和在桌面端做法基本一致。 首先,使用 MediaDevices.getUserMedia() 方法獲取攝像頭媒體流,并將其傳遞給 <video> 標簽進行渲染。 接著,使用 HTML 的 < ......

    uj5u.com 2023-01-12 07:58:22 more
  • 記錄--短視頻滑動播放在 H5 下的實作

    這里給大家分享我在網上總結出來的一些知識,希望對大家有所幫助 短視頻已經無數不在了,但是主體還是使用 app 來承載的。本文講述 H5 如何實作 app 的視頻滑動體驗。 無聲勝有聲,一圖頂百辯,且看下圖: 網址鏈接(需在微信或者手Q中瀏覽) 從上圖可以看到,我們主要實作的功能也是本文要講解的有: ......

    uj5u.com 2023-01-04 07:29:05 more
  • 一文讀懂 HTTP/1 HTTP/2 HTTP/3

    從 1989 年萬維網(www)誕生,HTTP(HyperText Transfer Protocol)經歷了眾多版本迭代,WebSocket 也在期間萌芽。1991 年 HTTP0.9 被發明。1996 年出現了 HTTP1.0。2015 年 HTTP2 正式發布。2020 年 HTTP3 或能正... ......

    uj5u.com 2022-12-24 06:56:02 more
  • 【HTML基礎篇002】HTML之form表單超詳解

    ??一、form表單是什么

    ??二、form表單的屬性

    ??三、input中的各種Type屬性值

    ??四、標簽 ......

    uj5u.com 2022-12-18 07:17:06 more