一、什么是鴻蒙
鴻蒙即 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。
4、下載 HarmonyOS SDK 成功后會進入歡迎頁,點擊歡迎頁中的 Configure > Settings 打開設置窗口,點擊 Apparance&behavior > System settings > HarmonyOS 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 中提供了
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),不定時推送文章: