小程序官方開發(fā)文檔學(xué)習(xí)(三)-- 視圖層

WXML
數(shù)據(jù)綁定
列表渲染
條件渲染
模板
事件
XWSS

WXML

  • WXML(WeiXin Markup Language)是框架設(shè)計(jì)的一套標(biāo)簽語言,結(jié)合基礎(chǔ)組件、事件系統(tǒng),可以構(gòu)建出頁面的結(jié)構(gòu)。
  • WXML的能力:數(shù)據(jù)綁定、列表渲染、條件渲染、模板、事件

數(shù)據(jù)綁定

  • 數(shù)據(jù)綁定: WXML 中的動(dòng)態(tài)數(shù)據(jù)均來自對(duì)應(yīng) Page 的 data。
簡單綁定:數(shù)據(jù)綁定使用 Mustache 語法(雙大括號(hào))將變量包起來,
可以作用于:內(nèi)容、組件屬性(需在雙引號(hào)之內(nèi))、控制屬性(需在雙引號(hào)之內(nèi))、關(guān)鍵字(需在雙引號(hào)之內(nèi))
true:boolean 類型的 true,代表真值。
false: boolean 類型的 false,代表假值。
<checkbox checked="{{false}}"> </checkbox>
特別注意:不要直接寫 checked="false",其計(jì)算結(jié)果是一個(gè)字符串,轉(zhuǎn)成 boolean 類型后代表真值。
  • 運(yùn)算可以在 {{}} 內(nèi)進(jìn)行簡單的運(yùn)算,支持的有如下幾種方式:
三元運(yùn)算:
 <view hidden="{{flag ? true : false}}"> Hidden </view>

參數(shù)運(yùn)算:
 <view> {{a + b}} + {{c}} + d </view>
Page({
  data: {
    a: 1,
    b: 2,
    c: 3
  }
})
view中的內(nèi)容為3 + 3 + d

邏輯判斷:
<view wx:if="{{length > 5}}"> </view>

字符串運(yùn)算:
<view>{{"hello" + name}}</view>
Page({
  data:{
    name: 'MINA'
  }
})

數(shù)據(jù)路徑運(yùn)算:
<view>{{object.key}} {{array[0]}}</view>
Page({
  data: {
    object: {
      key: 'Hello '
    },
    array: ['MINA']
  }
})

  • 組合--也可以在 Mustache 內(nèi)直接進(jìn)行組合,構(gòu)成新的對(duì)象或者數(shù)組。
數(shù)組:
<view wx:for="{{[zero, 1, 2, 3, 4]}}"> {{item}} </view>
Page({
  data: {
    zero: 0
  }
})
最終組合成數(shù)組[0, 1, 2, 3, 4]。

對(duì)象:
<template is="objectCombine" data="{{for: a, bar: b}}"></template>
Page({
  data: {
    a: 1,
    b: 2
  }
})
最終組合成的對(duì)象是 {for: 1, bar: 2}

擴(kuò)展運(yùn)算符:
也可以用擴(kuò)展運(yùn)算符 ... 來將一個(gè)對(duì)象展開
<template is="objectCombine" data="{{...obj1, ...obj2, e: 5}}"></template>
Page({
  data: {
    obj1: {
      a: 1,
      b: 2
    },
    obj2: {
      c: 3,
      d: 4
    }
  }
})
最終組合成的對(duì)象是 {a: 1, b: 2, c: 3, d: 4, e: 5}。

如果對(duì)象的 key 和 value 相同,也可以間接地表達(dá)。
<template is="objectCombine" data="{{foo, bar}}"></template>
Page({
  data: {
    foo: 'my-foo',
    bar: 'my-bar'
  }
})
最終組合成的對(duì)象是 {foo: 'my-foo', bar:'my-bar'}。
注意:上述方式可以隨意組合,但是如有存在變量名相同的情況,后邊的會(huì)覆蓋前面,如:
<template is="objectCombine" data="{{...obj1, ...obj2, a, c: 6}}"></template>
Page({
  data: {
    obj1: {
      a: 1,
      b: 2
    },
    obj2: {
      b: 3,
      c: 4
    },
    a: 5
  }
})

