All Products
Search
Document Center

View layer

Last Updated: Feb 05, 2021

Introduction

The view file has a suffix of axml and defines the label structure of the page.

Here are some examples to show the capabilities of axml.

  • Data binding:

    1. <view> {{message}} </view>
    1. // page.js
    2. Page({
    3. data: {
    4. message: 'Hello alipay!'
    5. }
    6. })
  • List rendering:

    1. <view a:for="{{items}}"> {{item}} </view>
    1. // page.js
    2. Page({
    3. data: {
    4. items: [1, 2, 3, 4, 5, 6, 7]
    5. }
    6. })
  • Conditional rendering:

    1. <view a:if="{{view == 'WEBVIEW'}}"> WEBVIEW </view>
    2. <view a:elif="{{view == 'APP'}}"> APP </view>
    3. <view a:else="{{view == 'alipay'}}"> alipay </view>
    1. // page.js
    2. Page({
    3. data: {
    4. view: 'alipay'
    5. }
    6. })
  • Template:

    1. <template name="staffName">
    2. <view>
    3. FirstName: {{firstName}}, LastName: {{lastName}}
    4. </view>
    5. </template>
    6. <template is="staffName" data="{{...staffA}}"></template>
    7. <template is="staffName" data="{{...staffB}}"></template>
    8. <template is="staffName" data="{{...staffC}}"></template>
    1. // page.js
    2. // Hats off to the Wechat MINI engineers.
    3. Page({
    4. data: {
    5. staffA: {firstName: 'san', lastName: 'zhang'},
    6. staffB: {firstName: 'si', lastName: 'li'},
    7. staffC: {firstName: 'wu', lastName: 'wang'},
    8. },
    9. })
  • Event:

    1. <view onTap="add"> {{count}} </view>
    1. Page({
    2. data: {
    3. count: 1
    4. },
    5. add(e) {
    6. this.setData({
    7. count: this.data.count + 1
    8. })
    9. }
    10. })

Data binding

All dynamic data in axml come from data in the corresponding Page.

Simple binding

The data binding uses the Mustache syntax (double braces) to enclose the variables, which can apply to various scenes.

  • Applies to content, for example:

    1. <view> {{ message }} </view>
    1. Page({
    2. data: {
    3. message: 'Hello alipay!'
    4. }
    5. })
  • Applies to component properties (must be enclosed in double quotes), for example:

    1. <view id="item-{{id}}"> </view>
    1. Page({
    2. data: {
    3. id: 0
    4. }
    5. })
  • Applies to control properties (must be enclosed in double quotes), for example:

    1. <view a:if="{{condition}}"> </view>
    1. Page({
    2. data: {
    3. condition: true
    4. }
    5. })
  • Applies to keywords (must be enclosed in double quotes), for example:

    1. <checkbox checked="{{false}}"> </checkbox>
    • true: A boolean true, representing a true value.
    • false: A Boolean false, representing a false value.

      Important: Do not write checked="false" directly, the result of which is a string that represents true after being converted to a Boolean data value.

The following simple operations can be performed within {{}}:

  • Ternary operation:

    1. <view hidden="{{flag ? true : false}}"> Hidden </view>
  • Arithmetic operation:

    1. <view> {{a + b}} + {{c}} + d </view>
    1. Page({
    2. data: {
    3. a: 1,
    4. b: 2,
    5. c: 3
    6. }
    7. })

    The content in the View is 3 + 3 + d.

  • Logical judgment:

    1. <view a:if="{{length > 5}}"> </view>
  • String operation:

    1. <view>{{"hello" + name}}</view>
    1. Page({
    2. data:{
    3. name: 'alipay'
    4. }
    5. })
  • Data path operation:

    1. <view>{{object.key}} {{array[0]}}</view>
    1. Page({
    2. data: {
    3. object: {
    4. key: 'Hello '
    5. },
    6. array: ['alipay']
    7. }
    8. })

