1. 程式人生 > >微信小程式:MINA檢視層

微信小程式:MINA檢視層

一、WXML

WXML(WeiXin Markup Language)是MINA設計的一套標籤語言,結合基礎元件、事件系統,可以構建出頁面的結構。
WXML具備資料繫結、列表渲染、條件渲染、模板、事件、引用等能力,下面逐一進行詳細介紹。

資料繫結
簡單繫結

資料繫結使用“Mustache”語法(雙大括號)將變數包起來,可以作用於:
內容
<view> {{ message }} </view>

Page({
  data: {
    message: 'Hello MINA!'
  }
})

元件屬性(需要在雙引號之內)
<view id="item-{{id}}"> </view>

Page({
  data: {
    id: 0
  }
})

控制屬性(需要在雙引號之內)
<view wx:if="{{condition}}"> </view>

Page({
  data: {
    condition: true
  }
})
運算

可以在{{}}內進行簡單的運算,支援的有如下幾種方式:
三元運算
<view hidden="{{flag ? true : false}}"> Hidden </view>
算數運算
<view> {{a + b}} + {{c}} + d </view>

Page({
  data: {
    a: 1
, b: 2, c: 3 } })

邏輯判斷
<view wx:if="{{length > 5}}"> </view>
字串運算
<view>{{"hello" + name}}</view>

Page({
  data:{
    name:"MINA"
  }
})
組合

也可以在Mustache內直接進行組合,構成新的物件或者陣列。
陣列
<view wx:for-items="{{[zero, 1, 2, 3, 4]}}"> {{item}} </view>

Page({
  data: {
    zero: 0
} })

物件
<template is="objectCombine" data="{{for: a, bar: b}}"></template>

Page({
  data: {
    a: 1,
    b: 2
  }
})

...展開物件,再構成新的物件
<template is="objectCombine" data="{{...obj1, ...obj2, e: 5}}"></template>

Page({
  data: {
    obj1: {
      a: 1,
      b: 2
    },
   obj2: {
      c: 3,
      d: 4
    }
  }
})

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

如果物件的 keyvalue相同,可以直接引用key

<template is="objectCombine" data="{{foo, bar}}"></template>

template是模板,is="objectCombine"是指拼接物件的模板,下文會有模板的詳細介紹。

Page({
  data: {
     foo: 'my-foo',
    bar: 'my-bar'
  }
})

注意:上述方式可以隨意組合,但是如有存在變數名相同的情況,後邊的會覆蓋前面,不會添加出新的變數。
<template is="objectCombine" data="{{...obj1, ...obj2, a, c: 6}}"></template>

Page({
  data: {
    obj1: {
      a: 1,
      b: 2
    },
    obj2: {
      b: 3,
    c: 4
    },
    a: 5
  }
})

最終組合成的物件是{a: 5, b: 3, c: 6}

條件渲染
wx:if

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

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

也可以用wx:elifwx:else來新增一個else塊:

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

block wx:if
條件渲染多個元件標籤時,使用<block/>進行包裝,對block新增wx:if控制屬性即可

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

注意:<block/>並不是元件,只是一個包裝元素,不會在頁面進行渲染,並且只接受控制屬性。(ps:這麼屌的元素應該多擴充套件一下)

wx:if vs hidden

因為wx:if之中的模板也可能包含資料繫結,所有當wx:if的條件值切換時,MINA有一個區域性渲染的過程,因為它會確保條件塊在切換時銷燬或重新渲染。
同時wx:if也是惰性的,如果在初始渲染條件為false,MINA什麼也不做,在條件第一次變成真的時候才開始區域性渲染。
相比之下,hidden就簡單的多,元件始終會被渲染,只是簡單的控制顯示與隱藏。
一般來說,wx:if有更高的切換消耗而hidden有更高的初始渲染消耗。因此,如果需要頻繁切換的情景下,用hidden更好,如果在執行時條件不大可能改變則wx:if較好。
(ps:頻繁顯隱用hidden,極少改變用wx:if。)

列表渲染
wx:for

在元件上使用wx:for控制屬性繫結一個數組,即可使用陣列中各項的資料重複渲染該元件。
預設陣列的當前項的下標變數名預設為index,陣列當前項的變數名預設為item。(下標:index,值:item)