最終組合成的對(duì)象是 {a: 5, b: 3, c: 6}。

條件渲染

  • wx:if
在框架中,我們用 wx:if="{{condition}}" 來判斷是否需要渲染該代碼塊:
<view wx:if="{{condition}}"> True </view>
也可以用 wx:elif 和 wx:else 來添加一個(gè) else 塊:
<view wx:if="{{length > 5}}"> 1 </view>
<view wx:elif="{{length > 2}}"> 2 </view>
<view wx:else> 3 </view>

*block wx:if

因?yàn)?wx:if 是一個(gè)控制屬性,需要將它添加到一個(gè)標(biāo)簽上。但是如果我們想一次性判斷多個(gè)組件標(biāo)簽,我們可以使用一個(gè) <block/> 標(biāo)簽將多個(gè)組件包裝起來,并在上邊使用 wx:if 控制屬性。
<block wx:if="{{true}}">
  <view> view1 </view>
  <view> view2 </view>
</block>

注意: <block/> 并不是一個(gè)組件,它僅僅是一個(gè)包裝元素,不會(huì)在頁面中做任何渲染,只接受控制屬性。
  • wx:if vs hidden
因?yàn)?wx:if 之中的模板也可能包含數(shù)據(jù)綁定,所有當(dāng) wx:if 的條件值切換時(shí),框架有一個(gè)局部渲染的過程,因?yàn)樗鼤?huì)確保條件塊在切換時(shí)銷毀或重新渲染。
同時(shí) wx:if 也是惰性的,如果在初始渲染條件為 false,框架什么也不做,在條件第一次變成真的時(shí)候才開始局部渲染。
相比之下,hidden 就簡單的多,組件始終會(huì)被渲染,只是簡單的控制顯示與隱藏。
一般來說,wx:if 有更高的切換消耗而 hidden 有更高的初始渲染消耗。因此,如果需要頻繁切換的情景下,用 hidden 更好,如果在運(yùn)行時(shí)條件不大可能改變則 wx:if 較好。

列表渲染

  • wx:for
在組件上使用wx:for控制屬性綁定一個(gè)數(shù)組,即可使用數(shù)組中各項(xiàng)的數(shù)據(jù)重復(fù)渲染該組件。
默認(rèn)數(shù)組的當(dāng)前項(xiàng)的下標(biāo)變量名默認(rèn)為index,數(shù)組當(dāng)前項(xiàng)的變量名默認(rèn)為item
<view wx:for="{{array}}">
  {{index}}: {{item.message}}
</view>
Page({
  data: {
    array: [{
      message: 'foo',
    }, {
      message: 'bar'
    }]
  }
})
使用 wx:for-item 可以指定數(shù)組當(dāng)前元素的變量名,
使用 wx:for-index 可以指定數(shù)組當(dāng)前下標(biāo)的變量名:

<view wx:for="{{array}}" wx:for-index="idx" wx:for-item="itemName">
  {{idx}}: {{itemName.message}}
</view>

wx:for也可以嵌套,下邊是一個(gè)九九乘法表
<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>

  • block wx:for
類似block wx:if,也可以將wx:for用在<block/>標(biāo)簽上,以渲染一個(gè)包含多節(jié)點(diǎn)的結(jié)構(gòu)塊。例如:
<block wx:for="{{[1, 2, 3]}}">
  <view> {{index}}: </view>
  <view> {{item}} </view>
</block>
  • wx:key
如果列表中項(xiàng)目的位置會(huì)動(dòng)態(tài)改變或者有新的項(xiàng)目添加到列表中,并且希望列表中的項(xiàng)目保持自己的特征和狀態(tài)(如 <input/> 中的輸入內(nèi)容,<switch/> 的選中狀態(tài)),需要使用 wx:key 來指定列表中項(xiàng)目的唯一的標(biāo)識(shí)符。
wx:key 的值以兩種形式提供
    1.字符串,代表在 for 循環(huán)的 array 中 item 的某個(gè) property,該 property 的值需要是列表中唯一的字符串或數(shù)字,且不能動(dòng)態(tài)改變。
    2.保留關(guān)鍵字 *this 代表在 for 循環(huán)中的 item 本身,這種表示需要 item 本身是一個(gè)唯一的字符串或者數(shù)字,如:
