微信小程式: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}
。
如果物件的 key
和value
相同,可以直接引用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:elif
和wx: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
會先後觸發handleTap1
和handleTap2
(因為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提供兩種檔案引用方式import
和include
。
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有作用域的概念,即只會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提供了一系列基礎元件,開發者可以通過組合這些基礎元件進行快速開發。