初窺鴻蒙

凹凸實驗室發表於2021-06-10

一、什麼是鴻蒙

鴻蒙即 HarmonyOS ,是華為公司推出的支援手機、平板、智慧穿戴、智慧屏、車機等多種終端裝置的分散式作業系統,並且它提供了多語言開發的 API,支援 Java、XML、C/C++、JS、CSS、HML(類 html 的鴻蒙自己的標記語言)等開發語言,而且它提供多種響應式佈局方案,支援柵格化佈局,可以使用同一套程式碼部署在手機手錶平板等多種不同尺寸螢幕的裝置上。

二、開發準備

2.1 環境安裝

開發鴻蒙軟體需要用到 HUAWEI DevEco Studio,它提供了模板建立、開發、編譯、除錯、釋出等服務。

1、登入 HarmonysOS 應用開發門戶,點選右上角註冊按鈕,註冊開發者帳號。

2、進入 HUAWEI DevEco Studio 產品頁,登入華為開發者賬號後下載 DevEco Studio 安裝包並進行安裝。

3、啟動 DevEco Studio,根據工具引導下載 HarmonyOS SDK。
下載HarmonyOS SDK

4、下載 HarmonyOS SDK 成功後會進入歡迎頁,點選歡迎頁中的 Configure > Settings 開啟設定視窗,點選 Apparance&behavior > System settings > HarmonyOS SDK,選中 JS SDK 進行下載。
下載JS SDK

至此開發環境安裝完成。

2.2 新建專案

點選選單欄中的 File > New > New Project
新建專案
選擇需要開發的專案裝置,然後選擇 Empty Featrue Ability(JS) 後,點選 Next,此時會出現專案的資訊配置
專案資訊配置
點選 Finish,一個新的專案就被建立出來了。

2.3 專案目錄

專案目錄

使用 JS SDK 進行開發的話,需要關注的是 entry > src > main > js 資料夾,其中:

  • i18n 目錄下存放的是多語言的 json 檔案

    en-US.json 為英文模式展示的內容
    zh-CN.json 為中文模式展示的內容

  • pages 下存放的是專案的多個頁面,每個頁面都由 hml、js 和 css 組成

    hml 檔案定義了頁面的佈局、頁面中用到的元件,以及這些元件的層級關係
    js 檔案定義了頁面的業務邏輯,比如資料繫結、事件處理等
    css 檔案定義了 index 頁面的樣式

  • app.js 中存放的是全域性的 js 邏輯和 app 的生命週期管理

除此之外,還可以自己建立 common 目錄用於存放公共資原始檔,比如:公共樣式和公用方法。

2.4 生命週期

生命週期分為應用的生命週期以及頁面的生命週期

生命週期

其中,應用的生命週期主要分為應用建立時呼叫的 onCreate,以及應用銷燬時觸發的 onDestroy。

而頁面的生命週期分為:

  • onInit:頁面資料準備完成時觸發;
  • onReady:頁面編譯完成時觸發;
  • onShow:頁面展示時觸發;
  • onHide:頁面被隱藏時觸發;
  • onDestroy:頁面被銷燬時觸發;

由於JS UI只支援應用同時執行並展示一個頁面,因此當應用從頁面 A 跳轉到頁面 B 時,首先觸發頁面 A 的 onHide、onDestroy 函式,然後依次呼叫頁面 B 的 onInit、onReady、onShow 函式來初始化和顯示頁面 B。

三、元件

在 hml 檔案中,元件分為容器元件、基礎元件、媒體元件、畫布元件、柵格元件,由於篇幅有限,這裡只列舉一下元件名稱和對應的描述,感興趣的同學可以點選 元件文件 進行查閱。

3.1 容器元件

元件名 描述
div 基礎容器
list 列表容器
list-item list 的子元件,用來展示列表具體 item
list-item-group list 的子元件,用來展示分組,寬度預設充滿 list 元件
badge 新事件標記容器
dialog 自定義彈窗容器
panel 彈出式可滑動皮膚容器
popup 氣泡提示容器
refresh 下拉重新整理容器
stack 堆疊容器,子元件按照順序依次入棧,後一個子元件覆蓋前一個子元件
stepper 步驟導航器。當完成一個任務需要多個步驟時,可以使用步驟導航器展示當前進展
stepper-item 步驟導航器子元件,作為步驟導航器某一個步驟的內容展示元件
swiper 滑動切換容器
tabs tab 頁標籤切換容器
tab-bar tabs 的子元件,用來展示 tab 的標籤區
tab-content tabs 的子元件,用來展示 tab 的內容區

3.2 基礎元件