當(dāng)數(shù)據(jù)改變觸發(fā)渲染層重新渲染的時(shí)候,會(huì)校正帶有 key 的組件,框架會(huì)確保他們被重新排序,而不是重新創(chuàng)建,以確保使組件保持自身的狀態(tài),并且提高列表渲染時(shí)的效率。
如不提供 wx:key,會(huì)報(bào)一個(gè) warning, 如果明確知道該列表是靜態(tài),或者不必關(guān)注其順序,可以選擇忽略。

示例代碼:
<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>

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

說明:上邊的例子通過展示開關(guān)控件,可以任意打開某幾個(gè),這樣使用wx:key 相對(duì)應(yīng)的switch就會(huì)保持自己的狀態(tài),這樣物流是switch排序的方法還是addToFront在最前邊增加的方法都是可以讓之前的狀態(tài)保持的
總結(jié):js文件中設(shè)置數(shù)據(jù)源 wxml為控件設(shè)置點(diǎn)擊,js中實(shí)現(xiàn)點(diǎn)擊方法,重新更新數(shù)據(jù)源,每次更新后,wxml也會(huì)進(jìn)行渲染

模板

  • WXML提供模板(template),可以在模板中定義代碼片段,然后在不同的地方調(diào)用。
  • 定義模板
<!--
  index: int
  msg: string
  time: string
-->
<template name="msgItem">
  <view>
    <text> {{index}}: {{msg}} </text>
    <text> Time: {{time}} </text>
  </view>
</template>
  • 使用模板--使用 is 屬性,聲明需要的使用的模板,然后將模板所需要的 data 傳入,如:
<template is="msgItem" data="{{...item}}"/>

Page({
  data: {
    item: {
      index: 0,
      msg: 'this is a template',
      time: '2016-09-15'
    }
  }
})

is 屬性可以使用 Mustache 語法,來動(dòng)態(tài)決定具體需要渲染哪個(gè)模板:
<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傳入的數(shù)據(jù)。

事件

  • 什么是事件?
    1.事件是視圖層到邏輯層的通訊方式。
    2.事件可以將用戶的行為反饋到邏輯層進(jìn)行處理。
    3.事件可以綁定在組件上,當(dāng)達(dá)到觸發(fā)事件,就會(huì)執(zhí)行邏輯層中對(duì)應(yīng)的事件處理函數(shù)。
    4.事件對(duì)象可以攜帶額外信息,如 id, dataset, touches。

  • 事件的使用方式
1.在組件中綁定一個(gè)事件處理函數(shù)。
如bindtap,當(dāng)用戶點(diǎn)擊該組件的時(shí)候會(huì)在該頁面對(duì)應(yīng)的Page中找到相應(yīng)的事件處理函數(shù)。
<view id="tapTest" data-hi="WeChat" bindtap="tapName"> Click me! </view>
說明:在點(diǎn)擊事件中需要傳遞一些信息的時(shí)候使用data-xxx=“aaa”,這樣在js方法參數(shù)中,就會(huì)攜帶xxx: aaa這樣的數(shù)據(jù),方便進(jìn)行下一步的操作

2.在相應(yīng)的Page定義中寫上相應(yīng)的事件處理函數(shù),參數(shù)是event。
Page({
  tapName: function(event) {
    console.log(event)
  }
})

3.可以看到log出來的信息大致如下:
{
"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
}]
}
  • 事件分類
事件分為冒泡事件和非冒泡事件:
1.冒泡事件:當(dāng)一個(gè)組件上的事件被觸發(fā)后,該事件會(huì)向父節(jié)點(diǎn)傳遞。
2.非冒泡事件:當(dāng)一個(gè)組件上的事件被觸發(fā)后,該事件不會(huì)向父節(jié)點(diǎn)傳遞。

