前言
微信小程序的火爆相信不用多說,作爲一個前端,小程序幾乎可以算得上是前端技能的一個加分項,如果找工作的時候會小程序,那麼相對而言會有很多優勢;
簡介
官方解釋:小程序是一種全新的連接用戶與服務的方式,它可以在微信內被便捷地獲取和傳播,同時具有出色的使用體驗。簡單的說,小程序就像是微信的一個功能插件,這個功能插件可以無縫的接入微信,讓用戶在微信中使用小程序時獲得接近原生app的體驗;
官方地址:小程序開發者文檔,通過閱讀簡介,對於小程序其實可以理解成,微信爲了更好的爲用戶提供使用體驗,它對JavaScript進行了再一次的封裝,並且制定了許多api供開發者使用,雖然經過封裝,但是開發語言的本質是JavaScript改變不了,因此,對前端開發者而言學習成本最小;
注意的是,小程序的開發環境和網頁開發環境是有區別的,雖然兩者幾乎一樣,但是還是有一些區別,比如jQuery等前端庫沒有辦法使用,環境也於Node.js不盡相同,因此有一些NPM的包也無法運行;
創建
小程序不是跟web項目那種雖然本地創建的,需要到官網進行註冊,開發者工具也是由微信官方提供(開發者工具下載),註冊過程就不說了,我第一次註冊的時候還是比較順利的,值的說一下的就是,每個有些只能申請一個小程序,當註冊成功之後,在菜單欄“開發” -> “開發設置” -> 可以看到一個屬性,叫做AppID(小程序ID),這個很重要,記得保存到本地,小程序的AppID相當於身份證;
之後,打開安裝完畢的開發者工具,掃碼登錄,如果是多人協同項目,那麼需要在小程序後臺(也就是上面註冊後獲取AppID的那個後臺),在開發人員中添加多人微信號就可以了;之後新建一個小程序項目還是導入小程序項目都隨用戶選擇;
關於開發者工具的具體介紹,可以看一下官方文檔,還是很有必要的:開發者工具介紹;如果需要預覽項目,那麼點擊開發者工具上面的“預覽”按鈕,就可以掃碼預覽;
完成之後,可以看到一個類似於下例的界面:
目錄結構
要開發項目,那麼肯定得先了解小程序的目錄結構,所以請先看下以下示例,這是一個新建項目後的基本目錄:
以app開頭的三個文件,是這個小程序的全局文件,可以這麼理解,這個三個文件會運行在小程序啓動之後,在用戶看到頁面之前的這段時間內,小程序根據這三個配置文件決定該讓用戶先看到哪個頁面,看到頁面前是否需要進行某些特定的操作,是不是需要有tab欄等等問題:
- app.js:全局小程序邏輯文件,這個文件裏寫的代碼是會影響到整個小程序的,該文件是必須的,不能沒有,每一次小程序打開都會讀取這個文件內的邏輯;
- app.json:全局小程序公共配置文件,決定頁面文件的路徑、窗口表現、設置網絡超時時間、設置多 tab 等。完整配置項說明請參考小程序全局配置,這個文件也是必須的,不能沒有;
- app.wxss:全局的公共樣式表,這個不是必須的,因爲如果不怕麻煩,所有相同的樣式都寫在頁面內部的wxss文件裏,也不是不可以;
頁面是寫在pages這個文件夾裏面的,下面每一個文件夾都是一個頁面,每個頁面裏都包含了: .js文件, .json文件, .wxml文件, .wxss文件;
- .js: 該頁面的頁面邏輯,這個文件裏的邏輯只針對當前頁面,不會影響到別的頁面;
- .json:該文件的頁面配置文件,影響範圍也僅限當前頁面;
- .wxml:該頁面的佈局文件,相當於html文件,描述的是頁面的結構;
- .wxss:該頁面的樣式表,相當於css,描述的是當前頁面的樣式;
文件構成
通過上一節知道,小程序的每個頁面基本是由: .js文件, .json文件, .wxml文件, .wxss文件,這些文件構成;
json 文件
json是一種數據格式,並不是編程語言,在小程序中扮演靜態配置角色,相當於告訴小程序,我需要配置這些指定的東西,比如每次打開小程序,首先需要顯示的頁面是page/index/index這個頁面,比如所有小程序頁面中的導航欄都是黑色的,字體顏色是白色的;
小程序中有三種json文件,分別是:項目的根目錄有一個 app.json 和 project.config.json,以及每個頁面文件夾下的json文件(比如上圖中的logs文件夾下的logs.json);
app.json 小程序配置
是當前小程序的全局配置,包括了小程序的所有頁面路徑、界面表現、網絡超時時間、底部 tab 等。默認的配置內容大致如下:
{
"pages":[
"pages/index/index",
"pages/logs/logs"
],
"window":{
"backgroundTextStyle":"light",
"navigationBarBackgroundColor": "#fff",
"navigationBarTitleText": "WeChat",
"navigationBarTextStyle":"black"
}
}
- pages屬性是告訴小程序所有的頁面路徑,其中第一個值是打開小程序時,默認顯示的頁面,如果將上例中的logs移動到第一個,那麼打開小程序時首先顯示的界面就是logs中的頁面,不再是index;
- window是定義小程序中所有頁面的頂部背景色,文字顏色等等;
其他配置項細節可以參考文檔 小程序的配置 app.json ;
project.config.json 工具配置
這個配置文件是針對開發者的,因爲每個開發者都會有一點屬於自己個性的東西,此時如果換一臺電腦,那麼這些配置就需要重新配置,因此,小程序通過這個文件將配置好的備份,換電腦的時候不再需要重新配置,開發者工具會自動根據這個文件將個性化配置恢復到設定的狀態;
page.json 頁面配置
這個page.json代表的是每個頁面文件夾下的json文件,比如上圖中的logs.json,index.json等,在app.json中定義的配置是全局的配置,比如所有頁面的導航都是黑色;
但實際項目中不可能是這樣的,設計師不會給你一套設計,所有的導航都是白色,肯定是有的頁面是白色的,有的頁面是主色的,因此,在當前頁面有一些特殊的配置需要覆蓋全局配置時,那麼就可以在這個當前的配置文件中配置,在這裏配置的信息的優先級會高於全局配置,因此等到加載頁面的時候會將這個裏面的配置信息爲優先;
WXML 文件
WXML文件,可以和HTML的關係劃約等於,但相比之下可能和vue中的vue文件更加類似,微信將常用的一些標籤,功能進行了封裝,變成了組件,等到使用的時候直接調用就可以了,而數組的使用則使用雙花括號的方式進行綁定,沒錯和vue中的使用方式一樣,因此,如果你很熟悉vue,那麼對小程序的入門可以非常快
<view class="container">
<view class="userinfo">
<button wx:if="{{!hasUserInfo && canIUse}}"> 獲取頭像暱稱 </button>
<block wx:else>
<image src="{{userInfo.avatarUrl}}" background-size="cover"></image>
<text class="userinfo-nickname">{{userInfo.nickName}}</text>
</block>
</view>
<view class="usermotto">
<text class="user-motto">{{motto}}</text>
</view>
</view>
這是一個官網的例子,簡單分析一下,上面有view,button這些微信封裝的組件,使用方式和html幾乎一致,區別在於,在html中是通過div,header,footer這些標籤進行佈局的,在小程序中則不是,通通使用view進行佈局,嗯,沒錯,這個view相當於H5之前頁面佈局的div標籤;
標籤上有 wx:if 這樣的屬性,這個相當於vue中的v-if,所以小程序其實也是MVVM的開發模式,與vue不同的是,vue中的指令是通過v-來表達的,而在微信小程序中的指令是通過wx:開頭表達的;
WXSS 樣式
WXSS樣式基本等同於CSS,區別在於:
- 新增了尺寸單位rpx,通過使用這個單位,在不同屏幕上的換算交給小程序即可,不再需要自己去做適配;
- 同樣WXSS也有全局樣式和局部樣式,同樣的,相同的部分佈局的WXSS樣式會覆蓋全局樣式;
- 對於CSS選擇器,WXSS僅支持部分,比如後臺選擇器,兄弟選擇器等是不支持的,具體請看這篇更詳細的文檔 WXSS ;
rpx是微信小程序官方提供的一個單位,這是一個會自適應屏幕的單位,寬度100%的時候是750rpx,通過這個可以幫助我們更好的佈局頁面(沒辦法安卓的屏幕類型實在是多)
JS 邏輯交互
JS交互部分就是前端開發人員的JavaScript,使用方式基本是一致的,區別在於事件的名字可能不大一樣,當然本質上是沒有什麼區別,其作用就是和用戶做交互,比如:響應用戶的點擊、獲取用戶的位置等等,下面是一個示例,點擊事件:
<view>{{ msg }}</view>
<button bindtap="clickMe">點擊我</button>
通過點擊按鈕,希望將msg的值顯示成Hello World,於是聲明瞭一個bindtap屬性,其值是一個函數,這個屬性代表單擊後會觸發後面綁定的函數
Page({
clickMe: function() {
this.setData({ msg: "Hello World" })
}
})
其實可以這麼理解,這個button不是我們html中的button,原生的button上的功能太少,達不到實際開發中的需求,爲了提高效率,微信中會將這些常用的標籤都進行一次封裝,大大的減少了耗時,換句話說,這裏的button實際上類似於Vue的組件,上面的屬性bindtap,其實是上傳到父組件上的一個屬性,這個屬性對應的函數會傳遞到組件內部的click事件中;
具體的事件相關請看參考文檔 WXML - 事件;
數據綁定
小程序中的數據綁定採用也是“Mustache”語法,也就是雙花括號,在雙花括號內,可以進行簡單的運算,比如:三元運算,算數運算,邏輯判斷,字符串運算等等,也就是說,在雙花括號內的運算,小程序會進行元算,之後將結果呈現出來;
微信頁面上的數據都是存儲在js文件Page中的data方法中的,類似於vue中的數據也是存儲在js部分的data中的,因此,比如:
//index.wxml文件中用雙花括號引入變量message
<view class='body-main'>
{{message}}
</view>
//在index.js文件中的data屬性中定義變量message並賦值
Page({
/**
* 頁面的初始數據
*/
data: {
message: "你好"
},
})
這時候,就可以在左側的界面上顯示對應的文字“你好”,同理如果是,獲取數組,或者對象,獲取方式也一樣:
//index.wxml文件中用雙花括號引入變量message
<view class='body-main'>
{{person.age}}{{list[0]}}
</view>
//在index.js文件中的data屬性中定義變量message並賦值
Page({
/**
* 頁面的初始數據
*/
data: {
person:{
age:18
},
list:["你好"]
},
})
另外小程序的變量是可以直接在屬性上使用的,比如有一個標籤,上面有id屬性,id屬性的某一部分是data中的變量,同樣也是在需要的地方使用雙花括號引入
//index.wxml
<view class='body-main'>
{{message}}
<ul>
<li id="id-{{id}}"></li>
</ul>
</view>
//index.js
Page({
/**
* 頁面的初始數據
*/
data: {
message: "你好",
id:"item"
},
})
同樣,雙花括號的寫法也可以寫在指令裏面,比如:
//index.wxml
//指令wx:if這些個是渲染條件,具體看下一節,這裏看個大概就好
<view wx:if="{{code===1}}">{{message}}1</view>
<view wx:elif="{{code===2}}">{{message}}2</view>
<view wx:else>{{message}}3</view>
//index.js
Page({
/**
* 頁面的初始數據
*/
data: {
code:1
},
})
這樣,如果code的值爲1,那麼第一個view後面的值就是ture,那麼此時頁面上就會渲染第一個view,剩下的就不再執行,同理code爲2的時候,只有第二個後面是true,那麼只會渲染第二個view;
數據渲染
列表渲染
小程序中的列表渲染使用的指令是:wx:for,用法幾乎和vue中的一樣,先看個例子:假設現在從服務器請求到了一個數組,數組中每一項都是一個對象,其中有一個id值,需要綁定在列表上的每個id屬性,並且將值打印出來
<!--index.wxml-->
<ul>
<li wx:for="{{array}}" id="id-{{item.id}}">{{item.id}}-{{index}}</li>
</ul>
//index.js
Page({
data: {
array:[
{
id:"item1"
},
{
id:"item2"
},
{
id:"item3"
}
]
}
})
通過雙花括號,可以將data中的數組array獲取到,之後通過wx:for的指令,將數組進行遍歷,之後變量item代表對應的每一項,index對應每一項的下標值;
注意的是,爲了保證列表改變時,每一項都可以被小程序內部追蹤到,因此需要綁定一個key值,比如上例,將id值綁定給key
<!--index.wxml-->
<ul>
<li wx:for="{{array}}" id="id-{{item.id}}" wx:key="id">{{item.id}}-{{index}}</li>
</ul>
key的綁定不需要雙花括號,也不需要item.之類的操作,其中的的變量都是每一項對象內的的鍵值;另外,假設獲得的數組,每一項就是一個數字或者字符串,此時沒有對應的屬性名,那麼可以使用保留字this,這個this就是每一項本身,比如:
<!--index.wxml-->
<ul>
<li wx:for="{{array}}" wx:key="*this">{{item}}</li>
</ul>
//index.js
Page({
data: {
array:[1, 2, 3]
}
})
條件渲染
小程序中的條件渲染使用的指令是wx:if,wx:elif,wx:else,用法和vue基本一致,看個示例:
//指令wx:if
<view wx:if="{{code===1}}">{{message}}1</view>
<view wx:elif="{{code===2}}">{{message}}2</view>
<view wx:else>{{message}}3</view>
//index.js
Page({
/**
* 頁面的初始數據
*/
data: {
code:1
},
})
wx:if將判斷=號後面的值是否爲true,只有值爲true的時候纔會渲染對應的部分,注意的是wx:if是真的渲染不渲染,假如爲false,那麼該部分是不會被渲染進DOM樹的,如果要使用的是類似於v-show這種渲染進dom樹,但是不顯示,則使用指令:hidden
<view hidden="{{code===1}}">{{message}}1</view>
此時的view不管hidden後面的是true還是false,都會將該部分渲染進DOM中,只是true的時候是顯示的,false的時候是隱藏的;
如果在項目中的某一部分是需要經常的切換顯示隱藏,那麼使用hidden比較好,如果不是太頻繁,那麼使用wx:if比較好;
模版
模版,template,可以理解成一段可重複使用的代碼片段,這些代碼片段只需要定義一次,就可以不斷的重複使用,比如:
//index.wxml
<template name="staffName">
<view>
FirstName: {{firstName}}, LastName: {{lastName}}
</view>
</template>
通過template定義了一個模版,並且給這個模版命名了一個名字staffName,使用的使用只需要通過名字就可以指定需要使用哪個模版了
//index.wxml
<template is="staffName" data="{{...person}}"></template>
<template is="staffName" data="{{...person}}"></template>
<template is="staffName" data="{{...person}}"></template>
//index.js
Page({
data: {
person:{
name:"oliver",
age:18
}
}
})
這裏模版被使用了3次,通過is屬性,指定要使用模版的名字,通過data屬性注入數據,當然,模版的名字也是支持雙花括號語法的,比如
<template name="{{name}}">
<view>
FirstName: {{firstName}}, LastName: {{lastName}}
</view>
</template>
通常,如果項目中有好些相同的佈局,那麼就可以考慮抽離出來,單獨存放,然後項目中往往是組合使用,比如使用的時候通過條件渲染模版,當獲取到的狀態是1的時候渲染的是模版1,如果狀態是2的時候渲染的是模版2等等;
這裏又出現了一個新問題,如果模版在頁面a中,那麼在這麼在頁面b中也使用這個模版?答案是通過import或include引入;
引用
import
//在demo1.wxml中定義了一個template
//當然demo1.wxml中肯定還有很多其他代碼,但是模版和其他代碼不衝突
<template name="itemTest">
{{age}}-{{name}}
</template>
//在demo2.wxml引入,src後面跟隨着的是需要引入的文件的路徑
<import src="item.wxml"/>
<template is="item" data="{{person}}"/>
import 有作用域的概念,即只會 import 目標文件中定義的 template,而不會 import 目標文件 import 的 template,舉個例子:C import B,B import A,在C中可以使用B定義的template,在B中可以使用A定義的template,但是C不能使用A定義的template;
**
include
和import不同,import會引入目標文件中的template,而include則是會引入 、外的所有代碼,也就是說,會將整個頁面都拷貝過來了;
比如現在所有的頁面都需要使用相同的header和相同的footer,那麼就可以將header和footer單獨寫一個文件,其他所有頁面都使用include引入
<!-- index.wxml -->
<include src="header.wxml"/>
<view> body </view>
<include src="footer.wxml"/>
<!-- header.wxml -->
<view> header </view>
<!-- footer.wxml -->
<view> footer </view>
WXS語法
WXS是小程序的一套腳本語言,它的語法和JavaScript不完全一致,WXS代碼可以編寫在wxml的標籤中,也可以寫在以.wxs爲後綴的文件內;
爲什麼要有WXS,作用上看它和JavaScript幾乎一致,官網上寫到:由於運行環境的差異,在 iOS 設備上小程序內的 WXS 會比 JavaScript 代碼快 2 ~ 20 倍。在 android 設備上二者運行效率無差異。這個速度差異其實很明顯,尤其是項目比較大的時候;
每個.wxs文件和標籤都是一個獨立的模塊;都有其自己獨立的作用域,每一個模塊內的變量與函數,默認都是私有的,這就代表如果要被其他模塊使用,必須通過module.exports實現,看個例子
<!--wxml-->
<wxs module="m1">
var msg = "hello world";
module.exports.message = msg;
</wxs>
<view> {{m1.message}} </view>
這個是一個頁面渲染的例子,基本上就是如果要使用wxs內的變量,必須通過module.exports導出,否則就無法識別,再看一個數據處理的例子:
// index.js
Page({
data: {
array: [1, 2, 3, 4, 5, 1, 2, 3, 4]
}
})
//index.wxml
<!-- 下面的 getMax 函數,接受一個數組,且返回數組中最大的元素的值 -->
<wxs module="m1">
var getMax = function(array) {
var max = undefined;
for (var i = 0; i < array.length; ++i) {
max = max === undefined ?
array[i] :
(max >= array[i] ? max : array[i]);
}
return max;
}
module.exports.getMax = getMax;
</wxs>
// 調用 wxs 裏面的 getMax 函數,參數爲 index.js 裏面的 array
<view> {{m1.getMax(array)}} </view>
同樣,如果是新建了一個wxs文件
var name = "我的名字是Oliver";
var bar = function(d){
return d;
}
module.exports = {
name:name,
func:bar
}
那麼在wxml文件中需要先指明路徑,比如:
//wxml文件
//通過src屬性引入wxs文件,然後通過module命名模塊
<wxs src="./indexDemo.wxs" module="m2"></wxs>
<span>{{m2.name}}</span>
<span>{{m2.func("大家好")}}</span>
另外,如果現在有兩個wxs文件,分別爲a.wxs和b.wxs,如果要在b.wxs中引用a.wxs,那麼可以通過require引入,比如:
//a.wxs
var foo = "'hello world' from tools.wxs";
var bar = function (d) {
return d;
}
module.exports = {
FOO: foo,
bar: bar,
};
module.exports.msg = "some msg";
//b.wxs
var tools = require("./a.wxs");
console.log(tools.FOO);
console.log(tools.bar("logic.wxs"));
console.log(tools.msg);
注意的是,require後面的路徑必須是相對路徑,另外如果多個wxs文件的module重名了,那麼寫在後面的將覆蓋前面的;
事件系統
小程序的事件系統和JS的事件系統的用法基本是一致的,區別在於事件名不一樣,因此具體的事件相關請看參考文檔 WXML - 事件;
先看個簡單的例子:
<view bindtap="tapName"> Click me! </view>
//錯誤示例
<view bindtap="tapName("oliver")"> Click me! </view>
這種傳遞參數是錯誤的,微信小程序不支持這種方式傳遞參數
這裏view標籤上通過bindtap綁定了一個tapName事件,作用是當用戶點擊到當前這個view時就會觸發tapName函數,而tapName函數則寫在對應的js文件中
Page({
/**
* 頁面的初始數據
*/
data: {
message: "你好",
id:"adb",
person:{
name:"oliver",
age:18
}
},
tapName: function(event) {
console.log(event)
}
})
同樣,小程序中的事件分爲冒泡事件和非冒泡事件,冒泡事件簡單的說,就是組件上的事件被觸發以後,會向其父節點傳遞,舉個例子
<view bindtap="tapName">
<button bindtap="click">Click me!</button>
</view>
點擊了button上的bindtap觸發click函數之後,其父元素傷的bindtap同樣會被觸發,這就是冒泡,小程序中的冒泡事件大致有以下:
看到這裏可能有疑惑,爲什麼事件類型中沒有bind這個詞,上面例子中明明是用的bindtap,表裏面爲什麼僅僅是tap?實際上bind是一個修飾詞,可以理解成是類似於bue中的v-on,v-bind這種,在小程序中bind代表的是普通事件綁定,換個可以更好理解的寫法,bind:,具體示例:
<view bind:tap="tapName"> Click me! </view>
綁定普通事件
通過bind修飾的事件,就是普通事件,普通事件不會對事件進行處理,但處理事件的函數名必須是字符串,因此,傳參,如下例是不行的,因爲小程序會將後面整體視作是一個字符串
<view bindtap="handleTap(1)">
Click here!
</view>
綁定普通事件並阻止冒泡
通過catch修飾事件,通過catch修飾的事件,會阻止其冒泡行爲
<view catchtap="handleTap">
Click here!
</view>
綁定互斥事件
通過mut-bind修飾的事件,代表互斥事件,一個 mut-bind 觸發後,如果事件冒泡到其他節點上,其他節點上的 mut-bind 綁定函數不會被觸發,但 bind 綁定函數和 catch 綁定函數依舊會被觸發;
<view id="outer" mut-bind:tap="handleTap1">
outer view
<view id="middle" bind:tap="handleTap2">
middle view
<view id="inner" mut-bind:tap="handleTap3">
inner view
</view>
</view>
</view>
上例中,函數handleTap3被觸發後,事件冒泡到父節點,之後handleTap2會被觸發,再之後事件繼續冒泡到父節點,但是此時的outer上的綁定也是互斥事件,因此handleTap1將不會被觸發;
事件的捕獲
捕獲階段在冒泡階段之前,採用的修飾是capture-bind和capture-catch,
capture-bind:代表當組件處於捕獲階段時監聽事件並觸發相關函數,之後按正常的捕獲和冒泡流程走;
capture-catch:和capture-bind不同,capture-catch在觸發事件後,會取消之後的捕獲和冒泡流程,相當於直接終止了之後的流程;
<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,那麼所有的事件都會被觸發,並且觸發的流程是:handleTap2、handleTap4、handleTap3、handleTap1;
但如果將capture-bind替換成capture-catch,在觸發第一個touchstart後,它就會終止之後的所有流程,因此,只會觸發一個handleTap2函數;
生命週期
理解起來和vue的生命週期有點類似,簡單的說,就是在小程序在運行的過程中,會經歷過不同的階段,在不同的階段會拋出一些函數,稱爲鉤子函數,這些鉤子函數中的代碼會在這個階段中被運行,因此在不同的階段可以做一些特定的處理,比如獲取服務器信息,比如初始化數據等等,而這些鉤子函數統稱爲生命週期,因爲運行這些鉤子函數的階段囊括了從小程序的創建到銷燬;
小程序的生命週期分爲兩種,一種是小程序本體的,另外一種是各個頁面的
小程序生命週期
小程序的生命週期是寫在app.js中的
//app.js
App({
//監聽小程序初始化
onLaunch: function () {},
//監聽小程序啓動或切前臺,小程序在後臺切到前臺的時候會調用;
onShow: function(){},
//監聽小程序切後臺,小程序從前臺切到後臺的時候會調用;
onHide: function(){},
/*
* 發生錯誤是調用函數,在這個函數內,通常是用在監聽線上小程序有沒有發生錯誤的,
* 當發生錯誤時,觸發這個函數,在這個函數內可以將錯誤提交到後臺;
*/
onError: function(){},
/*
* 頁面不存在時調用函數,比如,有時候印刷了一些小程序二維碼做推廣,但是因爲一些特殊原因,
* 頁面被刪除了,那麼此時就可以通過這個函數監聽錯誤,提交後臺,然後做一些兼容;
*/
onPageNotFound: function(){},
globalData: {
userInfo: null
}
})
這個globalData,這個屬性是定義的一些全局屬性,比如示例中的userInfo是存儲的用戶信息,比如在打開小程序後,獲取當前用戶的信息,賦值給userInfo,那麼在之後的頁面顯示中都可以獲取到當前的用戶信息了;
//index.js等其他頁面
var app = getApp()
Page({
/**
* 頁面的初始數據
*/
data: {
message: "你好",
id:"adb",
person:{
name:"oliver",
age:18
}
},
//打印
tapName: function(event) {
console.log(app.globalData.userInfo)
}
})
頁面的生命週期
小程序的每個頁面都有自己的生命週期,它的接收一個對象作爲參數,其上有頁面的初始化數據,生命週期回調,事件處理函數
Page({
/**
* 頁面的初始數據
*/
data: {},
/**
* 生命週期函數--監聽頁面加載
*/
onLoad: function (options) {},
/**
* 生命週期函數--監聽頁面初次渲染完成,第一次打開頁面完成之後觸發
*/
onReady: function () {},
/**
* 生命週期函數--監聽頁面顯示
* 如果小程序主體和頁面都有onShow事件,那麼會先觸發小程序的,再觸發頁面的
*/
onShow: function () {},
/**
* 生命週期函數--監聽頁面隱藏,
* 如果小程序主體和頁面都有onHide事件,那麼會先觸發頁面的,再觸發小程序的
*/
onHide: function () {},
/**
* 生命週期函數--監聽頁面卸載,比如打開頁面後路由地址被重定向了,那麼此時會觸發這個函數
*/
onUnload: function () {},
/**
* 頁面相關事件處理函數--監聽用戶下拉動作,當用戶在頂部有下拉操作的時候,觸發該函數
* 比如下拉刷新操作
*/
onPullDownRefresh: function () {},
/**
* 頁面上拉觸底事件的處理函數,當頁面上的數據夠多,有滾動條時,如果此時滾動條拉到底部
* 會觸發該函數,默認是距離底部50px時觸發
*/
onReachBottom: function () {},
/**
* 用戶點擊右上角分享,點擊的是右上角的三個點按鈕
*/
onShareAppMessage: function () {}
/**
* 頁面滾動觸發事件的處理函數
*/
onPageScroll: function () {}
/**
* 頁面尺寸改變時觸發
* 比如橫屏豎屏切換的時候觸發
*/
onResize: function () {}
/**
* 當前是tab頁時,點擊tab觸發
* 比如實現點擊tab欄的時候觸發刷新頁面操作
*/
onTabItemTap: function () {}
})
具體的生命週期函數運行的順序如下:
小程序運行機制
前臺/後臺狀態
小程序啓動後,界面會被展示給用戶,此時的小程序處於前臺狀態;
當用戶點擊右上角膠囊按鈕關閉小程序,或者按了Home鍵離開微信時,小程序並沒有完全終止運行,而是進入了後臺狀態,此時的小程序還可以運行一段時間;
當再次打開小程序時,小程序又會從後臺進入前臺,但如果用戶很久沒有再進入小程序,或者系統資源緊張,小程序可能被銷燬,即完全終止運行。
小程序啓動
小程序啓動可以分爲兩種情況,一種是冷啓動,一種是熱啓動。
- 冷啓動:如果用戶首次打開,或小程序銷燬後被用戶再次打開,此時小程序需要重新加載啓動,即冷啓動。
- 熱啓動:如果用戶已經打開過某小程序,然後在一定時間內再次打開該小程序,此時小程序並未被銷燬,只是從後臺狀態進入前臺狀態,這個過程就是熱啓動。
小程序銷燬時機
通常,只有當小程序進入後臺一定時間,或者系統資源佔用過高,纔會被銷燬。具體而言包括以下幾種情形
- 當小程序進入後臺,可以維持一小段時間的運行狀態,如果這段時間內都未進入前臺,小程序會被銷燬。
- 當小程序佔用系統資源過高,可能會被系統銷燬或被微信客戶端主動回收。
啓動場景分類
具體請看運行機制這一頁,大概意思就是,當小程序被啓動的時候的場景,大致分爲兩類:A場景和B場景,打開小程序首頁的場景稱爲A場景(具體的場景ID值看網頁),打開小程序指定的某個頁面,稱爲B場景;
在小程序的onLaunch和onShow方法參數中可獲取場景值,可以根據不同的場景值對界面做一些特殊處理
App({
onLaunch: function (options) {
console.log("[onLaunch] 本次場景值:", options.scene)
},
onShow: function (options) {
console.log("[onShow] 本次場景值:", options.scene)
}
})