元件名 描述
image 圖片元件,用來渲染展示圖片
image-animator 圖片幀動畫播放器
text 文字元件,用於展示文字資訊
span text 的子元件,提供文字修飾能力
textarea 多行文字輸入框
input 互動式元件,包括單選框,多選框,按鈕和單行文字輸入框
button 按鈕元件,包括膠囊按鈕、圓形按鈕、文字按鈕、弧形按鈕、下載按鈕
chart 圖表元件,用於呈現線形圖、柱狀圖、量規圖介面
divider 提供分隔器元件,分隔不同內容塊/內容元素。可用於列表或介面佈局
label 為 input、button、textarea 元件定義相應的標註,點選該標註時會觸發繫結元件的點選效果
marquee 跑馬燈元件,用於展示一段單行滾動的文字
menu 選單元件,作為臨時性彈出視窗,用於展示使用者可執行的操作
select 下拉選擇元件,可讓使用者在多個選項之間選擇
option 可作為 menu 或 select 元件的子元件,用來展示具體專案
picker 滑動選擇器元件,型別支援普通選擇器,日期選擇器,時間選擇器,時間日期選擇器,多列文字選擇器
picker-view 嵌入頁面的滑動選擇器
piece 一種塊狀的入口元件,可包含圖片和文字,常用於展示收件人
progress 進度條元件,用於顯示內容載入或操作處理進度
qrcode 二維碼元件,用於生成並顯示二維碼
rating 評分條元件
search 搜尋框元件,用於提供使用者搜尋內容的輸入區域
slider 滑動條元件,用來快速調節設定值,如音量、亮度等
switch 開關元件,用於開啟或關閉某個功能
toolbar 工具欄元件,放在介面底部,用於展示針對當前介面的操作選項
toolbar-item toolbar 子元件,用於展示工具欄上的一個操作選項
toggle 狀態按鈕元件,用於從一組選項中進行選擇

3.3 媒體元件

媒體元件暫時只有 video 元件一個,除了智慧穿戴裝置不支援外,手機、平板、智慧屏裝置均支援該元件,它為裝置提供了視訊播放功能。

3.4 畫布元件

畫布元件展示只有 canvas 元件一個,手機、平板、智慧屏、智慧穿戴裝置均支援該元件,它為裝置提供了自定義繪製圖形的能力。

3.5 柵格元件

元件名 描述
grid-container 柵格佈局容器根節點
grid-row grid-row 是柵格佈局容器 grid-container 的子容器元件,使用 flex 橫向佈局,排列每個 grid-col 容器,justify-content 與 align-items 預設為 flex-start,支援折行顯示
grid-col grid-row 的子容器元件

柵格系統有 Margins, Gutters, Columns 三個屬性:

  • Margins:用於控制元素距離螢幕最邊緣的距離
  • Gutters:用來控制元素和元素之間的距離關係
  • Columns:用來輔助佈局的主要定位工具,不同的螢幕尺寸匹配不同的 Columns 數量來輔助佈局定位,它會根據實際裝置的寬度和 Columns 數量自動計算每一個 Columns 的寬度

柵格系統

不同的裝置根據水平寬度 px,顯示不同數量的柵格數:

xs : 0px < 水平解析度 < 320px:2 Columns 柵格;

sm : 320px <= 水平解析度 < 600px:4 Columns 柵格;

md : 600px <= 水平解析度 < 840px:8 Columns 柵格;

lg : 840px <= 水平解析度:12 Columns 柵格。

四、HML語法

HML(HarmonyOS Markup Language)是一套類 HTML 的標記語言,通過元件,事件構建出頁面的內容。頁面具備事件繫結、資料繫結、列表渲染、條件渲染和邏輯控制等能力。

4.1 事件繫結

hml 中事件繫結預設返回一個事件物件引數,可以通過該引數獲取事件資訊,同時也可以傳遞額外引數。

<!-- xxx.hml -->
<div>
  <!-- 正常格式 -->
  <div onclick="clickfunc"></div>
  <!-- 縮寫 -->
  <div @click="clickfunc('hello')"></div>
  <!-- 使用事件冒泡模式繫結事件回撥函式 -->
  <div on:touchstart.bubble="touchstartfunc"></div>
  <!-- 使用事件捕獲模式繫結事件回撥函式 -->
  <div on:touchstart.capture="touchstartfunc"></div>
  <!-- on:{event}等價於on:{event}.bubble -->
  <div on:touchstart="touchstartfunc"></div>
  <!-- 繫結事件回撥函式,但阻止事件向上傳遞 -->
  <div grab:touchstart.bubble="touchstartfunc"></div>
  <!-- 繫結事件回撥函式,但阻止事件向下傳遞 -->
  <div grab:touchstart.capture="touchstartfunc"></div>
  <!-- grab:{event}等價於grab:{event}.bubble -->
  <div grab:touchstart="touchstartfunc"></div>