WXML的冒泡事件列表:

WXML的冒泡事件列表.png

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

  • 事件綁定
事件綁定的寫法同組件的屬性,以 key、value 的形式。
1.key 以bind或catch開頭,然后跟上事件的類型,如bindtap, catchtouchstart
2. value 是一個(gè)字符串,需要在對(duì)應(yīng)的 Page 中定義同名的函數(shù)。不然當(dāng)觸發(fā)事件的時(shí)候會(huì)報(bào)錯(cuò)。

bind事件綁定不會(huì)阻止冒泡事件向上冒泡,catch事件綁定可以阻止冒泡事件向上冒泡。
如在下邊這個(gè)例子中,點(diǎn)擊 inner view 會(huì)先后觸發(fā)handleTap3和handleTap2(因?yàn)閠ap事件會(huì)冒泡到 middle view,而 middle view 阻止了 tap 事件冒泡,不再向父節(jié)點(diǎn)傳遞),點(diǎn)擊 middle view 會(huì)觸發(fā)handleTap2,點(diǎn)擊 outter view 會(huì)觸發(fā)handleTap1。
<view id="outter" bindtap="handleTap1">
  outer view
  <view id="middle" catchtap="handleTap2">
    middle view
    <view id="inner" bindtap="handleTap3">
      inner view
    </view>
  </view>
</view>
  • 事件對(duì)象
    如無特殊說明,當(dāng)組件觸發(fā)事件時(shí),邏輯層綁定該事件的處理函數(shù)會(huì)收到一個(gè)事件對(duì)象。
    1.BaseEvent 基礎(chǔ)事件對(duì)象屬性列表:
BaseEvent 基礎(chǔ)事件對(duì)象屬性列表.png

2.CustomEvent 自定義事件對(duì)象屬性列表(繼承 BaseEvent):

CustomEvent 自定義事件對(duì)象屬性列表.png

3.TouchEvent 觸摸事件對(duì)象屬性列表(繼承 BaseEvent):

TouchEvent 觸摸事件對(duì)象屬性列表.png

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

type: 代表事件的類型。
timeStamp: 頁面打開到觸發(fā)事件所經(jīng)過的毫秒數(shù)。
target: 觸發(fā)事件的源組件。
currentTarget: 事件綁定的當(dāng)前組件。
觸發(fā)事件的源組件.png
事件綁定的當(dāng)前組件.png

<strong>說明: target 和 currentTarget 可以參考上例中,點(diǎn)擊 inner view 時(shí),handleTap3 收到的事件對(duì)象 target 和 currentTarget 都是 inner,而 handleTap2 收到的事件對(duì)象 target 就是 inner,currentTarget 就是 middle。</strong>

  • dataset: 在組件中可以定義數(shù)據(jù),這些數(shù)據(jù)將會(huì)通過事件傳遞給 SERVICE。 書寫方式: 以data-開頭,多個(gè)單詞由連字符-鏈接,不能有大寫(大寫會(huì)自動(dòng)轉(zhuǎn)成小寫)如data-element-type,最終在 event.target.dataset 中會(huì)將連字符轉(zhuǎn)成駝峰e(cuò)lementType。
示例:

<view data-alpha-beta="1" data-alphaBeta="2" bindtap="bindViewTap"> DataSet Test </view>

Page({
  bindViewTap:function(event){
    event.target.dataset.alphaBeta === 1 // - 會(huì)轉(zhuǎn)為駝峰寫法
    event.target.dataset.alphabeta === 2 // 大寫會(huì)轉(zhuǎn)為小寫
  }
})

  • touches 是一個(gè)數(shù)組,每個(gè)元素為一個(gè) Touch 對(duì)象(canvas 觸摸事件中攜帶的 touches 是 CanvasTouch 數(shù)組)。 表示當(dāng)前停留在屏幕上的觸摸點(diǎn)。
Touch對(duì)象.png
  • CanvasTouch對(duì)象