<view wx:for="{{items}}">
  {{index}}: {{item.message}}
</view>

資料:

Page({
  items: [{
    message: 'foo',
  },{
    message: 'bar'
  }]
})

更改陣列當前項變數名/下標名: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>

block wx:for
block wx:if一樣,wx:for也是控制屬性,所以可以用在<block/>標籤上,來渲染一個包含多節點的結構塊。

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

模板(template)可以在模板中定義程式碼片段,然後在不同的地方呼叫。

定義模板

使用name屬性作為模板名字,在<template/>內定義程式碼片段

<!--
  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-26'
    }
  }
})

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傳入的資料。

事件

事件是檢視層與邏輯層通訊的方式,將使用者行為傳達到邏輯層。事件繫結在元件上,當事件觸發時會執行邏輯層的事件處理函式,事件物件可以攜帶額外資訊,如id, dataset, touches。

事件的使用方式
  • 元件繫結事件處理函式

    <view id="tapTest" data-hi="MINA" bindtap="tapName"> Click me! </view>
  • 在相應的Page定義中寫上相應的事件處理函式,引數是event

    Page({
      tapName: function(event) {
        console.log(event)
      }
    })
  • log資訊

    {
    "type": "tap",
    "timeStamp": 1252,
    "target": {
      "id": "tapTest",
      "offsetLeft": 0,
      "offsetTop": 0,
      "dataset": {
       "hi": "MINA"
      }
    },
    "currentTarget": {
      "id": "tapTest",
      "offsetLeft": 0,
      "offsetTop": 0,
      "dataset": {
        "hi": "MINA"
      }
    },
    "touches": [{
      "pageX": 30,
      "pageY": 12,
      "clientX": 30,
      "clientY": 12,
      "screenX": 112,
      "screenY": 151
    }],
    "detail": {
      "x": 30,
      "y": 12
    }
    }
事件分類

事件分為冒泡事件非冒泡事件
冒泡事件:當一個元件上的事件被觸發後,該事件會向父節點傳遞。(子節點響應一次事件,父節點還會響應一次,直到根節點響應完成,所以有時候必須阻止事件冒泡)
非冒泡事件:當一個元件上的事件被觸發後,該事件不會向父節點傳遞。
WXML的冒泡事件列表:

型別 觸發條件
touchstart 手指觸控
touchmove 手指觸控後移動
touchcancel 手指觸控動作被打斷,如來電提醒,彈窗
touchend 手指觸控動作結束
tap 手指觸控後離開
longtap 手指觸控後,超過350ms再離開

注:除上表之外的其他元件自定義事件都是非冒泡事件,如<form/>的submit事件,<input/>的input事件,<scroll-view/>的scroll事件(後續會更新元件部分)。

事件繫結

繫結事件是以屬性的方式,key、value:

  • key以bind或catch開頭,然後跟上事件的型別,如bind tap, catchtouchstart
  • value是一個字串,需要在對應的Page中定義同名的函式。不然當觸發事件的時候會報錯。

bind不會阻止冒泡事件向上冒泡,catch會阻止冒泡事件向上冒泡。

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

上面例子中,點選 inner view會先後觸發handleTap1handleTap2(因為tap事件會冒泡到middle view,而middle view阻止了tap事件冒泡,不再向父節點傳遞),點選middle view會觸發handleTap2,點選ouster view會觸發handleTap1

事件物件

當元件觸發事件時,邏輯層繫結該事件的處理函式會收到一個事件物件(特殊說明除外)。
事件物件屬性列表:

屬性 型別 說明
type String 事件型別(如tap、longtap、touchstart等)
timeStamp Integer 事件生成時的時間戳(頁面開啟到觸發事件所經過的毫秒數)
target Object 觸發事件的元件的一些屬性值集合
currentTarget Object 當前元件的一些屬性值集合
touches Array 觸控事件,觸控點資訊的陣列
detail Object 額外的資訊,特殊事件所攜帶的資料,如單元件的提交事件會攜帶使用者的輸入,媒體的錯誤事件會攜帶錯誤資訊
target、currentTarget屬性列表
屬性 說明
id 事件源元件的id
dataset 事件源元件上由data-開頭的自定義屬性組成的集合
offsetLeft, offsetTop 事件源元件的座標系統中偏移量
dataset:

在元件中可以定義資料,這些資料將會通過事件傳遞給SERVICE。 書寫方式: 以data-開頭,多個單詞由連字元-連結,不能有大寫(大寫會自動轉成小寫)如data-element-type,最終在event.target.dataset中會將連字元轉成駝峰elementType

示例:

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

page:

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

touches是一個觸控點的陣列,每個觸控點的屬性如下:

屬性 說明
pageX,pageY 距離文件左上角的距離,文件的左上角為原點 ,橫向為X軸,縱向為Y軸
clientX,clientY 距離頁面可顯示區域(螢幕除去導航條)左上角距離,橫向為X軸,縱向為Y軸
screenX,screenY 距離螢幕左上角的距離,螢幕左上角為原點,橫向為X軸,縱向為Y軸
引用

WXML提供兩種檔案引用方式importinclude

import

import在該檔案中使用目標檔案定義的template,在item.wxml中定義了一個叫itemtemplate

<!-- 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有作用域的概念,即只會import目標檔案中定義的template,而不會import目標檔案import的template。

include

include可以將目標檔案除了<template/>的整個程式碼引入,相當於拷貝到include位置,如:

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

header.wxml:

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

footer.wxml

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

二、WXSS

WXSS(WeiXin Style Sheets)是MINA設計的一套樣式語言,用於描述WXML的元件樣式。
WXSS用來決定WXML的元件應該怎麼顯示。
WXSS不僅具有CSS大部分特性,還同時為了更適合開發微信小程式,對CSS進行了擴充以及修改。
與css相比我們擴充套件的特性有:尺寸單位樣式匯入

尺寸單位

rpx(responsive pixel): 可以根據螢幕寬度進行自適應。規定螢幕寬為750rpx。如在iPhone6上,螢幕寬度為375px,共有750個物理畫素,則750rpx = 375px = 750物理畫素,1rpx = 0.5px = 1物理畫素。

裝置 rpx換算px(螢幕寬度/750) px換算rpx(750/螢幕寬度)
iPhone5 1rpx = 0.42px 1px = 2.34px
iPhone6 1rpx = 0.5px 1px = 2rpx
iPhone6 Plus 1rpx = 0.552px 1px = 1.81rpx

注:rem(root em): 規定螢幕寬度為20rem;1rem = (750/20)rpm 。
建議:開發微信小程式時設計師可以用iPhone6作為視覺稿標準。

樣式匯入

外聯樣式

使用@import語句可以匯入外聯樣式表,@import後跟需要匯入的外聯樣式表的相對路徑,用;表示語句結束。

/** common.wxss **/
.small-p{
  padding:5px;
}

引入:

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

內聯樣式

MINA元件上支援使用style、class屬性來控制組件的樣式。

  • style:靜態的樣式統一寫到class中。style接收動態的樣式,在執行時會進行解析,所以不要將靜態的樣式寫進style中,以免影響渲染速度。

    <view style="color:{{color}};" />
  • class:用於指定樣式規則,其屬性值是樣式規則中類選擇器名(樣式類名)的集合,樣式類名不需要帶上.,樣式類名之間用空格分隔。

    <view class="normal_view" />

    選擇器

選擇器 樣例 樣例描述
.class .intro 選擇所有擁有class="intro"的元件
#id #firstname 選擇擁有id="firstname"的元件
element view 選擇所有view元件
element, element view checkbox 選擇所有文件的view元件和所有的checkbox元件
::after view::after 在view元件後邊插入內容
::before view::before 在view元件前邊插入內容

全域性樣式與區域性樣式

定義在app.wxss中的樣式為全域性樣式,作用於每一個頁面。在page的wxss檔案中定義的樣式為區域性樣式,只作用在對應的頁面,並會覆蓋app.wxss中相同的選擇器。

三、元件

MINA提供了一系列基礎元件,開發者可以通過組合這些基礎元件進行快速開發。