It can also be combined directly in Mustache to form a new array or object.

  • Array:

    1. <view a:for="{{[zero, 1, 2, 3, 4]}}"> {{item}} </view>
    1. Page({
    2. data: {
    3. zero: 0
    4. }
    5. })

    Finally combined into an array [0, 1, 2, 3, 4].

  • Object:

    1. <template is="objectCombine" data="{{foo: a, bar: b}}"></template>
    1. Page({
    2. data: {
    3. a: 1,
    4. b: 2
    5. }
    6. })

    The final combined object is {foo: 1, bar: 2}.

    You can also expand an object with the extended operator ....

    1. <template is="objectCombine" data="{{...obj1, ...obj2, e: 5}}"></template>
    1. Page({
    2. data: {
    3. obj1: {
    4. a: 1,
    5. b: 2
    6. },
    7. obj2: {
    8. c: 3,
    9. d: 4
    10. }
    11. }
    12. })

    The final combined object is {a: 1, b: 2, c: 3, d: 4, e: 5}.

    If the object’s key and value are the same, it can also be expressed indirectly.

    1. <template is="objectCombine" data="{{foo, bar}}"></template>
    1. Page({
    2. data: {
    3. foo: 'my-foo',
    4. bar: 'my-bar'
    5. }
    6. })

    The final combined object is {foo: ‘my-foo’, bar:’my-bar’}.

    Note: The above operations can be combined at will, but if there are cases where the variable names are the same, the latter variable will overwrite the former one.

    1. <template is="objectCombine" data="{{...obj1, ...obj2, a, c: 6}}"></template>
    1. Page({
    2. data: {
    3. obj1: {
    4. a: 1,
    5. b: 2
    6. },
    7. obj2: {
    8. b: 3,
    9. c: 4
    10. },
    11. a: 5
    12. }
    13. })

    The final combined object is {a: 5, b: 3, c: 6}.

Conditional rendering

a:if

In the framework, you can use a:if="{{condition}}" to determine if the code block needs to be rendered.

  1. <view a:if="{{condition}}"> True </view>

You can also use a:elif and a:else to add an else block.

  1. <view a:if="{{length > 5}}"> 1 </view>
  2. <view a:elif="{{length > 2}}"> 2 </view>
  3. <view a:else> 3 </view>

block a:if

Since a:if is a control attribute, you need to add it to a label. To determine multiple component labels at the same time, you can enclose multiple components with a single <block/> label and use a:if to control the attribute on it.

  1. <block a:if="{{true}}">
  2. <view> view1 </view>
  3. <view> view2 </view>
  4. </block>

Note: <block/> is not a component, but only an enclosure element that doesn’t need any rendering in the page and only accepts control properties.

List rendering

a:for

By binding an array on the component with the a:for attribute, you can repeatedly render the component using the data of each item in the array.

The subscripted variable name of the current item in the default array defaults to index. The variable name of the current item in the array defaults to item.

  1. <view a:for="{{array}}">
  2. {{index}}: {{item.message}}
  3. </view>
  1. Page({
  2. data: {
  3. array: [{
  4. message: 'foo',
  5. }, {
  6. message: 'bar'
  7. }]
  8. }
  9. })

Use a:for-item to specify the variable name of the current element of the array.

Use a:for-index to specify the variable name of the current subscript of the array.

  1. <view a:for="{{array}}" a:for-index="idx" a:for-item="itemName">
  2. {{idx}}: {{itemName.message}}
  3. </view>

a:for can also be nested. Below is an example of Multiplication Table:

  1. <view a:for="{{[1, 2, 3, 4, 5, 6, 7, 8, 9]}}" a:for-item="i">
  2. <view a:for="{{[1, 2, 3, 4, 5, 6, 7, 8, 9]}}" a:for-item="j">
  3. <view a:if="{{i <= j}}">
  4. {{i}} * {{j}} = {{i * j}}
  5. </view>
  6. </view>
  7. </view>

block a:for

Similar to block a:if, you can also use a:for on the <block/> label to render a building block containing multiple nodes.

  1. <block a:for="{{[1, 2, 3]}}">
  2. <view> {{index}}: </view>
  3. <view> {{item}} </view>
  4. </block>

a:key

If the position of an item in the list changes dynamically or a new item is added to the list, and you want the item in the list to maintain its own feature and state (such as the input of <input/> and the selected state of <switch/>), you need to use a:key to specify a unique identifier for the item in the list.

a:key has a value that is provided in two forms:

  • A string, representing an attribute of item in array in the for loop. The value of this attribute must be a unique string or number in the list and cannot be changed dynamically.
  • A reserved keyword *this, representing the item itself in the for loop. It indicates that item itself must be a unique string or number. For example, when the data change triggers the rendering layer to re-render, the component with key is calibrated, and the framework ensures that they are reordered rather than recreated to guarantee that the component maintains its state and improves the efficiency of list rendering.

If you know that the list is static or you don’t care its order, you can choose to ignore it.

The code sample is as follows:

  1. <view class="container">
  2. <view a:for="{{list}}" a:key="*this">
  3. <view onTap="bringToFront" data-value="{{item}}">
  4. {{item}}: click to bring to front
  5. </view>
  6. </view>
  7. </view>
  1. Page({
  2. data:{
  3. list:['1', '2', '3', '4'],
  4. },
  5. bringToFront(e) {
  6. const { value } = e.target.dataset;
  7. const list = this.data.list.concat();
  8. const index = list.indexOf(value);
  9. if (index !== -1) {
  10. list.splice(index, 1);
  11. list.unshift(value);
  12. this.setData({ list });
  13. }
  14. }
  15. });