CanvasTouch對(duì)象.png
  • changedTouches -- changedTouches 數(shù)據(jù)格式同 touches。 表示有變化的觸摸點(diǎn),如從無變有(touchstart),位置變化(touchmove),從有變無(touchend、touchcancel)。
  • detail -- 自定義事件所攜帶的數(shù)據(jù),如表單組件的提交事件會(huì)攜帶用戶的輸入,媒體的錯(cuò)誤事件會(huì)攜帶錯(cuò)誤信息,詳見組件定義中各個(gè)事件的定義。

引用

  • WXML 提供兩種文件引用方式import和include。
1.import
import可以在該文件中使用目標(biāo)文件定義的template,如:
在 item.wxml 中定義了一個(gè)叫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'}}"/>

2.import 的作用域
import 有作用域的概念,即只會(huì) import 目標(biāo)文件中定義的 template,而不會(huì) import 目標(biāo)文件 import 的 template。
如:C import B,B import A,在C中可以使用B定義的template,在B中可以使用A定義的template,但是C不能使用A定義的template。

<!-- A.wxml -->
<template name="A">
  <text> A template </text>
</template>

<!-- B.wxml -->
<import src="a.wxml"/>
<template name="B">
  <text> B template </text>
</template>

<!-- C.wxml -->
<import src="b.wxml"/>
<template is="A"/>  <!-- Error! Can not use tempalte when not import A. -->
<template is="B"/>

4.include
include可以將目標(biāo)文件除了<template/>的整個(gè)代碼引入,相當(dāng)于是拷貝到include位置,如:

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

<!-- header.wxml -->
<view> header </view>

<!-- footer.wxml -->
<view> footer </view>

WXSS

WXSS(WeiXin Style Sheets)是一套樣式語言,用于描述 WXML 的組件樣式。
WXSS 用來決定 WXML 的組件應(yīng)該怎么顯示。
與 CSS 相比我們擴(kuò)展的特性有:
1.尺寸單位
2.樣式導(dǎo)入

  • 尺寸單位 -- rpx(responsive pixel): 可以根據(jù)屏幕寬度進(jìn)行自適應(yīng)。規(guī)定屏幕寬為750rpx。如在 iPhone6 上,屏幕寬度為375px,共有750個(gè)物理像素,則750rpx = 375px = 750物理像素,1rpx = 0.5px = 1物理像素。
尺寸單位.png

<strong>建議: 開發(fā)微信小程序時(shí)設(shè)計(jì)師可以用 iPhone6 作為視覺稿的標(biāo)準(zhǔn)</strong>

  • 樣式導(dǎo)入 -- 使用@import語句可以導(dǎo)入外聯(lián)樣式表,@import后跟需要導(dǎo)入的外聯(lián)樣式表的相對(duì)路徑, 用;表示語句結(jié)束。
示例代碼:
/** common.wxss **/
.small-p {
  padding:5px;
}

/** app.wxss **/
@import "common.wxss";
.middle-p {
  padding:15px;
}

  • 內(nèi)聯(lián)樣式
    框架組件上支持使用 style、class 屬性來控制組件的樣式。
    1.style:靜態(tài)的樣式統(tǒng)一寫到 class 中。style 接收動(dòng)態(tài)的樣式,在運(yùn)行時(shí)會(huì)進(jìn)行解析,請(qǐng)盡量避免將靜態(tài)的樣式寫進(jìn) style 中,以免影響渲染速度。
    <view style="color:{{color}};" />
    2.class:用于指定樣式規(guī)則,其屬性值是樣式規(guī)則中類選擇器名(樣式類名)的集合,樣式類名不需要帶上.,樣式類名之間用空格分隔。
    <view class="normal_view" />

選擇器

  • 目前支持的選擇器有


    目前支持的選擇器.png
  • 全局樣式與局部樣式
    定義在 app.wxss 中的樣式為全局樣式,作用于每一個(gè)頁面。在 page 的 wxss 文件中定義的樣式為局部樣式,只作用在對(duì)應(yīng)的頁面,并會(huì)覆蓋 app.wxss 中相同的選擇器。
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容