《微信小程序》徹底入門小程序

前言

微信小程序的火爆相信不用多說,作爲一個前端,小程序幾乎可以算得上是前端技能的一個加分項,如果找工作的時候會小程序,那麼相對而言會有很多優勢;

簡介

官方解釋:小程序是一種全新的連接用戶與服務的方式,它可以在微信內被便捷地獲取和傳播,同時具有出色的使用體驗。簡單的說,小程序就像是微信的一個功能插件,這個功能插件可以無縫的接入微信,讓用戶在微信中使用小程序時獲得接近原生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)
    }
})
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章