1# HML 2 3The OpenHarmony Markup Language (HML) is an HTML-like language that allows you to build pages based on components and events. Pages built using HML have advanced capabilities such as data binding, event binding, loop rendering, conditional rendering, and logic control. 4 5 6## HML Page Structure 7 8```html 9<!-- xxx.hml --> 10<div class="item-container"> 11 <text class="item-title">Image Show</text> 12 <div class="item-content"> 13 <image src="/common/xxx.png" class="image"></image> 14 </div> 15</div> 16``` 17 18 19## Data Binding 20 21```html 22<!-- xxx.hml --> 23<div onclick="changeText"> 24 <text> {{content[1]}} </text> 25</div> 26``` 27```css 28/*xxx.css*/ 29.container{ 30 margin: 200px; 31} 32``` 33```js 34// xxx.js 35export default { 36 data: { 37 content: ['Hello World!', 'Welcome to my world!'] 38 }, 39 changeText: function() { 40 this.content.splice(1, 1, this.content[0]); 41 } 42} 43``` 44 45> **NOTE** 46> - To make the array data modification take effect, use the **splice** method to change array items. 47> 48> - ECMAScript 6 (ES6) syntax is not supported in HML. 49 50![en-us_image_0000001118642003](figures/en-us_image_0000001118642003.png) 51 52## Common Event Binding 53 54Events are bound to components through **'on'** or **'\@'**. When a component triggers an event, the corresponding event processing function in the **.js** file is executed. 55 56Events can be written in the following formats: 57 58- **funcName**: name of the event callback, which is implemented by defining the corresponding function in the **.js** file. 59 60- **funcName(a,b)**: function parameters, such as **a** and **b**, which can be constants, or variables defined in **data** in the **.js** file. Do not add the prefix **this.** to variables. 61 62- Example 63 ```html 64 <!-- xxx.hml --> 65 <div class="container"> 66 <text class="title">{{count}}</text> 67 <div class="box"> 68 <input type="button" class="btn" value="increase" onclick="increase" /> 69 <input type="button" class="btn" value="decrease" @click="decrease" /> 70 <!-- Pass additional parameters. --> 71 <input type="button" class="btn" value="double" @click="multiply(2)" /> 72 <input type="button" class="btn" value="decuple" @click="multiply(10)" /> 73 <input type="button" class="btn" value="square" @click="multiply(count)" /> 74 </div> 75 </div> 76 ``` 77 78 ```js 79 // xxx.js 80 export default { 81 data: { 82 count: 0 83 }, 84 increase() { 85 this.count++; 86 }, 87 decrease() { 88 this.count--; 89 }, 90 multiply(multiplier) { 91 this.count = multiplier * this.count; 92 } 93 }; 94 ``` 95 96 ```css 97 /* xxx.css */ 98 .container { 99 display: flex; 100 flex-direction: column; 101 justify-content: center; 102 align-items: center; 103 left: 0px; 104 top: 0px; 105 width: 454px; 106 height: 454px; 107 } 108 .title { 109 font-size: 30px; 110 text-align: center; 111 width: 200px; 112 height: 100px; 113 } 114 .box { 115 width: 454px; 116 height: 200px; 117 justify-content: center; 118 align-items: center; 119 flex-wrap: wrap; 120 } 121 .btn { 122 width: 200px; 123 border-radius: 0; 124 margin-top: 10px; 125 margin-left: 10px; 126 } 127 ``` 128 129![en-us_image_0000001118642002](figures/en-us_image_0000001118642002.gif) 130 131## Binding for Event Bubbling<sup>5+</sup> 132 133Binding for event bubbling covers the following: 134 135- Bind an event callback for event bubbling: **on:{event}.bubble**. **on:{event}** is equivalent to **on:{event}.bubble**. 136 137- Bind an event callback, but stop the event from bubbling upwards: **grab:{event}.bubble**. **grab:{event}** is equivalent to **grab:{event}.bubble**. 138 > **NOTE** 139 > 140 > - Event bubbling occurs when the target element and its ancestors have registered a listener for the same event. When the event happens on the element, it first runs the event handler on it, then on its parent, and then all the way up on other ancestors. If an element triggers this event, it first triggers the callback on the element, then on its parent, and then all the way up on other ancestors. 141 > 142 > - For details about event bubbling, see [Universal Events](../reference/arkui-js/js-components-common-events.md). 143- Example 144 ```html 145 <!-- xxx.hml --> 146 <div> 147 <!-- Bind an event callback for event bubbling.5+ --> 148 <div on:touchstart.bubble="touchstartfunc"></div> 149 <div on:touchstart="touchstartfunc"></div> 150 <!-- Bind an event callback, but stop the event from bubbling upwards.5+ --> 151 <div grab:touchstart.bubble="touchstartfunc"></div> 152 <div grab:touchstart="touchstartfunc"></div> 153 <!-- Bind an event callback for event bubbling.6+ --> 154 <div on:click.bubble="clickfunc"></div> 155 <div on:click="clickfunc"></div> 156 <!-- Bind an event callback, but stop the event from bubbling upwards.6+ --> 157 <div grab:click.bubble="clickfunc"></div> 158 <div grab:click="clickfunc"></div> 159 </div> 160 ``` 161 162 ```js 163 // xxx.js 164 export default { 165 clickfunc: function(e) { 166 console.log(e); 167 }, 168 touchstartfuc: function(e) { 169 console.log(e); 170 }, 171 } 172 ``` 173 174> **NOTE** 175> 176> Events bound using a traditional statement (such as **onclick**) will bubble only when the API version in use is 6 or later. 177 178## Binding for Event Capturing<sup>5+</sup> 179 180Touch events can be captured. In the capture phase, which precedes the bubbling phase, an event starts from the parent component to the child component. 181 182Binding for event capturing covers the following: 183 184- Bind an event callback for event capturing: **on:{event}.capture**. 185 186- Bind an event callback, but stop the event from being captured during downward transfer: **grab:{event}.capture**. 187 188- Example 189 ```html 190 <!-- xxx.hml --> 191 <div> 192 <!-- Bind an event callback for event capturing.5+ --> 193 <div on:touchstart.capture="touchstartfunc"></div> 194 <!-- Bind an event callback, but stop the event from being captured during downward transfer.5+ --> 195 <div grab:touchstart.capture="touchstartfunc"></div> 196 </div> 197 ``` 198 199 ```js 200 // xxx.js 201 export default { 202 touchstartfuc: function(e) { 203 console.log(e); 204 }, 205 } 206 ``` 207 208 209## Loop Rendering 210 211```html 212<!-- xxx.hml --> 213<div class="array-container" style="flex-direction: column;margin: 200px;"> 214 <!-- div loop rendering --> 215 <!-- By default, $item indicates the element in the array, and $idx indicates the index of the element in the array. --> 216 <div for="{{array}}" tid="id" onclick="changeText"> 217 <text>{{$idx}}.{{$item.name}}</text> 218 </div> 219 <!-- Define the name for an element variable. --> 220 <div for="{{value in array}}" tid="id" onclick="changeText"> 221 <text>{{$idx}}.{{value.name}}</text> 222 </div> 223 <!-- Define an element variable and its index name. --> 224 <div for="{{(index, value) in array}}" tid="id" onclick="changeText"> 225 <text>{{index}}.{{value.name}}</text> 226 </div> 227</div> 228 229``` 230 231```js 232// xxx.js 233export default { 234 data: { 235 array: [ 236 {id: 1, name: 'jack', age: 18}, 237 {id: 2, name: 'tony', age: 18}, 238 ], 239 }, 240 changeText: function() { 241 if (this.array[1].name === "tony"){ 242 this.array.splice(1, 1, {id:2, name: 'Isabella', age: 18}); 243 } else { 244 this.array.splice(2, 1, {id:3, name: 'Bary', age: 18}); 245 } 246 }, 247} 248``` 249 250The **tid** attribute accelerates the **for** loop and improves the re-rendering efficiency when data in a loop changes. 251 252The **tid** attribute specifies the unique ID of each element in the array. If it is not specified, the index of each element in the array is used as the ID. For example, **tid="id"** indicates that the **id** attribute of each element is its unique ID. 253 254The **for** loop supports the following statements: 255 256- for="array": **array** is an array object, whose element variable is **$item** by default. 257 258- for="v in array": **v** is a custom element variable, whose index is **$idx** by default. 259 260- for="(i, v) in array": **i** indicates the element index, and **v** indicates the element variable. All elements of the array object will be looped through. 261 262> **NOTE** 263> - Each element in the array must have the data attribute specified by **tid**. Otherwise, an exception may occur. 264> 265> - The attribute specified by **tid** in the array must be unique. Otherwise, performance loss occurs. In the above example, only **id** and **name** can be used as **tid** because they are unique fields. 266> 267> - The **tid** attribute does not support expressions. 268 269![en-us_image_0000001118642001](figures/en-us_image_0000001118642001.gif) 270 271## Conditional Rendering 272 273There are two ways to implement conditional rendering: **if-elif-else** or **show**. In **if-elif-else**, when the **if** statement evaluates to **false**, the component is not built in the VDOM and is not rendered. For **show**, when show is **false**, the component is not rendered but is built in the VDOM. In addition, the **if-elif-else** statements must be used in sibling nodes. Otherwise, the compilation fails. The following example uses both ways to implement conditional rendering: 274 275```html 276<!-- xxx.hml --> 277<div class="container"> 278 <button class="btn" type="capsule" value="toggleShow" onclick="toggleShow"></button> 279 <button class="btn" type="capsule" value="toggleDisplay" onclick="toggleDisplay"></button> 280 <text if="{{visible}}"> Hello-world1 </text> 281 <text elif="{{display}}"> Hello-world2 </text> 282 <text else> Hello-World </text> 283</div> 284``` 285 286```css 287/* xxx.css */ 288.container{ 289 flex-direction: column; 290 align-items: center; 291} 292.btn{ 293 width: 280px; 294 font-size: 26px; 295 margin: 10px 0; 296} 297``` 298 299```js 300// xxx.js 301export default { 302 data: { 303 visible: false, 304 display: true, 305 }, 306 toggleShow: function() { 307 this.visible = !this.visible; 308 }, 309 toggleDisplay: function() { 310 this.display = !this.display; 311 } 312} 313``` 314 315![en-us_image_0000001118642004](figures/en-us_image_0000001118642004.gif) 316 317In the optimized rendering (**show**), if **show** is **true**, the node is rendered properly; if it is **false**, the display style will be **none**. 318 319```html 320<!-- xxx.hml --> 321<div class="container"> 322 <button class="btn" type="capsule" value="toggle" onclick="toggle"></button> 323 <text show="{{visible}}" > Hello World </text> 324</div> 325``` 326 327```css 328/* xxx.css */ 329.container{ 330 flex-direction: column; 331 align-items: center; 332} 333.btn{ 334 width: 280px; 335 font-size: 26px; 336 margin: 10px 0; 337} 338``` 339 340```js 341// xxx.js 342export default { 343 data: { 344 visible: false, 345 }, 346 toggle: function() { 347 this.visible = !this.visible; 348 }, 349} 350``` 351 352> **NOTE** 353> 354> Do not use **for** and **if** attributes at the same time in an element. 355 356![en-us_image_0000001118642005](figures/en-us_image_0000001118642005.gif) 357 358## Logic Control Block 359 360**\<block>** makes loop rendering and conditional rendering more flexible. A **\<block>** will not be compiled as a real component. Note that the **\<block>** tag supports only the **for** and **if** attributes. 361 362```html 363<!-- xxx.hml --> 364<list> 365 <block for="glasses"> 366 <list-item type="glasses"> 367 <text>{{$item.name}}</text> 368 </list-item> 369 <block for="$item.kinds"> 370 <list-item type="kind"> 371 <text>{{$item.color}}</text> 372 </list-item> 373 </block> 374 </block> 375</list> 376``` 377 378```js 379// xxx.js 380export default { 381 data: { 382 glasses: [ 383 {name:'sunglasses', kinds:[{name:'XXX',color:'XXX'},{name:'XXX',color:'XXX'}]}, 384 {name:'nearsightedness mirror', kinds:[{name:'XXX',color:'XXX'}]}, 385 ], 386 }, 387} 388``` 389 390![en-us_image_0000001118642006](figures/en-us_image_0000001118642006.png) 391 392## Template Reference 393 394HML supports using **element** to reference template files. For details, see [Custom Components](../reference/arkui-js/js-components-custom-basic-usage.md). 395 396```html 397<!-- template.hml --> 398<div class="item"> 399 <text>Name: {{name}}</text> 400 <text>Age: {{age}}</text> 401</div> 402``` 403 404```html 405<!-- index.hml --> 406<element name='comp' src='../../common/template.hml'></element> 407<div> 408 <comp name="Tony" age="18"></comp> 409</div> 410``` 411