Skip to content

WXML 模板

WXML全稱是WeiXin Markup Language,是小程序框架設計的一套標籤語言,結合小程序的基礎組件、事件系統,可以構建出頁面的結構。
打開開發工具的編輯器,在根目錄下找到app.json文件,按兩下打開,在'pages/index/index'上新增一行'pages/wxml/index'保存文件模擬器重繪後,讀者可以在編輯器中找到pages/wxml/index.wxml文件,本小結的學習通過修改這個檔來完成。

介紹

WXML文件后綴名是.wxml,打開pages/wxml/index.wxml文件,有過HTML的開發經驗的讀者應該會很熟悉這種代碼的書寫管道,簡單的WXML語句在語法上同HTML非常相似。

js
<!--pages/wxml/index.wxml-->

<text>pages/wxml/index.wxml</text>
不帶有任何邏輯功能的WXML基本語法如下:
js
<!-- Add comment here-->

<Tag name Attribute name 1="Attribute value 1" Attribute name 2="Attribute value 2" ...> ...</Tag name>
一個完整的WXML語句由一段開始標籤和一段結束標籤組成,在標籤中可以是內容,也可以是其他的WXML語句,這一點上同HTML是一致的有所不同的是,WXML要求標籤必須是嚴格閉合的,沒有閉合將會導致編譯錯誤,如下代碼所示:
js
<text>hello world
<!--
text is not closed, resulting in a compile error:
VM148:2 ./pages/wxml/index.wxml
 end tag missing, near text
> 1 | <text>hello world
    | ^
-->
標籤可以擁有内容,内容提供了有關的WXML元素更多資訊内容總是定義在開始標籤中,除了一些特殊的内容外,其餘内容的格式都是key='value'的管道成對出現需要注意的是,WXML中的内容是大小寫敏感的,也就是說class和Class在WXML中是不同的内容,下方代碼是一個文字標籤的示例。
js
<!-- A simple text tag-->
<text>hello world</text>

<!-- view contains text tags -->
<view>
  <text>hello world</text>
</view>
帶内容的圖片標籤的例子如下所示:
js
<image class="userinfo-avatar" src="./image/a.png" ></image>

數據綁定

使用者介面呈現會因為當前時刻數據不同而有所不同,或者是因為用戶的操作發生動態改變,這就要求程序的運行過程中,要有動態的去改變渲染介面的能力在Web開發中,開發者使用JavaScript通過Dom介面來完成介面的即時更新在小程序中,使用WXML語言所提供的數據綁定功能,來完成此項功能。
先看一個簡單的例子。
將pages/wxml/index.wxml文件的內容做一些簡單的修改,如下代碼所示:
js
<!--pages/wxml/index.wxml-->
<text>Current time: {{time}}</text>
保存後工具重繪,模擬器並沒有顯示出當前的時間,這是因為我們並沒有給time設定任何初始值,請打開pages/wxml/index.js文件,在data的大括弧中加入: time: (new Date()).toString(), 如下代碼所示:
js
// pages/wxml/index.js
Page({
  /**
   * Initial page data
   */
  data: {
    time: (new Date()).toString()
  },
})
保存,模擬器重繪後正確的展示了當前時間,並且每次編譯時間都會被更新。
WXML 透過 {{變數名稱}} 來綁定 WXML 檔案和對應的 JavaScript 檔案中的 data 對象+C678屬性。
後文中為了保持簡單,通過以下格式來展示上述的代碼邏輯,使用第一段注釋來表明WXML對應的腳本文件中的data結構,如下代碼所示:
js
<!--
{
  time: (new Date()).toString()
}
-->
<text> Current time: {{time}}/text>
屬性值也可以動態的去改變,有所不同的是,屬性值必須被包裹在雙引號中,如下代碼所示:
js
<!-- Correct coding -->
<text data-test="{{test}}"> hello world</text>


<!-- Wrong coding  -->
<text data-test={{test}}> hello world </text >
要注意的是變數名稱是大小寫敏感的,也就是說 {{name}} 和 {{Name}} 是兩個不同的變量,如下程式碼所示:
js
<!--
{
  w: 'w',
  W: 'W'
}
-->


<view>{{w}}</view>
<view>{{W}}</view>


<!-- Output
w
W
-->
還需要注意,沒有被定義的變量的或者是被設定為undefined的變量不會被同步到wxml中,如下代碼所示:
js
<!--
{
  var2: undefined,
  var3: null,
  var4: "var4"
}
-->


