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