微信小程序WXML

原文地址:WXML

一、說明

WXML(WeiXin Markup Language)是框架設計的一套標籤語言,結合基礎組件、事件系統,可以構建出頁面的結構。其基本功能如下:


二、數據綁定

原文地址:WXML數據綁定
WXML 中的動態數據均來自對應 Page 的 data。在WXML中,使用雙大括號將變量包起來,框架會在在對應的page.js中尋找此變量的值。幾種常見用法如下:

2.1 簡單綁定

  • page.js中聲明數據
Page({
  data: {
    message: 'Hello MINA!',
    id: 0,
    condition: true
  }
})
  • WXML中進行數據簡單綁定
<!-- 簡單內容 -->
<view> {{ message }} </view>
<!-- 組件屬性(需要在雙引號之內) -->
<view id="item-{{id}}"> </view>
<!-- 控制屬性(需要在雙引號之內) -->
<view wx:if="{{condition}}"> </view>
<!-- 關鍵字(需要在雙引號之內) -->
<checkbox checked="{{false}}"> </checkbox>

2.2 在 {{}} 內進行簡單的運算

  • page.js中聲明數據
Page({
  data: {
    a: 1,
    b: 2,
    c: 3,
    name: 'MINA',
    object: {
      key: 'Hello '
    },
    array: ['MINA'],
    zero: 0,
    obj1: {
      a: 1,
      b: 2
    },
    obj2: {
      c: 3,
      d: 4
    }
  }
})
  • WXML中進行運算
<!-- 三元運算 -->
<view hidden="{{flag ? true : false}}"> Hidden </view>
<!-- 算數運算 -->
<view> {{a + b}} + {{c}} + d </view>
<!-- 邏輯判斷 -->
<view wx:if="{{length > 5}}"> </view>
<!-- 字符串運算 -->
<view>{{"hello" + name}}</view>
<!-- 數據路徑運算 -->
<view>{{object.key}} {{array[0]}}</view>

2.3 組合

也可以在 Mustache 內直接進行組合,構成新的對象或者數組。

組合數組:

  • page.js中聲明數據
Page({
  data: {
    zero: 0,
  }
})
  • 在WXML中合成數組
<view wx:for="{{[zero, 1, 2, 3, 4]}}"> {{item}} </view>

最終組合成的數組爲[0,1,2,3,4]。

組合對象:

  • page.js中聲明數據
Page({
  data: {
    a: 1,
    b: 2
  }
})
  • 在WXML中合成對象
<template is="objectCombine" data="{{for: a, bar: b}}"></template>

最終組合成的對象是{for: 1, bar: 2}

也可以用擴展運算符 … 來將一個對象展開

  • page.js中聲明數據
Page({
  data: {
    obj1: {
      a: 1,
      b: 2
    },
    obj2: {
      c: 3,
      d: 4
    }
  }
})
  • 在WXML中合成對象
<template is="objectCombine" data="{{...obj1, ...obj2, e: 5}}"></template>

最終組合成的對象是 {a: 1, b: 2, c: 3, d: 4, e: 5}

如果對象的 key 和 value 相同,也可以間接地表達。

  • page.js中聲明數據
Page({
  data: {
    foo: 'my-foo',
    bar: 'my-bar'
  }
})
  • 在WXML中合成對象
<template is="objectCombine" data="{{foo, bar}}"></template>

最終組合成的對象是{foo: 'my-foo', bar:'my-bar'}