<view>{{var1}}</view>
<view>{{var2}}</view>
<view>{{var3}}</view>
<view>{{var4}}</view>


<!--
Output:
null
var4
-->
關於數據綁定的概念在第三章中有更為詳細的介紹。

邏輯語法

透過 {{ 變數名稱 }} 語法可以使得 WXML 擁有動態渲染的能力,除此外還可以在 {{ }} 內進行簡單的邏輯運算。

三元運算:

js
<!-- Display page content conditionally based on whether a is equal to 10 or not -->
<text>{{ a === 10? "variable a is equal to 10": "variable a is not equal to 10"}}</text>
算數運算:
js
<!--
{ a: 1,  b: 2, c: 3 }
-->


<view> {{a + b}} + {{c}} + d </view>


<!-- Output 3 + 3 + d -->
類似於算數運算,還支持字串的拼接,如下代碼所示:
js
<!--
{ name: 'world' }
-->


<view>{{"hello " + name}}</view>


<!-- Output hello world -->
括號中也可以直接放置數字、字串或是數組,如下程序碼所示:
js
<text>{{[1,2,3]}}</text>

<!-- Output 1,2,3 -->



<text>{{"hello world"}}</text>

<!-- Output hello world -->

條件邏輯

WXML 中,使用 wx:if="{{condition}}" 來判斷是否需要渲染該程式碼區塊:

js
<view wx:if="{{condition}}"> True </view>
使用wx:elif和wx:else來添加一個else塊:
js
<view wx:if="{{length > 5}}"> 1 </view>
<view wx:elif="{{length > 2}}"> 2 </view>
<view wx:else> 3 </view>
因為wx:if是一個控制内容,需要將它添加到一個標籤上如果要一次性判斷多個組件標籤,可以使用一個<block/>標籤將多個組件包裝起來,並在上邊使用wx:if控制内容。
js
<block wx:if="{{true}}">
  <view> view1 </view>
  <view> view2 </view>
</block>

清單渲染

在組件上使用wx:for控制内容綁定一個數組,即可使用數組中各項的數據重複渲染該組件默認數組的當前項的下標變量名默認為index,數組當前項的變量名默認為item,如下代碼所示:

js
<!-- `array` is an array -->
<view wx:for="{{array}}">
  {{index}}: {{item.message}}
</view>

<!-- Corresponding script file
Page({
  data: {
    array: [{
      message: 'foo',
    }, {
      message: 'bar'
    }]
  }
})
-->
使用wx:for-item指定數組當前元素的變量名,使用wx:for-index指定數組當前下標的變量名:
js
<view wx:for="{{array}}" wx:for-index="idx" wx:for-item="itemName">
  {{idx}}: {{itemName.message}}
</view>
類似block wx: if , 也可以將wx:for用在<block/>標籤上,以渲染一個包含多節點的結構塊,如下代碼所示:
js
<block wx:for="{{[1, 2, 3]}}">
  <view> {{index}}: </view>
  <view> {{item}} </view>
</block>
如果清單中項目的位置會動態改變或者有新的項目添加到清單中,並且希望清單中的項目保持自己的特徵和狀態(如<input/>中的輸入內容,<switch/>的選中狀態),需要使用wx:key來指定清單中項目的唯一的識別字。
wx:key的值以兩種形式提供:
1. 字串,代表在for迴圈的array中item的某個property,該property的值需要是清單中唯一的字串或數位,且不能動態改變。
2. 保留關鍵字this代表在for迴圈中的item本身,這種表示需要item本身是一個唯一的字串或者數位,如:
當數據改變觸發渲染層重新渲染的時候,會校正帶有key的組件,框架會確保他們被重新排序,而不是重新創建,以確保使組件保持自身的狀態,並且提高清單渲染時的效率,如下代碼所示:
js
<switch wx:for="{{objectArray}}" wx:key="unique" > {{item.id}} </switch>
<button bindtap="switch"> Switch </button>
<button bindtap="addToFront"> Add to the front </button>