key

key is a more common version of a:key, in which you can populate with any expressions or strings.

The code sample is as follows:

  1. <view class="container">
  2. <view a:for="{{list}}" key="{{item}}">
  3. <view onTap="bringToFront" data-value="{{item}}">
  4. {{item}}: click to bring to front
  5. </view>
  6. </view>
  7. </view>
  1. Page({
  2. data:{
  3. list:['1', '2', '3', '4'],
  4. },
  5. bringToFront(e) {
  6. const { value } = e.target.dataset;
  7. const list = this.data.list.concat();
  8. const index = list.indexOf(value);
  9. if (index !== -1) {
  10. list.splice(index, 1);
  11. list.unshift(value);
  12. this.setData({ list });
  13. }
  14. }
  15. });

In addition, you can use key to prevent the reuse of components. For example, if you allow users to enter different types of data:

  1. <input a:if="{{name}}" placeholder="Enter your username">
  2. <input a:else placeholder="Enter your email address">

Then, when you enter name and switch to email, the current input value will be retained. If you don’t want to retain it, you can add key:

  1. <input key="name" a:if="{{name}}" placeholder="Enter your username">
  2. <input key="email" a:else placeholder="Enter your email address">

Reference

axml provides two file reference methods, import and include.

import

import can be used to load a defined template.

For example, a template named item is defined in item.axml.

  1. <!-- item.axml -->
  2. <template name="item">
  3. <text>{{text}}</text>
  4. </template>

By referencing item.axml in index.axml, you can use the item template.

  1. <import src="./item.axml"/>
  2. <template is="item" data="{{text: 'forbar'}}"/>

import has a concept of scope, which only import the template defined in the target file. For example, if B is imported to C and A is imported to B, then you can use the template defined by B in C, and use the template defined by A in B, but you can’t use the template defined by A in C.

  1. <!-- A.axml -->
  2. <template name="A">
  3. <text> A template </text>
  4. </template>
  1. <!-- B.axml -->
  2. <import src="./a.axml"/>
  3. <template name="B">
  4. <text> B template </text>
  5. </template>
  1. <!-- C.axml -->
  2. <import src="./b.axml"/>
  3. <template is="A"/> <!-- Error! Can not use tempalte when not import A. -->
  4. <template is="B"/>

Note that a template can only have one child node instead of multiple ones, for example:

  • Allowed:
    1. <template name="x">
    2. <view />
    3. </template>
  • Restricted:
    1. <template name="x">
    2. <view />
    3. <view />
    4. </template>

include

include can introduce the entire code of target file (except <template/>), which is equivalent to copying to include.

The code sample is as follows:

  1. <!-- index.axml -->
  2. <include src="./header.axml"/>
  3. <view> body </view>
  4. <include src="./footer.axml"/>
  1. <!-- header.axml -->
  2. <view> header </view>
  1. <!-- footer.axml -->
  2. <view> footer </view>

Template

axml provides a template, in which you can define code snippets and call them in different places.

Define a template

Use the name attribute as the name of the template and then define the code snippets within <template/>.

  1. <!--
  2. index: int
  3. msg: string
  4. time: string
  5. -->
  6. <template name="msgItem">
  7. <view>
  8. <text> {{index}}: {{msg}} </text>
  9. <text> Time: {{time}} </text>
  10. </view>
  11. </template>

Use a template

Use the is attribute to declare the template you want to use and then pass in the data required by the template, for example:

  1. <template is="msgItem" data="{{...item}}"/>
  1. Page({
  2. data: {
  3. item: {
  4. index: 0,
  5. msg: 'this is a template',
  6. time: '2016-09-15'
  7. }
  8. }
  9. })

is attribute can use the Mustache syntax to dynamically determine which template needs to be rendered.

  1. <template name="odd">
  2. <view> odd </view>
  3. </template>
  4. <template name="even">
  5. <view> even </view>
  6. </template>
  7. <block a:for="{{[1, 2, 3, 4, 5]}}">
  8. <template is="{{item % 2 == 0 ? 'even' : 'odd'}}"/>
  9. </block>

Note: The template has its own scope and can only use data passed by data, however, it can handle functions by using the logic bound to page through onXX.

It is recommended that you use a template to introduce template snippets, because the template will specify its own scope and only use the data passed by data, which will be optimized by the MINI program. If the data of the template is not changed, the snippet UI will not be re-rendered.

The import path supports loading third-party modules from the node_modules directory, for example: page.axml:

  1. <import src="./a.axml"/> <!-- Relative path -->
  2. <import src="/a.axml"/> <!-- Project absolute path -->
  3. <import src="third-party/x.axml"/> <!-- Third party npm package path -->