• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1# HML
2
3HML 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 class="container" 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/apis-arkui/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. It 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. The **for** loop supports the following statements:
251
252- for="array": **array** is an array object, whose element variable is **$item** by default.
253
254- for="v in array": **v** is a custom element variable, whose index is **$idx** by default.
255
256- 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.
257
258> **NOTE**
259> - Each element in the array must have the data attribute specified by **tid**. Otherwise, an exception may occur.
260>
261> - 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.
262>
263> - The **tid** attribute does not support expressions.
264
265![en-us_image_0000001118642001](figures/en-us_image_0000001118642001.gif)
266
267## Conditional Rendering
268
269There 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:
270
271```html
272<!-- xxx.hml -->
273<div class="container">
274  <button class="btn" type="capsule" value="toggleShow" onclick="toggleShow"></button>
275  <button class="btn" type="capsule" value="toggleDisplay" onclick="toggleDisplay"></button>
276  <text if="{{visible}}"> Hello-world1 </text>
277  <text elif="{{display}}"> Hello-world2 </text>
278  <text else> Hello-World </text>
279</div>
280```
281
282```css
283/* xxx.css */
284.container{
285  flex-direction: column;
286  align-items: center;
287}
288.btn{
289  width: 280px;
290  font-size: 26px;
291  margin: 10px 0;
292}
293```
294
295```js
296// xxx.js
297export default {
298  data: {
299    visible: false,
300    display: true,
301  },
302  toggleShow: function() {
303    this.visible = !this.visible;
304  },
305  toggleDisplay: function() {
306    this.display = !this.display;
307  }
308}
309```
310
311![en-us_image_0000001118642004](figures/en-us_image_0000001118642004.gif)
312
313In the optimized rendering (**show**), if **show** is **true**, the node is rendered properly; if it is **false**, the display style will be **none**.
314
315```html
316<!-- xxx.hml -->
317<div class="container">
318  <button class="btn" type="capsule" value="toggle" onclick="toggle"></button>
319  <text show="{{visible}}" > Hello World </text>
320</div>
321```
322
323```css
324/* xxx.css */
325.container{
326  flex-direction: column;
327  align-items: center;
328}
329.btn{
330  width: 280px;
331  font-size: 26px;
332  margin: 10px 0;
333}
334```
335
336```js
337// xxx.js
338export default {
339  data: {
340    visible: false,
341  },
342  toggle: function() {
343    this.visible = !this.visible;
344  },
345}
346```
347
348> **NOTE**
349>
350> Do not use **for** and **if** attributes at the same time in an element.
351
352![en-us_image_0000001118642005](figures/en-us_image_0000001118642005.gif)
353
354## Logic Control Block
355
356**\<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.
357
358```html
359<!-- xxx.hml -->
360<list>
361  <block for="glasses">
362    <list-item type="glasses">
363      <text>{{$item.name}}</text>
364    </list-item>
365    <block for="$item.kinds">
366      <list-item type="kind">
367        <text>{{$item.color}}</text>
368      </list-item>
369    </block>
370  </block>
371</list>
372```
373
374```js
375// xxx.js
376export default {
377  data: {
378    glasses: [
379      {name:'sunglasses', kinds:[{name:'XXX',color:'XXX'},{name:'XXX',color:'XXX'}]},
380      {name:'nearsightedness mirror', kinds:[{name:'XXX',color:'XXX'}]},
381    ],
382  },
383}
384```
385
386![en-us_image_0000001118642006](figures/en-us_image_0000001118642006.png)
387
388## Template Reference
389
390HML supports using **element** to reference template files. For details, see [Custom Components](../reference/apis-arkui/arkui-js/js-components-custom-basic-usage.md).
391
392```html
393<!-- template.hml -->
394<div class="item">
395  <text>Name: {{name}}</text>
396  <text>Age: {{age}}</text>
397</div>
398```
399
400```html
401<!-- index.hml -->
402<element name='comp' src='../../common/template.hml'></element>
403<div>
404  <comp name="Tony" age="18"></comp>
405</div>
406```
407