<switch wx:for="{{numberArray}}" wx:key="*this" > {{item}} </switch>
<button bindtap="addNumberToFront"> Add Number to the front </button>
js
Page({
  data: {
    objectArray: [
      {id: 5, unique: 'unique_5'},
      {id: 4, unique: 'unique_4'},
      {id: 3, unique: 'unique_3'},
      {id: 2, unique: 'unique_2'},
      {id: 1, unique: 'unique_1'},
      {id: 0, unique: 'unique_0'},
    ],
    numberArray: [1, 2, 3, 4]
  },
  switch: function(e) {
    const length = this.data.objectArray.length
    for (let i = 0; i < length; ++i) {
      const x = Math.floor(Math.random() * length)
      const y = Math.floor(Math.random() * length)
      const temp = this.data.objectArray[x]
      this.data.objectArray[x] = this.data.objectArray[y]
      this.data.objectArray[y] = temp
    }
    this.setData({
      objectArray: this.data.objectArray
    })
  },
  addToFront: function(e) {
    const length = this.data.objectArray.length
    this.data.objectArray = [{id: length, unique: 'unique_' + length}].concat(this.data.objectArray)
    this.setData({
      objectArray: this.data.objectArray
    })
  },
  addNumberToFront: function(e){
    this.data.numberArray = [ this.data.numberArray.length + 1 ].concat(this.data.numberArray)
    this.setData({
      numberArray: this.data.numberArray
    })
  }
})

模版

WXML提供模版(template),可以在模版中定義代碼片段,然後在不同的地方調用使用name内容,作為模版的名字然後在<template/>內定義代碼片段,如下代碼所示:

js
<template name="msgItem">
  <view>
    <text> {{index}}: {{msg}} </text>
    <text> Time: {{time}} </text>
  </view>
</template>
使用is内容,聲明需要的使用的模版,然後將模版所需要的data傳入,如下代碼所示:
js
<!--
item: {
  index: 0,
  msg: 'this is a template',
  time: '2016-06-18'
}
-->


<template name="msgItem">
  <view>
    <text> {{index}}: {{msg}} </text>
    <text> Time: {{time}} </text>
  </view>
</template>


<template is="msgItem" data="{{...item}}"/>

<!-- Output
0: this is a template Time: 2016-06-18
-->
使用is可以動態决定具體需要渲染哪個模版,如下代碼所示:
js

<template name="odd">
  <view> odd </view>
</template>


<template name="even">
  <view> even </view>
</template>


<block wx:for="{{[1, 2, 3, 4, 5]}}">
  <template is="{{item % 2 == 0 ? 'even' : 'odd'}}"/>
</block>



<!-- Output
odd
even
odd
even
odd
-->

引用

WXML提供兩種文件引用管道import和include。

import可以在該文件中使用目標文件定義的template,如:在item.wxml中定義了一個叫item的template。
js
<!-- item.wxml -->
<template name="item">
  <text>{{text}}</text>
</template>
在index.wxml中引用了item.wxml,就可以使用item模版:
js
<import src="item.wxml"/>

<template is="item" data="{{text: 'forbar'}}"/>
需要注意的是import有作用域的概念,即只會import目標文件中定義的template,而不會import目標文件中import的template,簡言之就是import不具有遞迴的特性。
例如:C引用B,B引用A,在C中可以使用B定義的template,在B中可以使用A定義的template,但是C不能使用A定義的template,如下代碼所示:
js
<!-- A.wxml -->
<template name="A">
  <text> A template </text>
</template>
js
<!-- B.wxml --><import src="a.wxml"/><template name="B">  <text> B template </text></template>
js
<!-- C.wxml -->
<import src="b.wxml"/>

<template is="A"/>  <!-- A warning will be triggered here because template A is not defined in b -->

<template is="B"/>
include可以將目標文件中除了<template/> <wxs/>外的整個代碼引入,相當於是拷貝到include位置,如下代碼所示:
js
<!-- index.wxml -->
<include src="header.wxml"/>

<view> body </view>

<include src="footer.wxml"/>
js
<!-- header.wxml -->
<view> header </view>
js
<!-- footer.wxml -->
<view> footer </view>

共同内容

所有wxml標籤都支持的内容稱之為共同内容,如下表所示。
内容名
類型
描述
注解
id
String
組件的唯一標識
整個頁面唯一
class
String
組件的樣式類
在對應的WXSS中定義的樣式類
style
String
組件的內聯樣式
可以動態設定的內聯樣式
hidden
Boolean
組件是否顯示
所有組件默認顯示
data-*
Any
自訂屬性
組件上觸發的事件時,會發送給事件處理函數
bind*/catch*
EventHandler
組件的事件
-