注意:上述方式可以隨意組合,但是如有存在變量名相同的情況,後邊的會覆蓋前面
花括號和引號之間如果有空格,將最終被解析成爲字符串("{{[1,2,3]}} "等同於"{{[1,2,3] + ' '}}"


三、列表渲染

原文地址:WXML列表渲染

WXML可以通過一些特殊屬性控制列表的渲染,這些控制屬性如下:

3.1 wx:for

在組件上使用 wx:for 控制屬性綁定一個數組,即可使用數組中各項的數據重複渲染該組件。

默認數組的當前項的下標變量名默認爲 index,數組當前項的變量名默認爲 item。

  • page.js中聲明數據
Page({
  data: {
    array: [{
      message: 'foo',
    }, {
      message: 'bar'
    }]
  }
})
  • WXML中渲染
<!-- 簡單渲染 -->
<view wx:for="{{array}}">
  {{index}}: {{item.message}}
</view>
<!-- 使用 wx:for-item 可以指定數組當前元素的變量名 -->
<!-- 使用 wx:for-index 可以指定數組當前下標的變量名 -->
<view wx:for="{{array}}" wx:for-index="idx" wx:for-item="itemName">
  {{idx}}: {{itemName.message}}
</view>
<!-- wx:for 也可以嵌套,下邊是一個九九乘法表 -->
<view wx:for="{{[1, 2, 3, 4, 5, 6, 7, 8, 9]}}" wx:for-item="i">
  <view wx:for="{{[1, 2, 3, 4, 5, 6, 7, 8, 9]}}" wx:for-item="j">
    <view wx:if="{{i <= j}}">
      {{i}} * {{j}} = {{i * j}}
    </view>
  </view>
</view>

3.2 block wx:for

將 wx:for 用在<block/>標籤上,可以渲染一個包含多節點的結構塊。如:

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

3.3 wx:key

如果列表中項目的位置會動態改變或者有新的項目添加到列表中,並且希望列表中的項目保持自己的特徵和狀態(如<input/> 中的輸入內容,<switch/>的選中狀態),需要使用 wx:key 來指定列表中項目的唯一的標識符。

wx:key 的值以兩種形式提供

  1. 字符串,代表在 for 循環的 array 中 item 的某個 property,該 property 的值需要是列表中唯一的字符串或數字,且不能動態改變。
  2. 保留關鍵字*this 代表在 for 循環中的 item 本身,這種表示需要 item 本身是一個唯一的字符串或者數字(如:當數據改變觸發渲染層重新渲染的時候,會校正帶有 key 的組件,框架會確保他們被重新排序,而不是重新創建,以確保使組件保持自身的狀態,並且提高列表渲染時的效率)

示例代碼:

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
    })
  }
})
<switch wx:for="{{objectArray}}" wx:key="unique" style="display: block;"> {{item.id}} </switch>
<button bindtap="switch"> Switch </button>
<button bindtap="addToFront"> Add to the front </button>

<switch wx:for="{{numberArray}}" wx:key="*this" style="display: block;"> {{item}} </switch>
<button bindtap="addNumberToFront"> Add to the front </button>

注意:當 wx:for 的值爲字符串時,會將字符串解析成字符串數組;花括號和引號之間如果有空格,將最終被解析成爲字符串


四、條件渲染

原文地址:WXML條件渲染

WXML支持條件渲染

4.1 wx:if

在框架中,使用wx:if="{{condition}}"來判斷是否需要渲染該代碼塊:

<view wx:if="{{condition}}"> True </view>

也可以用 wx:elif 和 wx:else 來添加一個 else 塊:

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

4.2 block wx:if

如果要一次性判斷多個組件標籤,可以使用一個<block/>標籤將多個組件包裝起來,並在上邊使用 wx:if 控制屬性。

<block wx:if="{{true}}">
  <view> view1 </view>
  <view> view2 </view>
</block>

4.3 wx:if vs hidden

由於 wx:if 之中的模板也可能包含數據綁定,所以當 wx:if 的條件值切換時,框架有一個局部渲染的過程(框架會確保條件塊在切換時銷燬或重新渲染)。

同時 wx:if 也是惰性的,如果在初始渲染條件爲 false,框架什麼也不做,在條件第一次變成真的時候纔開始局部渲染。

相比之下,hidden 就簡單的多,組件始終會被渲染,只是簡單的控制顯示與隱藏。

