視圖層:Pages主要有 wxml頁面文件和模板文件、wxs腳本文件、wxss樣式文件;component是抽取出來的業務單元,同樣擁有wxml頁面文件和模板文件、wxs腳本文件、wxss樣式文件。
WXML(WeiXin Markup language) 用於描述頁面的結構。
WXS(WeiXin Script) 是小程序的一套腳本語言,結合 WXML
,可以構建出頁面的結構。
WXSS(WeiXin Style Sheet) 用於描述頁面的樣式。
組件(Component)是視圖的基本組成單元。
一:WXML:WXML(WeiXin Markup Language)是一套標簽語言,結合基礎組件、事件系統,可以構建出頁面的結構。
MVVM模式:
在網頁的一般開發流程中,我們通常會通過 JS 操作 DOM (對應 HTML 的描述產生的樹),以引起界面的一些變化響應用戶的行為。例如,用戶點擊某個按鈕的時候,JS 會記錄一些狀態變化到 JS 變量里邊,同時通過 DOM API 操控 DOM 的屬性或者行為,進而引起界面一些變化。
當項目越來越大的時候,你的代碼會充斥着非常多的界面交互邏輯和程序的各種狀態變量,顯然這不是一個很好的開發模式。
MVVM 的開發模式把渲染和邏輯分離:不讓 JS 直接操控 DOM,JS只需要管理狀態(數據)變化即可;然后再通過一種模板語法來描述狀態和界面結構的關系,將狀態(數據)變化實時更新到界面。
MVVM在微信小程序開發中的實現:通過數據綁定,將狀態(數據)在界面上顯示;通過 WXS腳本語言,根據狀態(數據)動態決定頁面結構。
通過 {{ }} 的語法把一個變量綁定到界面上,我們稱為數據綁定。僅僅通過數據綁定還不夠完整的描述狀態和界面的關系,還需要 if/else, for等控制能力,在小程序里邊,這些控制能力都用 wx: 開頭的wxs語法來表達。
1)數據綁定
簡單數據綁定:使用 Mustache 語法(雙大括號)將要綁定的變量包起來。數據在js文件中定義,在wxml文件中綁定。
Page({ data: { //定義數據 message: 'Hello world!' } })
<view> {{ message }} </view> //數據綁定到頁面
組件屬性綁定:wxml中組件的屬性值也可以通過數據綁定來賦值。
<view id="{{數據名}}"> </view>
條件語句值綁定:條件語句的值也可以通過數據綁定來賦值。
<view wx:if="{{condition}}"> </view>
Page({ data: { condition: true //條件語句的值 } })
關鍵字綁定:對於一些關鍵字、保留字,需要在 {{關鍵字}} 內才能起作用,如果只有雙引號、沒有雙括號,則只是作為一個字符串而已。
<checkbox checked="{{false}}"> </checkbox> //不要直接寫 checked="false",其計算結果是一個字符串,轉成 boolean 類型后代表真值。
運算結果綁定:可以在 {{表達式}} 內進行運算,將結果綁定到頁面。
運算支持: 三目運算:conditions ? val1 : val2 算術運算:+-*/ 比較運算:> < == 等 點運算符:對象.屬性 索引運算:數組對象[index] 組合成數組:{{[var...]}} 組合成對象:{{屬性1:值,屬性2:值,屬性3:值...}} 展開一個對象:{{...object}} //用 ... 運算符將對象展開成 鍵值對 的形式
【特別注意:花括號和引號之間如果有空格,將最終被解析成為字符串。】
2)wxs渲染控制語句
2.1)條件控制語句:
//條件語句是在view屬性中定義的,當條件成立時,該view就被繪制 <view wx:if="{{條件1}}"> 內容</view> <view wx:elif="{{條件2}}"> 內容</view> <view wx:else> 內容 </view>
如果要一次性判斷多個組件標簽,可以使用一個 <block/>
標簽將多個組件包裝起來,並在block標簽使用 wx:if
控制屬性:
<block wx:if="{{條件}}"> <view> view1 </view> <view> view2 </view> </block>
wx:if vs hidden
因為 wx:if 之中的模板也可能包含數據綁定,所有當 wx:if 的條件值切換時,框架有一個局部渲染的過程,因為它會確保條件塊在切換時銷毀或重新渲染。
同時 wx:if 也是惰性的,如果在初始渲染條件為 false,框架什么也不做,在條件第一次變成真的時候才開始局部渲染。
相比之下,hidden 就簡單的多,組件始終會被渲染,只是簡單的控制顯示與隱藏。
一般來說,wx:if 有更高的切換消耗而 hidden 有更高的初始渲染消耗。因此,如果需要頻繁切換的情景下,用 hidden 更好,如果在運行時條件不大可能改變則 wx:if 較好。
2.2)循環語句
組件上使用 wx:for
控制屬性綁定一個數組,即可使用數組中各項的數據重復渲染該組件。
//默認數組的當前項的下標變量名默認為 index,數組當前項的變量名默認為 item <view wx:for="{{array}}"> {{index}}: {{item}} </view>
也可以使用 wx:for-item
可以指定數組當前元素的變量名,使用 wx:for-index
可以指定數組當前下標的變量名:
<view wx:for="{{array}}" wx:for-index="idx" wx:for-item="itemName"> {{idx}}: {{itemName}} </view>
重復渲染多個組件,可以用一個block標簽把他們組成塊:
<block wx:for="{{array}}"> <view> {{index}}: </view> <view> {{item}} </view> </block>
優化:使用wx:key避免被重新繪制、丟失狀態。
如果view數組的view組件數量會動態增減或者view組件位置會動態變化,這些變化會引起view數組重新繪制,那么某個被重繪的view組件當前的狀態可能會丟失(如:input接收的輸入、switch開關的狀態)。
若想要保持住這些狀態數據,可以使用 wx:key 來避免組件被重繪。當數據改變觸發渲染層重新渲染的時候,會校正帶有 key 的組件,框架會確保他們被重新排序,而不是重新創建,以確保使組件保持自身的狀態,並且提高列表渲染時的效率。
wx:key 的值以兩種形式提供:
字符串:使用array中item 的某個屬性值,該屬性值需要是數組中唯一的字符串或數字,且不能動態改變。
保留關鍵字*this:使用item本身,這種表示需要 item 本身是一個唯一的字符串或者數字。
//使用 item 的屬性值作key <switch wx:for="{{objectArray}}" wx:key="unique" style="display: block;"> {{item.id}} </switch> objectArray: [ {id: 5, unique: 'unique_5'}, //每個item的unique屬性值均唯一 {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'}, ], //使用 *this 作為key <switch wx:for="{{numberArray}}" wx:key="*this" style="display: block;"> {{item}} </switch> numberArray: [1, 2, 3, 4]
3)WXML模版
對於可以在不同頁面出現的頁面結構,我們可以提取成為一個WXML模版,然后在不同的wxml文件引入這個模版並為模版傳具體值,就可以復用這個頁面結構了。
【注意區分:wxml模版是界面結構的重用;自定義組件則是功能結構的重用】
3.1)模版定義:
可以新建一個template目錄,專門用於存放wxml模版文件。模版文件也是wxml文件,以wxml為后綴名。模版部分界面結構用 template 括住:
//header.wxml 頁面頭部模版文件示例 <template name="header"> <view class="left"> 左邊內容 </view> <view class="center"> 中間內容 </view> <view class="right"> 右邊內容 </view> </template>
在模版文件中,也可以使用wxs語法進行組件的條件渲染、列表渲染。
3.2)使用模版
使用 is 屬性聲明需要的使用的模板,然后將模板所需要的 data 傳入。data的格式需要符合模板中數據綁定的格式(類型、變量名都要對應上)
<import src="模板文件相對路徑"/> //導入模板 <template is="模板名" data="{{模板需要的數據}}" /> //傳遞數據,適用模板
is 屬性可以使用 Mustache 語法,動態決定具體需要渲染哪個模板:
<template is="{{條件 ? '模版名1' : '模板名2'}}"/>
4)引用
WXML 提供兩種文件引用方式import
和include
。
4.1)import
可以在該文件中使用目標文件定義的template,上面模板使用已經示范過了。
4.2)include
可以將目標文件除了 <template/>
<wxs/>
外的整個代碼引入,相當於是拷貝到 include
位置。
5)視圖層事件
5.1)事件分為冒泡事件和非冒泡事件:
- 冒泡事件:當一個組件上的事件被觸發后,該事件會向父節點傳遞。
- 非冒泡事件:當一個組件上的事件被觸發后,該事件不會向父節點傳遞。
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 動畫完成時觸發 |
注:除上表之外的其他組件自定義事件如無特殊聲明都是非冒泡事件,如<form/>
的submit
事件,<input/>
的input
事件,<scroll-view/>
的scroll
事件。
5.2)事件的綁定
事件綁定的寫法同組件的屬性,以 key、value 的形式。
- key 以
bind
或catch
開頭,然后跟上事件的類型,如bindtap
、catchtouchstart
。bind
和catch
后可以緊跟一個冒號再跟事件類型,其含義不變,如bind:tap
、、catch:touchstart
。 - value 是一個字符串,需要在對應的 Page 中定義同名的事件處理函數。
bind
事件綁定不會阻止冒泡事件向上冒泡,catch
事件綁定可以阻止冒泡事件向上冒泡。
5.3)事件處理的流程
事件處理可以包括兩個階段:事件捕獲階段(從界面父節點向組件子節點傳遞,被捕獲)、事件處理階段(冒泡的事件會從組件子節點開始處理,逐層向父節點傳播,被處理【除非被catch阻止了】)
捕獲事件可以采用capture-bind
、capture-catch
關鍵字,后者將中斷捕獲階段和取消冒泡階段。
5.4)事件處理函數
當組件觸發事件時,邏輯層綁定該事件的處理函數會收到一個事件對象,根據事件類型的不同,事件對象攜帶的信息也不同。
BaseEvent 基礎事件對象屬性列表:
屬性 | 類型 | 說明 |
---|---|---|
type | String | 事件類型 |
timeStamp | Integer | 事件生成時的時間戳 |
target | Object | 觸發事件的組件的一些屬性值集合 |
currentTarget | Object | 當前組件的一些屬性值集合 |
CustomEvent 自定義事件對象屬性列表(繼承 BaseEvent):
屬性 | 類型 | 說明 |
---|---|---|
detail | Object | 額外的信息 |
TouchEvent 觸摸事件對象屬性列表(繼承 BaseEvent):
屬性 | 類型 | 說明 |
---|---|---|
touches | Array | 觸摸事件,當前停留在屏幕中的觸摸點信息的數組 |
changedTouches | Array | 觸摸事件,當前變化的觸摸點信息的數組 |
其中的幾個Object類型參數主要包含信息如下:
target:觸發事件的源組件。
屬性 | 類型 | 說明 |
---|---|---|
id | String | 事件源組件的id |
tagName | String | 當前組件的類型 |
dataset | Object | 事件源組件上由data- 開頭的自定義屬性組成的集合 |
currentTarget:事件綁定的當前組件。
屬性 | 類型 | 說明 |
---|---|---|
id | String | 當前組件的id |
tagName | String | 當前組件的類型 |
dataset | Object | 當前組件上由data- 開頭的自定義屬性組成的集合 |
Touch 對象
屬性 | 類型 | 說明 |
---|---|---|
identifier | Number | 觸摸點的標識符 |
pageX, pageY | Number | 距離文檔左上角的距離,文檔的左上角為原點 ,橫向為X軸,縱向為Y軸 |
clientX, clientY | Number | 距離頁面可顯示區域(屏幕除去導航條)左上角距離,橫向為X軸,縱向為Y軸 |
二:WXS:WXS(WeiXin Script)是小程序的一套腳本語言,結合 WXML
,可以構建出頁面的結構。
【wxs 的運行環境和其他 javascript 代碼是隔離的,wxs 中不能調用其他 javascript 文件中定義的函數,也不能調用小程序提供的API。】
WXS 代碼可以編寫在 wxml 文件中的 <wxs>
標簽內,或以 .wxs
為后綴名的文件內。
2.1)模塊
每一個 .wxs
文件和 <wxs>
標簽都是一個單獨的模塊,一個模塊要想對外暴露其內部的私有變量與函數,只能通過 module.exports
實現。
2.2)WXS文件中定義module
每個 wxs
模塊均有一個內置的 module
對象,用於導出模塊內數據與函數。
var ref = require("./ref.wxs"); //引用其他wxs模塊
var foo = 定義變量;
var bar = function (param) {
ref.var; //調用引用模塊的變量
ref.func();//調用引用模塊的函數
方法體;
}
module.exports = { //導出變量、函數,並且指明導出名(用於調用)
FOO: foo,
bar: bar,
};
在wxml中使用wxs模塊文件:
<wxs src="./../ref.wxs" module="ref" /> //定義module標簽,創建一個module;並且通過src屬性指明module的定義源文件路徑 <view> {{ref.var}} </view> //通過module名調用數據、函數 <view> {{ref.func(param)}} </view>
2.3)wxs標簽中定義module
module 屬性是當前 <wxs>
標簽的模塊名。
<wxs module="模塊名"> //1:通過 wxs 標簽創建模塊 var 變量 =值; //2:在模塊內定義變量、函數 module.exports = { 導出名 : 變量, //3:導出模塊內容 } </wxs> <view> {{模塊名.變量/函數}} </view> //4:調用模塊內容
<wxs>
模塊只能在定義模塊的 WXML 文件中被訪問到。使用<include>
或<import>
時,<wxs>
模塊不會被引入到對應的 WXML 文件中。<template>
標簽中,只能使用定義該<template>
的 WXML 文件中定義的<wxs>
模塊。
2.4)語句
if語句:
// if ...
if (表達式) 語句;
if (表達式)
語句;
if (表達式) {
代碼塊;
}
// if ... else
if (表達式) 語句;
else 語句;
if (表達式)
語句;
else
語句;
if (表達式) {
代碼塊;
} else {
代碼塊;
}
// if ... else if ... else ...
if (表達式) {
代碼塊;
} else if (表達式) {
代碼塊;
} else if (表達式) {
代碼塊;
} else {
代碼塊;
}
switch語句:
switch (表達式) {
case 變量:
語句;
case 數字:
語句;
break;
case 字符串:
語句;
default:
語句;
}
for語句:
for (語句; 語句; 語句)
語句;
for (語句; 語句; 語句) {
代碼塊;
}
while語句:
while (表達式)
語句;
while (表達式){
代碼塊;
}
do {
代碼塊;
} while (表達式)
2.5)數據類型
number : 數值
string :字符串
boolean:布爾值
object:對象(無序鍵值對,用 {} 來定義)
function:函數
array : 數組
date:日期
regexp:正則
//函數的兩種定義方式
function a (x) {
return x;
}
//方法 2
var b = function (x) {
return x;
}
2.6)基礎類庫
console類庫:控制台類庫,可以調用log方法打印信息。
Math類庫:數學常量、函數。
Json類庫:Json與字符串互相轉換。
Number類庫:最大最小數字常量。
Date類庫:日期相關。
Global類庫:類型轉換函數、判斷有效值等。
三:WXSS樣式文件
3.1)選擇器
.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 組件前邊插入內容
3.2)定義wxss文件
選擇器 { 樣式定義(鍵值對); ... }
3.3)wxml文件中使用樣式【小程序根據 同名 規則,將同名的 wxml、wxss、js文件自動引用,無需導入,只需使用相關名稱來調用即可】
<view style="樣式屬性定義;" />
<view class="某種已經定義好樣式的類選擇器" />
3.4)wxss文件之間的引用
我們在定義某個wxss文件時,如果某些樣式已經在別處定義過,那么可以將別處的樣式導入進來,無需重復定義。
使用@import
語句可以導入外聯樣式表,@import
后跟需要導入的外聯樣式表的相對路徑,用;
表示語句結束。
@import "./../路徑/名字.wxss";