目錄
1 ->?HML語法
1.1 ->?頁面結構
1.2 ->?數據綁定
1.3 -> 普通事件綁定
1.4 ->?冒泡事件綁定5+
1.5 -> 捕獲事件綁定5+
1.6 -> 列表渲染
1.7 -> 條件渲染
1.8 -> 邏輯控制塊
1.9 -> 模板引用
2 -> CSS語法
2.1 -> 尺寸單位
2.2 -> 樣式導入
2.3 -> 聲明樣式
2.4 -> 選擇器
2.5 -> 選擇器優先級
2.6 -> 偽類
2.7 -> 樣式預編譯
2.8 -> CSS樣式繼承6+
3 -> JS語法
3.1 -> 語法
3.2 -> 對象
3.3 -> 方法
3.4 -> 獲取DOM元素
3.5 -> 獲取ViewModel
1 ->?HML語法
HML(HarmonyOS Markup Language)是一套類HTML的標記語言,通過組件,事件構建出頁面的內容。頁面具備數據綁定、事件綁定、列表渲染、條件渲染和邏輯控制等高級能力。
1.1 ->?頁面結構
<!-- test.hml --><div class="item-container"><text class="item-title">Image Show</text><div class="item-content"><image src="/common/xxx.png" class="image"></image></div></div>
1.2 ->?數據綁定
<!-- test.hml --><div onclick="changeText"><text> {{content[1]}} </text></div>
/*test.css*/
.container{margin: 200px;
}
// test.js
export default {data: {content: ['Hello World!', 'Welcome to my world!']},changeText: function() {this.content.splice(1, 1, this.content[0]);}
}
說明
-
針對數組內的數據修改,請使用splice方法生效數據綁定變更。
-
hml文件中的js表達式不支持ES6語法。
1.3 -> 普通事件綁定
事件通過'on'或者'@'綁定在組件上,當組件觸發事件時會執行JS文件中對應的事件處理函數。
事件支持的寫法有:
-
"funcName":funcName為事件回調函數名(在JS文件中定義相應的函數實現)。
-
"funcName(a,b)":函數參數例如a,b可以是常量,或者是在JS文件中的data中定義的變量(前面不用寫this.)。
-
示例
<!-- test.hml --><div class="container"><text class="title">{{count}}</text><div class="box"><input type="button" class="btn" value="increase" onclick="increase" /><input type="button" class="btn" value="decrease" @click="decrease" /><!-- 傳遞額外參數 --><input type="button" class="btn" value="double" @click="multiply(2)" /><input type="button" class="btn" value="decuple" @click="multiply(10)" /><input type="button" class="btn" value="square" @click="multiply(count)" /></div></div>
/* test.css */
.container {display: flex;flex-direction: column;justify-content: center;align-items: center;left: 0px;top: 0px;width: 454px;height: 454px;
}
.title {font-size: 30px;text-align: center;width: 200px;height: 100px;
}
.box {width: 454px;height: 200px;justify-content: center;align-items: center;flex-wrap: wrap;
}
.btn {width: 200px;border-radius: 0;margin-top: 10px;margin-left: 10px;
}
// test.js
export default {data: {count: 0},increase() {this.count++;},decrease() {this.count--;},multiply(multiplier) {this.count = multiplier * this.count;}
};
1.4 ->?冒泡事件綁定5+
冒泡事件綁定包括:
-
綁定冒泡事件:on:{event}.bubble。on:{event}等價于on:{event}.bubble。
-
綁定并阻止冒泡事件向上冒泡:grab:{event}.bubble。grab:{event}等價于grab:{event}.bubble。
-
示例
<!-- test.hml --><div><!-- 使用事件冒泡模式綁定事件回調函數。5+ -->;
<div on:touchstart.bubble="touchstartfunc"></div><div on:touchstart="touchstartfunc"></div><!-- 綁定事件回調函數,但阻止事件向上傳遞。5+ --><div grab:touchstart.bubble="touchstartfunc"></div><div grab:touchstart="touchstartfunc"></div><!-- 使用事件冒泡模式綁定事件回調函數。6+ --><div on:click.bubble="clickfunc"></div><div on:click="clickfunc"></div><!-- 綁定事件回調函數,但阻止事件向上傳遞。6+ --><div grab:click.bubble="clickfunc"></div><div grab:click="clickfunc"></div></div>
// test.js
export default {clickfunc: function(e) {console.log(e);},touchstartfuc: function(e) {console.log(e);},
}
說明
采用舊寫法(onclick)的事件綁定在最小API版本6以下時采用不冒泡處理,在最小API版本為6及6以上時采用冒泡處理。
1.5 -> 捕獲事件綁定5+
Touch觸摸類事件支持捕獲,捕獲階段位于冒泡階段之前,捕獲事件先到達父組件然后達到子組件。
捕獲事件綁定包括:
-
綁定捕獲事件:on:{event}.capture。
-
綁定并阻止事件向下傳遞:grab:{event}.capture。
-
示例
<!-- test.hml --><div><!-- 使用事件捕獲模式綁定事件回調函數。5+ --><div on:touchstart.capture="touchstartfunc"></div><!-- 綁定事件回調函數,但阻止事件向下傳遞。5+ --><div grab:touchstart.capture="touchstartfunc"></div></div>
// xxx.js
export default {touchstartfuc: function(e) {console.log(e);},
}
1.6 -> 列表渲染
<!-- test.hml --><div class="array-container" style="flex-direction: column;margin: 200px;"><!-- div列表渲染 --><!-- 默認$item代表數組中的元素, $idx代表數組中的元素索引 --><div for="{{array}}" tid="id" onclick="changeText"><text>{{$idx}}.{{$item.name}}</text></div><!-- 自定義元素變量名稱 --><div for="{{value in array}}" tid="id" onclick="changeText"><text>{{$idx}}.{{value.name}}</text></div><!-- 自定義元素變量、索引名稱 --><div for="{{(index, value) in array}}" tid="id" onclick="changeText"><text>{{index}}.{{value.name}}</text></div></div>
// test.js
export default {data: {array: [{id: 1, name: 'jack', age: 18},{id: 2, name: 'tony', age: 18},],},changeText: function() {if (this.array[1].name === "tony"){this.array.splice(1, 1, {id:2, name: 'Isabella', age: 18});} else {this.array.splice(2, 1, {id:3, name: 'Bary', age: 18});}},
}
tid屬性主要用來加速for循環的重渲染,旨在列表中的數據有變更時,提高重新渲染的效率。tid屬性是用來指定數組中每個元素的唯一標識,如果未指定,數組中每個元素的索引為該元素的唯一id。例如上述tid="id"表示數組中的每個元素的id屬性為該元素的唯一標識。for循環支持的寫法如下:
-
for="array":其中array為數組對象,array的元素變量默認為$item。
-
for="v in array":其中v為自定義的元素變量,元素索引默認為$idx。
-
for="(i, v) in array":其中元素索引為i,元素變量為v,遍歷數組對象array。
說明
-
數組中的每個元素必須存在tid指定的數據屬性,否則運行時可能會導致異常。
-
數組中被tid指定的屬性要保證唯一性,如果不是則會造成性能損耗。比如,示例中只有id和name可以作為tid字段,因為它們屬于唯一字段。
-
tid不支持表達式。
1.7 -> 條件渲染
條件渲染分為2種:if/elif/else和show。兩種寫法的區別在于:第一種寫法里if為false時,組件不會在vdom中構建,也不會渲染,而第二種寫法里show為false時雖然也不渲染,但會在vdom中構建;另外,當使用if/elif/else寫法時,節點必須是兄弟節點,否則編譯無法通過。實例如下:
<!-- test.hml --><div class="container"><button class="btn" type="capsule" value="toggleShow" onclick="toggleShow"></button><button class="btn" type="capsule" value="toggleDisplay" onclick="toggleDisplay"></button><text if="{{visible}}"> Hello-world1 </text><text elif="{{display}}"> Hello-world2 </text><text else> Hello-World </text></div>
/* test.css */
.container{flex-direction: column;align-items: center;
}
.btn{width: 280px;font-size: 26px;margin: 10px 0;
}
// test.js
export default {data: {visible: false,display: true,},toggleShow: function() {this.visible = !this.visible;},toggleDisplay: function() {this.display = !this.display;}
}
優化渲染優化:show方法。當show為true時,節點正常渲染;當為false時,僅僅設置display樣式為none。
<!-- test.hml --><div class="container"><button class="btn" type="capsule" value="toggle" onclick="toggle"></button><text show="{{visible}}" > Hello World </text></div>
/* test.css */
.container{flex-direction: column;align-items: center;
}
.btn{width: 280px;font-size: 26px;margin: 10px 0;
}
// test.js
export default {data: {visible: false,},toggle: function() {this.visible = !this.visible;},
}
說明
禁止在同一個元素上同時設置for和if屬性。
1.8 -> 邏輯控制塊
<block>控制塊使得循環渲染和條件渲染變得更加靈活;block在構建時不會被當作真實的節點編譯。注意block標簽只支持for和if屬性。
<!-- test.hml --><list><block for="glasses"><list-item type="glasses"><text>{{$item.name}}</text></list-item><block for="$item.kinds"><list-item type="kind"><text>{{$item.color}}</text></list-item></block></block></list>
// test.js
export default {data: {glasses: [{name:'sunglasses', kinds:[{name:'XXX',color:'XXX'},{name:'XXX',color:'XXX'}]},{name:'nearsightedness mirror', kinds:[{name:'XXX',color:'XXX'}]},],},
}
1.9 -> 模板引用
<!-- template.hml -->
<div class="item"> <text>Name: {{name}}</text><text>Age: {{age}}</text>
</div>
<!-- index.hml -->
<element name='comp' src='../../common/template.hml'></element>
<div><comp name="Tony" age="18"></comp>
</div>
2 -> CSS語法
CSS是描述HML頁面結構的樣式語言。所有組件均存在系統默認樣式,也可在頁面CSS樣式文件中對組件、頁面自定義不同的樣式。
2.1 -> 尺寸單位
-
邏輯像素px(文檔中以<length>表示):
- 默認屏幕具有的邏輯寬度為720px,實際顯示時會將頁面布局縮放至屏幕實際寬度,如100px在實際寬度為1440物理像素的屏幕上,實際渲染為200物理像素(從720px向1440物理像素,所有尺寸放大2倍)。
- 額外配置autoDesignWidth為true時,邏輯像素px將按照屏幕密度進行縮放,如100px在屏幕密度為3的設備上,實際渲染為300物理像素。應用需要適配多種設備時,建議采用此方法。
-
百分比(文檔中以<percentage>表示):表示該組件占父組件尺寸的百分比,如組件的width設置為50%,代表其寬度為父組件的50%。
2.2 -> 樣式導入
為了模塊化管理和代碼復用,CSS樣式文件支持 @import 語句,導入css文件。
2.3 -> 聲明樣式
每個頁面目錄下存在一個與布局hml文件同名的css文件,用來描述該hml頁面中組件的樣式,決定組件應該如何顯示。
1. 內部樣式,支持使用style、class屬性來控制組件的樣式。例如:
<!-- index.hml -->
<div class="container"><text style="color: red">Hello World</text>
</div>
/* index.css */
.container {justify-content: center;
}
2. 文件導入,合并外部樣式文件。例如,在common目錄中定義樣式文件style.css,并在index.css文件首行中進行導入:
/* style.css */
.title {font-size: 50px;
}
/* index.css */
@import '../../common/style.css';
.container {justify-content: center;
}
2.4 -> 選擇器
css選擇器用于選擇需要添加樣式的元素,支持的選擇器如下表所示:
選擇器 | 樣例 | 樣例描述 |
.class | .container | 用于選擇class="container"的組件。 |
#id | #titleld | 用于選擇id="titleId"的組件。 |
tag | text | 用于選擇text組件。 |
, | .title, .content | 用于選擇class="title"和class="content"的組件。 |
#id .class tag | #containerld .content text | 非嚴格父子關系的后代選擇器,選擇具有id="containerId"作為祖先元素,class="content"作為次級祖先元素的所有text組件。如需使用嚴格的父子關系,可以使用“>”代替空格,如:#containerId>.content。 |
示例:
<!-- 頁面布局test.hml -->
<div id="containerId" class="container"><text id="titleId" class="title">標題</text><div class="content"><text id="contentId">內容</text></div>
</div>
/* 頁面樣式test.css */
/\* 對所有div組件設置樣式 \*/
div {flex-direction: column;
}
/* 對class="title"的組件設置樣式 */
.title {font-size: 30px;
}
/* 對id="contentId"的組件設置樣式 */
#contentId {font-size: 20px;
}
/* 對所有class="title"以及class="content"的組件都設置padding為5px */
.title, .content {padding: 5px;
}
/\* 對class="container"的組件下的所有text設置樣式 \*/
.container text {color: \#007dff;
}
/\* 對class="container"的組件下的直接后代text設置樣式 \*/
.container > text {color: \#fa2a2d;
}
以上樣式運行效果如下:
其中“.container text”將“標題”和“內容”設置為藍色,而“.container > text”直接后代選擇器將“標題”設置為紅色。2者優先級相同,但直接后代選擇器聲明順序靠后,將前者樣式覆蓋。
2.5 -> 選擇器優先級
選擇器的優先級計算規則與w3c規則保持一致(只支持:內聯樣式,id,class,tag,后代和直接后代),其中內聯樣式為在元素style屬性中聲明的樣式。
當多條選擇器聲明匹配到同一元素時,各類選擇器優先級由高到低順序為:內聯樣式 > id > class > tag。
2.6 -> 偽類
css偽類是選擇器中的關鍵字,用于指定要選擇元素的特殊狀態。例如,:disabled狀態可以用來設置元素的disabled屬性變為true時的樣式。
除了單個偽類之外,還支持偽類的組合,例如,:focus:checked狀態可以用來設置元素的focus屬性和checked屬性同時為true時的樣式。支持的單個偽類如下表所示,按照優先級降序排列:
名稱 | 支持組件 | 描述 |
:diaabled | 支持disabled屬性的組件 | 表示disabled屬性變為true時的元素(不支持動畫樣式的設置)。 |
:active | 支持click事件的組件 | 表示被用戶激活的元素,如:被用戶按下的按鈕、被激活的tab-bar頁簽(不支持動畫樣式的設置)。 |
:waiting | button | 表示waiting屬性為true的元素(不支持動畫樣式的設置)。 |
:checked | input[type="checkbox"、type=“radio”]、switch | 表示checked屬性為true的元素(不支持動畫樣式的設置)。 |
偽類示例如下,設置按鈕的:active偽類可以控制被用戶按下時的樣式:
<!-- index.hml -->
<div class="container"><input type="button" class="button" value="Button"></input>
</div>
/* index.css */
.button:active {background-color: #888888;/*按鈕被激活時,背景顏色變為#888888 */
}
說明
針對彈窗類組件及其子元素不支持偽類效果,包括popup、dialog、menu、option、picker。
2.7 -> 樣式預編譯
預編譯提供了利用特有語法生成css的程序,可以提供變量、運算等功能,令開發者更便捷地定義組件樣式,目前支持less、sass和scss的預編譯。使用樣式預編譯時,需要將原css文件后綴改為less、sass或scss,如index.css改為index.less、index.sass或index.scss。
-
當前文件使用樣式預編譯,例如將原index.css改為index.less:
/* index.less */
/* 定義變量 */
@colorBackground: #000000;
.container {background-color: @colorBackground; /* 使用當前less文件中定義的變量 */
}
引用預編譯文件,例如common中存在style.scss文件,將原index.css改為index.scss,并引入style.scss:
/* style.scss */
/* 定義變量 */
$colorBackground: #000000;
在index.scss中引用:
/* index.scss */
/* 引入外部scss文件 */
@import '../../common/style.scss';
.container {background-color: $colorBackground; /* 使用style.scss中定義的變量 */
}
說明
引用的預編譯文件建議放在common目錄進行管理。
2.8 -> CSS樣式繼承6+
css樣式繼承提供了子節點繼承父節點樣式的能力,繼承下來的樣式在多選擇器樣式匹配的場景下,優先級排最低,當前支持以下樣式的繼承:
-
font-family
-
font-weight
-
font-size
-
font-style
-
text-align
-
line-height
-
letter-spacing
-
color
-
visibility
3 -> JS語法
JS文件用來定義HML頁面的業務邏輯,支持ECMA規范的JavaScript語言。基于JavaScript語言的動態化能力,可以使應用更加富有表現力,具備更加靈活的設計能力。下面講述JS文件的編譯和運行的支持情況。
3.1 -> 語法
支持ES6語法。
-
模塊聲明
使用import方法引入功能模塊:
import router from '@system.router';
- 代碼引用
????????使用import方法導入js代碼:
import utils from '../../common/utils.js';
3.2 -> 對象
- 應用對象
屬性 | 類型 | 描述 |
$def | Object | 使用this.$app.$def獲取在app.js中暴露的對象。 ?說明: > 應用對象不支持數據綁定,需主動觸發UI更新。 |
示例代碼
// app.js
export default {onCreate() {console.info('Application onCreate');},onDestroy() {console.info('Application onDestroy');},globalData: {appData: 'appData',appVersion: '2.0',},globalMethod() {console.info('This is a global method!');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;},invokeGlobalMethod() {this.$app.$def.globalMethod();},getAppVersion() {this.appVersion = this.$app.$def.globalData.appVersion;}
}
- 頁面對象
屬性 | 類型 | 描述 |
data | Object/Function | 頁面的數據模型,類型是對象或者函數,如果類型是函數,返回值必須是對象。屬性名不能以$或_開頭,不要使用保留字for, if, show, tid。 data與private和public不能重合使用。 |
$refs | Object | 持有注冊過ref 屬性的DOM元素或子組件實例的對象。 |
private | Object | 頁面的數據模型,private下的數據屬性只能由當前頁面修改。 |
public | Object | 頁面的數據模型,public下的數據屬性的行為與data保持一致。 |
props | Array/Object | props用于組件之間的通信,可以通過<tag xxxx='value'>方式傳遞給組件;props名稱必須用小寫,不能以$或_開頭,不要使用保留字for, if, show, tid。目前props的數據類型不支持Function。 |
computed | Object | 用于在讀取或設置進行預先處理,計算屬性的結果會被緩存。計算屬性名不能以$或_開頭,不要使用保留字。 |
3.3 -> 方法
- 數據方法
方法 | 參數 | 描述 |
$set | key: string, value:any | 添加新的數據屬性或者修改已有數據屬性。 用法: this.$set('key',value):添加數據屬性。 |
$delete | key: string | 刪除數據屬性。 用法: this.$delete('key'):刪除數據屬性。 |
示例代碼
// index.js
export default {data: {keyMap: {OS: 'HarmonyOS',Version: '2.0',},},getAppVersion() {this.$set('keyMap.Version', '3.0');console.info("keyMap.Version = " + this.keyMap.Version); // keyMap.Version = 3.0this.$delete('keyMap');console.info("keyMap.Version = " + this.keyMap); // log print: keyMap.Version = undefined}
}
- 公共方法
方法 | 參數 | 描述 |
$element | id: string | 獲得指定id的組件對象,如果無指定id,則返回根組件對象。 用法: <div id='xxx'></div> - this.$element('xxx'):獲得id為xxx的組件對象。 - this.$element():獲得根組件對象。 |
$rootElement | 無 | 獲取根組件對象。 用法:this.$rootElement().scrollTo({ duration: 500, position: 300 }), 頁面在500ms內滾動300px。 |
$root | 無 | 獲得頂級ViewModel實例。 |
$parent | 無 | 獲得父級ViewModel實例。 |
$child | id: string | 獲得指定id的子級自定義組件的ViewModel實例。 用法: this.$child('xxx') :獲取id為xxx的子級自定義組件的ViewModel實例。 |
- 事件方法
方法 | 參數 | 描述 |
$watch | data: string, callback: string | Function | 觀察data中的屬性變化,如果屬性值改變,觸發綁定的事件。 用法: this.$watch('key', callback) |
- 頁面方法
方法 | 參數 | 描述 |
scrollTo6+ | scrollPageParam: ScrollPageParam | 將頁面滾動到目標位置,可以通過ID選擇器指定或者滾動距離指定。 |
名稱 | 類型 | 默認值 | 描述 |
position | number | - | 指定滾動位置。 |
id | string | - | 指定需要滾動到的元素id。 |
duration | number | 300 | 指定滾動時長,單位為毫秒。 |
timingFunction | string | ease | 指定滾動動畫曲線,可選值。 |
complete | () => void | - | 指定滾動完成后需要執行的回調函數。 |
示例:
this.$rootElement().scrollTo({position: 0})
this.$rootElement().scrollTo({id: 'id', duration: 200, timingFunction: 'ease-in', complete: ()=>void})
3.4 -> 獲取DOM元素
1. 通過$refs獲取DOM元素
<!-- index.hml -->
<div class="container"><image-animator class="image-player" ref="animator" images="{{images}}" duration="1s" onclick="handleClick"></image-animator>
</div>
// index.js
export default {data: {images: [{ src: '/common/frame1.png' },{ src: '/common/frame2.png' },{ src: '/common/frame3.png' },],},handleClick() {const animator = this.$refs.animator; // 獲取ref屬性為animator的DOM元素const state = animator.getState();if (state === 'paused') {animator.resume();} else if (state === 'stopped') {animator.start();} else {animator.pause();}},
};
2. 通過$element獲取DOM元素
<!-- index.hml -->
<div class="container"><image-animator class="image-player" id="animator" images="{{images}}" duration="1s" onclick="handleClick"></image-animator>
</div>
// index.js
export default {data: {images: [{ src: '/common/frame1.png' },{ src: '/common/frame2.png' },{ src: '/common/frame3.png' },],},handleClick() {const animator = this.$element('animator'); // 獲取id屬性為animator的DOM元素const state = animator.getState();if (state === 'paused') {animator.resume();} else if (state === 'stopped') {animator.start();} else {animator.pause();}},
};
3.5 -> 獲取ViewModel
根節點所在頁面:
<!-- root.hml -->
<element name='parentComp' src='../../common/component/parent/parent.hml'></element>
<div class="container"><div class="container"><text>{{text}}</text><parentComp></parentComp></div>
</div>
// root.js
export default {data: {text: 'I am root!',},
}
自定義parent組件:
<!-- parent.hml -->
<element name='childComp' src='../child/child.hml'></element>
<div class="item" onclick="textClicked"><text class="text-style" onclick="parentClicked">parent component click</text><text class="text-style" if="{{showValue}}">hello parent component!</text><childComp id = "selfDefineChild"></childComp>
</div>
// parent.js
export default {data: {showValue: false,text: 'I am parent component!',},parentClicked () {this.showValue = !this.showValue;console.info('parent component get parent text');console.info(`${this.$parent().text}`);console.info("parent component get child function");console.info(`${this.$child('selfDefineChild').childClicked()}`);},
}
自定義child組件:
<!-- child.hml -->
<div class="item" onclick="textClicked"><text class="text-style" onclick="childClicked">child component clicked</text><text class="text-style" if="{{show}}">hello child component</text>
</div>
// child.js
export default {data: {show: false,text: 'I am child component!',},childClicked () {this.show = !this.show;console.info('child component get parent text');console.info('${this.$parent().text}');console.info('child component get root text');console.info('${this.$root().text}');},
}
感謝各位大佬支持!!!
互三啦!!!