一般來說,wx:if 有更高的切換消耗而 hidden 有更高的初始渲染消耗。因此,如果需要頻繁切換的情景下,用 hidden 更好,如果在運行時條件不大可能改變則 wx:if 較好。


五、模板

原文地址:WXML模板

WXML提供模板(template),可以在模板中定義代碼片段,然後在不同的地方調用。

5.1 定義模板

使用 name 屬性,作爲模板的名字。然後在<template/>內定義代碼片段,如:

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

5.2 使用模板

使用 is 屬性,聲明需要的使用的模板,然後將模板所需要的 data 傳入,如:

<template is="msgItem" data="{{...item}}"/>
Page({
  data: {
    item: {
      index: 0,
      msg: 'this is a template',
      time: '2016-09-15'
    }
  }
})

is 屬性可以使用 Mustache 語法,來動態決定具體需要渲染哪個模板:

<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>

注意:模板擁有自己的作用域,只能使用 data 傳入的數據以及模版定義文件中定義的 <wxs /> 模塊。


六、事件

原文地址:WXML事件

6.1 什麼是事件

  • 事件是視圖層到邏輯層的通訊方式。
  • 事件可以將用戶的行爲反饋到邏輯層進行處理。
  • 事件可以綁定在組件上,當達到觸發事件,就會執行邏輯層中對應的事件處理函數。
  • 事件對象可以攜帶額外信息,如 id, dataset, touches。

6.2 事件的使用方式

  • 在組件中綁定一個事件處理函數。
    如bindtap,當用戶點擊該組件的時候會在該頁面對應的Page中找到相應的事件處理函數。
<view id="tapTest" data-hi="WeChat" bindtap="tapName"> Click me! </view>
  • 在相應的Page定義中寫上相應的事件處理函數,參數是event。
Page({
  tapName: function(event) {
    console.log(event)
  }
})

事件中包含的信息如下:

{
"type":"tap",
"timeStamp":895,
"target": {
  "id": "tapTest",
  "dataset":  {
    "hi":"WeChat"
  }
},
"currentTarget":  {
  "id": "tapTest",
  "dataset": {
    "hi":"WeChat"
  }
},
"detail": {
  "x":53,
  "y":14
},
"touches":[{
  "identifier":0,
  "pageX":53,
  "pageY":14,
  "clientX":53,
  "clientY":14
}],
"changedTouches":[{
  "identifier":0,
  "pageX":53,
  "pageY":14,
  "clientX":53,
  "clientY":14
}]
}

6.3 事件分類

事件分爲冒泡事件和非冒泡事件:

  • 冒泡事件:當一個組件上的事件被觸發後,該事件會向父節點傳遞。
  • 非冒泡事件:當一個組件上的事件被觸發後,該事件不會向父節點傳遞。

WXML的冒泡事件列表:

類型 觸發條件 最低版本
touchstart 手指觸摸動作開始
touchmove 手指觸摸後移動
touchcancel 手指觸摸動作被打斷,如來電提醒,彈窗
touchend 手指觸摸動作結束
tap 手指觸摸後馬上離開
longpress 手指觸摸後,超過350ms再離開,如果指定了事件回調函數並觸發了這個事件,tap事件將不被觸發 1.5.0
longtap 手指觸摸後,超過350ms再離開(推薦使用longpress事件代替)
transitionend 會在 WXSS transition 或 wx.createAnimation 動畫結束後觸發
animationstart 會在一個 WXSS animation 動畫開始時觸發
animationiteration 會在一個 WXSS animation 一次迭代結束時觸發
animationend 會在一個 WXSS animation 動畫完成時觸發
touchforcechange 在支持 3D Touch 的 iPhone 設備,重按時會觸發 1.9.90

注:除上表之外的其他組件自定義事件如無特殊聲明都是非冒泡事件,如<form/>的submit事件,<input/>的input事件,<scroll-view/>的scroll事件

6.4 事件綁定和冒泡

