• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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