1# HML
2
3
4HML 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, and conditional rendering.
5
6
7## HML Page Structure
8
9
10```html
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```html
25<!-- xxx.hml -->
26<div onclick="changeText">
27  <text> {{content[1]}} </text>
28</div>
29```
30
31
32```js
33// xxx.js
34export default {
35  data: {
36    content: ['Hello World!', 'Welcome to my world!']
37  },
38  changeText: function() {
39    this.content.splice(1, 1, this.content[0]);
40  }
41}
42```
43
44>  **NOTE**
45>  - To make the array data modification take effect, use the **splice** method to change array items.
46>
47>  - ECMAScript 6.0 syntax is not supported in HML.
48
49
50## Event Binding
51
52The callback bound to an event receives an event object parameter, which can be used to obtain the event information.
53
54
55```html
56<!-- xxx.hml -->
57<div>
58  <!-- Bind an event using @. -->
59  <div @click="clickfunc"></div>
60  <!-- Bind an event using on. -->
61  <div onclick="clickfunc"></div>
62  <!--  Bind an event using on.<sup>5+</sup> This statement is not recommended. -->
63  <div onclick="clickfunc"></div>
64  <!-- Bind an event callback for event bubbling.<sup>5+</sup>-->
65  <div on:click.bubble="clickfunc"></div>
66  <!-- on:{event} is equivalent to on:{event}.bubble.<sup>5+</sup> -->
67  <div on:click="clickfunc"></div>
68  <!-- Bind an event callback, but stop the event from bubbling upwards.<sup>5+</sup> -->
69  <div grab:click.bubble="clickfunc"></div>
70  <!-- grab:{event} is equivalent to grab:{event}.bubble.<sup>5+</sup> -->
71  <div grab:click="clickfunc"></div>
72</div>
73```
74
75
76```js
77// xxx.js
78export default {
79  data: {
80    obj: '',
81  },
82  clickfunc: function(e) {
83    this.obj = 'Hello World';
84    console.log(e);
85  },
86}
87```
88
89>  **NOTE**
90>
91>  Event bubbling is supported since API version 5. After you upgrade the SDK and run an existing JavaScript application, events bound using a traditional statement (such as **onclick**) will not bubble. However, if you use the new SDK to repack the JavaScript application, such events will bubble. To avoid service logic errors, replace the traditional statement with one supported by the new SDK. For example, replace **onclick** with **grab:click**.
92
93**Example**
94
95```html
96<!-- xxx.hml -->
97<div class="container">
98  <text class="title">{{count}}</text>
99  <div class="box">
100    <input type="button" class="btn" value="increase" onclick="increase" />
101    <input type="button" class="btn" value="decrease" @click="decrease" />
102    <!-- Pass additional parameters. -->
103    <input type="button" class="btn" value="double" @click="multiply(2)" />
104    <input type="button" class="btn" value="decuple" @click="multiply(10)" />
105    <input type="button" class="btn" value="square" @click="multiply(count)" />
106  </div>
107</div>
108```
109
110
111```js
112// xxx.js
113export default {
114  data: {
115    count: 0
116  },
117  increase() {
118    this.count++;
119  },
120  decrease() {
121    this.count--;
122  },
123  multiply(multiplier) {
124    this.count = multiplier * this.count;
125  }
126};
127```
128
129
130```css
131/* xxx.css */
132.container {
133    display: flex;
134    flex-direction: column;
135    justify-content: center;
136    align-items: center;
137    left: 0px;
138    top: 0px;
139    width: 454px;
140    height: 454px;
141}
142.title {
143    font-size: 30px;
144    text-align: center;
145    width: 200px;
146    height: 100px;
147}
148.box {
149    width: 454px;
150    height: 200px;
151    justify-content: center;
152    align-items: center;
153    flex-wrap: wrap;
154}
155.btn {
156    width: 200px;
157    border-radius: 0;
158    margin-top: 10px;
159    margin-left: 10px;
160}
161```
162
163
164## Loop Rendering
165
166
167```html
168<!-- xxx.hml -->
169<div class="array-container">
170  <!-- div loop rendering -->
171  <!-- By default, $item indicates the element in the array, and $idx indicates the index of the element in the array. -->
172    <div class="item-container" for="{{array}}" tid="id" onclick="changeText">
173        <text>{{$idx}}.{{$item.name}}</text>
174    </div>
175  <!-- Define the name for an element variable. -->
176    <div class="item-container" for="{{value in array}}" tid="id" onclick="changeText">
177        <text>{{$idx}}.{{value.name}}</text>
178    </div>
179  <!-- Define an element variable and its index name. -->
180    <div class="item-container" for="{{(index, value) in array}}" tid="id" onclick="changeText">
181        <text>{{index}}.{{value.name}}</text>
182    </div>
183</div>
184```
185
186
187```js
188// xxx.js
189export default {
190  data: {
191    array: [
192      {id: 1, name: 'jack', age: 18},
193      {id: 2, name: 'tony', age: 18},
194    ],
195  },
196  changeText: function() {
197    if (this.array[1].name === "tony"){
198      this.array.splice(1, 1, {id:2, name: 'Isabella', age: 18});
199    } else {
200      this.array.splice(2, 1, {id:3, name: 'Bary', age: 18});
201    }
202  },
203}
204```
205
206
207```css
208.array-container {
209    width: 100%;
210    height: 100%;
211    justify-content: center;
212    align-items: center;
213    flex-direction: column;
214}
215
216.item-container {
217    margin-top: 10px;
218    width: 200px;
219    height: 50px;
220    flex-direction: column;
221}
222```
223
224
225The **tid** attribute accelerates the **for** loop and improves the re-rendering efficiency when data in a loop changes. The **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. The **for** loop supports the following statements:
226
227- for="array": **array** is an array object, whose element variable is **$item** by default.
228
229- for="v in array": **v** is a custom element variable, whose index is **$idx** by default.
230
231- 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.
232
233>  **NOTE**
234>
235> - Each element in the array must have the data attribute specified by **tid**. Otherwise, an exception may occur.
236>
237> - 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.
238>
239> - The **tid** field does not support expressions.
240
241
242## Conditional Rendering
243
244There 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:
245
246
247```html
248<!-- xxx.hml -->
249<div class="container">
250  <button class="btn" type="capsule" value="toggleShow" onclick="toggleShow"></button>
251  <button class="btn" type="capsule" value="toggleDisplay" onclick="toggleDisplay"></button>
252  <text if="{{show}}"> Hello-One </text>
253  <text elif="{{display}}"> Hello-Two </text>
254  <text else> Hello-World </text>
255</div>
256```
257
258
259```css
260/* xxx.css */
261.container{
262  flex-direction: column;
263  align-items: center;
264}
265.btn{
266  width: 280px;
267  font-size: 26px;
268  margin: 10px 0;
269}
270```
271
272
273```js
274// xxx.js
275export default {
276  data: {
277    show: false,
278    display: true,
279  },
280  toggleShow: function() {
281    this.show = !this.show;
282  },
283  toggleDisplay: function() {
284    this.display = !this.display;
285  }
286}
287```
288
289In the optimized rendering (**show**), if **show** is **true**, the node is rendered properly; if it is **false**, the display style will be **none**.
290
291
292```html
293<!-- xxx.hml -->
294<div class="container">
295  <button class="btn" type="capsule" value="toggle" onclick="toggle"></button>
296  <text show="{{visible}}" > Hello World </text>
297</div>
298```
299
300
301```css
302/* xxx.css */
303.container{
304  flex-direction: column;
305  align-items: center;
306}
307.btn{
308  width: 280px;
309  font-size: 26px;
310  margin: 10px 0;
311}
312```
313
314
315```js
316// xxx.js
317export default {
318  data: {
319    visible: false,
320  },
321  toggle: function() {
322    this.visible = !this.visible;
323  },
324}
325```
326
327>  **NOTE**
328>
329>  Do not use **for** and **if** attributes at the same time in an element.
330