事件綁定的寫法同組件的屬性,以 key、value 的形式。

  • key 以bind或catch開頭,然後跟上事件的類型,如bindtap、catchtouchstart。自基礎庫版本 1.5.0 起,bind和catch後可以緊跟一個冒號,其含義不變,如bind:tap、catch:touchstart。
  • value 是一個字符串,需要在對應的 Page 中定義同名的函數。不然當觸發事件的時候會報錯。

bind事件綁定不會阻止冒泡事件向上冒泡,catch事件綁定可以阻止冒泡事件向上冒泡。

如在下邊這個例子中,點擊 inner view 會先後調用handleTap3和handleTap2(因爲tap事件會冒泡到 middle view,而 middle view 阻止了 tap 事件冒泡,不再向父節點傳遞),點擊 middle view 會觸發handleTap2,點擊 outer view 會觸發handleTap1。

<view id="outer" bindtap="handleTap1">
  outer view
  <view id="middle" catchtap="handleTap2">
    middle view
    <view id="inner" bindtap="handleTap3">
      inner view
    </view>
  </view>
</view>

6.5 事件的捕獲階段

自基礎庫版本 1.5.0 起,觸摸類事件支持捕獲階段。捕獲階段位於冒泡階段之前,且在捕獲階段中,事件到達節點的順序與冒泡階段恰好相反。需要在捕獲階段監聽事件時,可以採用capture-bind、capture-catch關鍵字,後者將中斷捕獲階段和取消冒泡階段。

在下面的代碼中,點擊 inner view 會先後調用handleTap2、handleTap4、handleTap3、handleTap1。

<view id="outer" bind:touchstart="handleTap1" capture-bind:touchstart="handleTap2">
  outer view
  <view id="inner" bind:touchstart="handleTap3" capture-bind:touchstart="handleTap4">
    inner view
  </view>
</view>

如果將上面代碼中的第一個capture-bind改爲capture-catch,將只觸發handleTap2。

<view id="outer" bind:touchstart="handleTap1" capture-catch:touchstart="handleTap2">
  outer view
  <view id="inner" bind:touchstart="handleTap3" capture-bind:touchstart="handleTap4">
    inner view
  </view>
</view>

6.6 事件對象

如無特殊說明,當組件觸發事件時,邏輯層綁定該事件的處理函數會收到一個事件對象。

  • BaseEvent 基礎事件對象屬性列表:
屬性 類型 說明
type String 事件類型
timeStamp Integer 事件生成時的時間戳
target Object 觸發事件的組件的一些屬性值集合
currentTarget Object 當前組件的一些屬性值集合
  • CustomEvent 自定義事件對象屬性列表(繼承 BaseEvent):
屬性 類型 說明
detail Object 額外的信息
  • TouchEvent 觸摸事件對象屬性列表(繼承 BaseEvent):
屬性 類型 說明
touches Array 觸摸事件,當前停留在屏幕中的觸摸點信息的數組
changedTouches Array 觸摸事件,當前變化的觸摸點信息的數組

特殊事件: <canvas/> 中的觸摸事件不可冒泡,所以沒有 currentTarget。

更具體的屬性內容請看原文檔


七、引用

原文地址:WXML引用

7.1 說明

WXML 提供兩種文件引用方式import和include。

7.1.1 import

import可以在該文件中使用目標文件定義的template,如:
在 item.wxml 中定義了一個叫item的template:

<!-- item.wxml -->
<template name="item">
  <text>{{text}}</text>
</template>

在 index.wxml 中引用了 item.wxml,就可以使用item模板:

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

import 有作用域的概念,即只會 import 目標文件中定義的 template,而不會 import 目標文件 import 的 template。
如:C import B,B import A,在C中可以使用B定義的template,在B中可以使用A定義的template,但是C不能使用A定義的template。

7.1.2 include

include 可以將目標文件除了 <template/> <wxs/> 外的整個代碼引入,相當於是拷貝到 include 位置

發佈了22 篇原創文章 · 獲贊 9 · 訪問量 5萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章