</div>
// xxx.js
export default {
  data: {
    text: '',
  },
  clickfunc: function(str, e) {
    console.log(e);
    this.text = str;
  },
  touchstartfunc: function(e) {
    console.log(e);
  }
}

4.2 資料繫結

資料繫結的形式分兩種:資料初始化,資料更新
資料更新流程

hml 只支援資料層到檢視層的單向資料繫結。
檢視層想改變資料層,只能通過繫結事件的方式實現。

4.2.1 資料初始化

hml 中的資料都來自於對應 js 中的 data 物件,因此在初始化頁面時,在 data 物件中寫入資料,hml 中就可以通過 {{}} 的形式繫結資料。

// xxx.js
export default {
  data: {
    text: 'HELLO WORLD'
  }
}
<!-- xxx.hml -->
<div>{{text}}</div>

4.2.2 資料更新

通過為頁面元素繫結事件,可以呼叫方法更新資料,從而觸發檢視更新資料

// xxx.js
export default {
  data: {
    text: 'HELLO WORLD'
  },
  changeText: function() {
    this.$set('text', '你好,世界');
  }
}
<!-- xxx.hml -->
<div @click='changeText'>{{text}}</div>

4.3 列表渲染

hml 中需要進行列表渲染的話只需在元件上新增 for 屬性並繫結需要渲染的資料,同時可自定義變數和索引的名稱:

// xxx.js
export default {
  data: {
    array: [
      {id: 1, name: '老周', age: 28}, 
      {id: 2, name: '老李', age: 29},
    ],
  },
  changeText: function(val, index) {
    if (val === "老李"){
      this.array.splice(index, 1, {id:2, name: '老王', age: 30});
    } else {
      this.array.splice(index, 1, {id:3, name: '老鄭', age: 31});
    }
  },
}
<!-- xxx.hml -->
<div class="array-container">
  <!-- div列表渲染 -->
  <!-- 預設$item代表陣列中的元素, $idx代表陣列中的元素索引 -->
  <div for="{{array}}" tid="id" onclick="changeText($item.name, $idx)">
    <text>{{$idx}}.{{$item.name}}</text>
  </div>
  <!-- 自定義元素變數名稱 -->
  <div for="{{value in array}}" tid="id" onclick="changeText(value.name, $idx)">    
    <text>{{$idx}}.{{value.name}}</text>
  </div>
  <!-- 自定義元素變數、索引名稱 -->
  <div for="{{(index, value) in array}}" tid="id" onclick="changeText(value.name, index)">    
    <text>{{index}}.{{value.name}}</text>
  </div>
</div>

陣列中的每個元素必須存在 tid 指定的資料屬性,且必須具有唯一性。
針對陣列內的資料修改,請使用 splice 方法生效資料繫結變更

4.4 條件渲染

hml 中實現條件渲染有兩種方式,分別是為元件新增 if/elif/else 或 show 屬性,它們的區別在於 if/elif/else 屬性不符合條件判斷則不會在 vdom 中構建,而 show 屬性為 false 時雖然不會渲染,但是會在 vdom 中構建,只是設定了 display 樣式為 none。

因此出於效能因素考慮,顯示隱藏狀態需要頻繁切換推薦使用 show,顯示狀態改變次數較少則使用 if/elif/else。

// xxx.js
export default {
  data: {
    show: false,
    display: true,
    visible: false
  },
  toggle: function() {
    this.visible = !this.visible;
  }
}
<!-- xxx.hml -->
<div class="container">
  <text if="{{show}}"> 你好,世界 </text>
  <text elif="{{display}}"> hi </text>
  <text else> Hello World </text>
  
  <button class="btn" type="capsule" value="toggle" onclick="toggle"></button>
  <text show="{{visible}}" > Hello World! </text>
</div>

當使用 if/elif/else 寫法時,節點必須是兄弟節點,否則編譯無法通過
禁止在同一個元素上同時設定 for 和 if 屬性

4.5 邏輯控制塊

hml 中提供了 控制塊,它不會被當作真實的節點編譯,但是隻支援 for 和 if 屬性。

4.6 自定義元件

HML 可以通過 element 標籤引用模板檔案,通過它可以實現自定義元件。

<!-- template.hml -->
<div class="item"> 
  <text>Name: {{name}}</text>
  <text>Age: {{age}}</text>
</div>
<!-- index.hml -->
<element name='man' src='../../common/template.hml'></element>
<div>
  <man name="老朱" age="28"></man>
</div>

其中 element 標籤的 name 屬性則為自定義元件的名稱,src 屬性為自定義元件相對該檔案的路徑,可以為自定義元件標籤新增屬性向其傳遞資料,自定義元件內也可使用 $emit 方法向父元件傳遞引數。

五、JS語法

鴻蒙中的 js 檔案支援 ES6 語法。

5.1 引用

鴻蒙中可以使用 import 方法引入功能模組或 js 程式碼:

import router from '@system.router'
import utils from '../../common/utils.js'

5.2 獲取app物件

在頁面中可以使用 this.$app.$def 獲取在 app.js 中暴露的物件。

// app.js
export default {
  onCreate() {
    console.info('App onCreate');
  },
  onDestroy() {
    console.info('App onDestroy');
  },
  globalData: {
    appData: 'appData',
    appVersion: '2.0',
  },
  changeAppVer () {
    this.globalData.appVersion = '3.0';
  }
};
// index.js
export default {
  data: {
    appData: 'localData',
    appVersion:'1.0',
  },
  onInit() {
    this.appData = this.$app.$def.globalData.appData;
    this.appVersion = this.$app.$def.globalData.appVersion;
  },
  pageMethod() {
    this.$app.$def.changeAppVer();
  }
}

5.3 頁面物件

屬性 型別 描述
data Object/Function 頁面的資料模型
$refs Object 持有註冊過 ref 屬性的 DOM 元素或子元件例項的物件
props Array/Object props 用於接收父元件傳遞過來的引數
computed Object 計算屬性,用於在讀取或設定進行預先處理,計算屬性的結果會被快取
private Object 頁面的資料模型,private 下的資料屬性只能由當前頁面修改
public Object 頁面的資料模型,public 下的資料屬性的行為與 data 保持一致

5.4 方法

5.4.1 資料方法

屬性 型別 引數 描述
$set Function key: string, value: any 新增新的資料屬性或者修改已有資料屬性。用法:this.$set('key',value)。
$delete Function key: string 刪除資料屬性。用法:this.$delete('key')。
export default {
  data: {
    appInfo: {
      OS: 'HarmonyOS',
      Version: '2.0',
    },
  },
  changeAppInfo() {
    this.$set('appInfo.Version', '3.0');
    console.log(this.appInfo);
    this.$delete('appInfo');
    console.log(this.appInfo);
  }
}

5.4.2 事件方法

鴻蒙中可以使用 $watch 方法觀察 data 中的屬性變化,如果屬性值改變,則會觸發繫結的事件。

export default { 
  props: ['title'],
  onInit() {
    this.$watch('title', 'onPropChange');
  },
  onPropChange(newV, oldV) {
    console.info('title屬性由'+ oldV +'變化為' + newV);
  },
}

5.5 路由

{
  "pages": [
    "pages/index/index",
    "pages/detail/index"
  ]
}

鴻蒙 app 中頁面的路由資訊儲存在 src > main > config.json 檔案中的 pages 內,引入 @system.router 後,呼叫其 push 方法傳入需要跳轉頁面的 uri,即可完成跳轉,也可使用其 back 方法回到首頁。

import router from '@system.router';
export default {
  launch() {
    router.push ({
      uri: 'pages/detail/index',
    });
  },
  goBack() {
    router.back();
  }
}

六、CSS語法

CSS 是描述 HML 頁面結構的樣式語言,所有元件均存在系統預設樣式,也可在頁面 CSS 樣式檔案中對元件、頁面自定義不同的樣式。

6.1 尺寸單位

鴻蒙中尺寸單位有兩種,px(邏輯畫素) 以及百分比。

{
  "window": {
    "designWidth": 720,
    "autoDesignWidth": false
  }
}

邏輯畫素的配置在 src > main > config.json 檔案中的 window 內,designWidth 為螢幕的邏輯寬度,預設為720px,實際顯示時會將頁面佈局縮放至螢幕實際寬度,如100px在實際寬度為1440物理畫素的螢幕上,實際渲染為200物理畫素。

當 autoDesignWidth 設定為 true 時,邏輯畫素 px 將按照螢幕密度進行縮放,如 100px 在螢幕密度為3的裝置上,實際渲染為300物理畫素。

而百分比單位表示該元件佔父元件尺寸的百分比,如元件的 width 設定為50%,代表其寬度為父元件的50%。

6.2 樣式匯入

CSS 樣式檔案支援 @import 語句,匯入 CSS 檔案。

@import '../../common/style.css';

七、總結

使用鴻蒙的 JS SDK 開發 App,整體的專案結構、生命週期以及開發流程很像微信的小程式,而 hml 和 JS 的語法又很像 Vue,整個流程走下來,感覺對 web 開發者而言還是很友好的,相信有 Web 前端開發基礎的小夥伴們都可以快速的上手。

由於篇幅有限,文中還有很多沒有提到的鴻蒙賦予開發者的硬體呼叫能力,希望鴻蒙可以越做越好,讓越來越多的開發者和使用者加入到鴻蒙的大生態中來。

八、參考


歡迎關注凹凸實驗室部落格:aotu.io

或者關注凹凸實驗室公眾號(AOTULabs),不定時推送文章:

歡迎關注凹凸實驗室公眾號

相關文章