Skip to content

邏輯層

1.介紹

小程序開發框架的邏輯層使用JavaScript引擎為小程序提供開發JavaScript代碼的運行環境以及Luffa Cloud小程序的特有功能。

邏輯層將數據進行處理後發送給視圖層,同時接受視圖層的事件迴響。

開發者寫的所有代碼最終將會打包成一份JavaScript文件,並在小程序啟動的時候運行,直到小程序銷毀這一行為類似 SeviceWorker 所以邏輯層也稱之為App Service

在JavaScript的基礎上,我們新增了一些功能,以方便小程序的開發:

  • 新增App和Page方法,進行 程序注册頁面注册
  • 新增getApp和getCurrentPages方法,分別用來獲取App實例和當前頁面棧。
  • 提供豐富的 API,如獲取地理位置,掃一掃等特有能力。
  • 提供 模組化 能力,每個頁面有獨立的作用域。

TIP

小程序框架的邏輯層並非運行在瀏覽器中,囙此JavaScript在web中一些能力都無法使用,如window,document等。

2.注册小程序

每個小程序都需要在app.js中調用App(Object)方法注册小程序實例,綁定生命週期回呼函數、錯誤監聽和頁面不存在監聽函數等。

詳細的參數含義和使用請參攷 App

js
// app.js
App({  
  onLaunch (options) {    
    // Do something initial when launch.  
  },  
  onShow (options) {    
    // Do something when show.  
  },  
  onHide () {    
    // Do something when hide.  
  },  
  onError (msg) {    
    console.log(msg)  
  },  
  globalData: 'I am global data'
})

整個小程序只有一個App實例,是全部頁面共亯的開發者可以通過getApp方法獲取到全域唯一的App實例,獲取App上的數據或調用開發者注册在App上的函數。

js
// xxx.js
const appInstance = getApp()
console.log(appInstance.globalData) // I am global data

3.注册頁面

對於小程序中的每個頁面,都需要在頁面對應的js文件中進行注册,指定頁面的初始數據、生命週期回檔、事件處理函數等。

3.1使用Page構造器注册頁面

簡單的頁面可以使用Page(Object)進行構造。

代碼示例:

js
// index.js
Page({
  data: {
    text: "This is page data."
  },
  onLoad: function(options) {
    // Do some initialize when page load.
  },
  onReady: function() {
    // Do something when page ready.
  },
  onShow: function() {
    // Do something when page show.
  },
  onHide: function() {
    // Do something when page hide.
  },
  onUnload: function() {
    // Do something when page close.
  },
  onPullDownRefresh: function() {
    // Do something when pull down.
  },
  onReachBottom: function() {
    // Do something when page reach bottom.
  },
  onShareAppMessage: function () {
    // return custom share data when user share.
  },
  onPageScroll: function() {
    // Do something when page scroll
  },
  onResize: function() {
    // Do something when page resize
  },
  onTabItemTap(item) {
    console.log(item.index)
    console.log(item.pagePath)
    console.log(item.text)
  },
  // Event handler.
  viewTap: function() {
    this.setData({
      text: 'Set some data for updating view.'
    }, function() {
      // this is setData callback
    })
  },
  customData: {
    hi: 'MINA'
  }
})

詳細的參數含義和使用請參攷 頁面

3.2使用Component構造器構造頁面

Page構造器適用於簡單的頁面但對於複雜的頁面,Page構造器可能並不好用。

此時,可以使用Component建構器來建構頁面。 Component建構器的主要差異是:方法需要放在methods: { }裡面。

代碼示例:

js
Component({
  data: {
    text: "This is page data."
  },
  methods: {
    onLoad: function(options) {
      // Executed when the page is created
    }, onPullDownRefresh: function() { // Execute on page creation.
    onPullDownRefresh: function() {
      // onPullDownRefresh: function() { // On page creation }, onPullDownRefresh: function()
    }, onPullDownRefresh.
    // Event response function
    viewTap: function() {
      // ...
    }
  }
})

這種創建管道非常類似於 自定義組件,可以像自定義組件一樣使用behaviors等高級特性。

具體細節請閱讀 Component構造器

4.頁面生命週期

下圖說明了頁面Page實例的生命週期:

5.頁面路由

在小程序中所有頁面的路由全部由框架進行管理。

5.1頁面棧

框架以棧的形式維護了當前的所有頁面當發生路由切換的時候,頁面棧的表現如下:

路由管道
頁面棧表現
初始化
頁面棧表現
打開新頁面
組件的樣式類
頁面重定向
當前頁面入棧新頁面入棧
頁面返回
頁面不斷出棧,直到目標返回頁
切換
頁面全部出棧,只留下新的Tab頁面
重加載
頁面全部出棧,只留下新的頁面

開發者可以使用getCurrentPages()函數獲取當前頁面棧,以數組形式按棧的順序給出,第一個元素為首頁,最後一個元素為當前頁面。

TIP

  • 不要嘗試修改頁面棧,會導致路由以及頁面狀態錯誤
  • 不要在App.onLaunch的時候調用getCurrentPages(),此時page還沒有生成。

5.2路由管道

對於路由的觸發管道以及頁面生命週期函數如下:

路由管道
觸發時機
路由前頁面
路由後頁面
初始化
小程序打開的第一個頁面
-
onLoad, onShow
打開新頁面
調用API wx.navigateTo或使用組件<navigator open-type='navigateTo'/>
onHide
onLoad, onShow
頁面重定向
調用API wx.redirectTo或使用組件<navigator open-type='redirectTo'/>
onUnload
onLoad, onShow
頁面返回
調用API wx.switchTab或使用組件<navigator open-type='switchTab'/>或用戶切換Tab
onUnload
onShow
Tab切換
調用API wx.switchTab或使用組件<navigator open-type='switchTab'/>或用戶切換Tab
-
各種情况請參攷下錶
重啟動
調用API wx.reLaunch或使用組件<navigator open-type='reLaunch'/>
onUnload
onLoad, onShow

Tab切換對應的生命週期(以A、B頁面為Tabbar頁面,C是從A頁面打開的頁面,D頁面是從C頁面打開的頁面為例):

當前頁面
路由後頁面
觸發的生命週期(按順序)
A
A
Nothing happend
A
B
A.onHide(), B.onLoad(), B.onShow()
A
B(再次打開)
A.onHide(), B.onShow()
C
A
C.onUnload(), A.onShow()
C
B
C.onUnload(), B.onLoad(), B.onShow()
D
B
D.onUnload(), C.onUnload(), B.onLoad(), B.onShow()
D(從轉發進入)
A
D.onUnload(), A.onLoad(), A.onShow()
D(從轉發進入)
B
D.onUnload(), B.onLoad(), B.onShow()

TIP

  • navigateTo,redirectTo只能打開非tabBar頁面。
  • switchTab只能打開tabBar頁面。
  • reLaunch可以打開任意頁面。
  • 頁面底部的tabBar由頁面决定,即只要是定義為tabBar的頁面,底部都有tabBar。
  • 調用頁面路由帶的參數可以在目標頁面的onLoad中獲取。

模組化

6.1模組化

可以將一些公共的代碼抽離成為一個單獨的js文件,作為一個模塊模塊只有通過 module.exports 或者exports才能對外暴露接口。

TIP

  • exports是module.exports的一個引用,囙此在模塊裡邊隨意更改exports的指向會造成未知的錯誤所以更推薦開發者採用module.exports來暴露模塊接口,除非您已經清晰知道這兩者的關係。
  • 小程序現時不支持直接引入node_modules,開發者需要使用到node_modules時候建議拷貝出相關的代碼到小程序的目錄中,或者使用小程序支持的npm功能。
js
// common.js
function sayHello(name) {
  console.log(`Hello ${name} !`)
}
function sayGoodbye(name) {
  console.log(`Goodbye ${name} !`)
}

module.exports.sayHello = sayHello
exports.sayGoodbye = sayGoodbye

在需要使用這些模塊的文件中,使用require將公共代碼引入:

js
var common = require('common.js')
Page({
helloMINA: function() {
  common.sayHello('MINA')
},
goodbyeMINA: function() {
  common.sayGoodbye('MINA')
}
})

6.2文件作用域

在JavaScript文件中聲明的變量和函數只在該文件中有效; 不同的文件中可以聲明相同名字的變量和函數,不會互相影響。

通過全域函數getApp可以獲取全域的應用實例,如果需要全域的數據可以在App()中設定,如:

js
// app.js
App({
  globalData: 1
})
js
// a.js
// The localValue can only be used in file a.js.
var localValue = 'a'
// Get the app instance.
var app = getApp()
// Get the global data and change it.
app.globalData++
js
// a.js
// The localValue can only be used in file a.js.
var localValue = 'a'
// Get the app instance.
var app = getApp()
// Get the global data and change it.
app.globalData++

TIP

  • 值得注意的是,require引入模塊時,需要使用相對路徑。

7.API

小程序開發框架提供豐富的原生API,可以方便的調起小程序SDK提供的能力,如獲取用戶資訊,本地存儲等詳細介紹請參攷

7.1 事件監聽API

我們約定,以on開頭的API用來監聽某個事件是否觸發,如:wx.onSocketOpen,wx.onCompassChange等。

這類API接受一個回呼函數作為參數,當事件觸發時會調用這個回呼函數,並將相關資料以參數形式傳入。

代碼示例:

js
wx.onCompassChange(function (res) {
  console.log(res.direction)
})

7.2 同步API

我們約定,以Sync結尾的API都是同步API,如wx.setStorageSync,wx.getSystemInfoSync等此外,也有一些其他的同步API,如wx.createWorker,wx.getBackgroundAudioManager等,詳情參見API文件中的說明。

同步API的執行結果可以通過函數返回值直接獲取,如果執行出錯會拋出异常。

代碼示例:

js
try {
  wx.setStorageSync('key', 'value')
} catch (e) {
  console.error(e)
}

7.3 非同步API

大多數API都是非同步API,如wx.request,wx.login等這類API接口通常都接受一個Object類型的參數,這個參數都支持按需指定以下欄位來接收接口調用結果:

Object參數說明

參數名
類型
必填
說明
success
function
接口調用成功的回呼函數
fail
function
接口調用成功的回呼函數
complete
function
接口調用結束的回呼函數(調用成功、失敗都會執行)
complete
function
接口調用結束的回呼函數(調用成功、失敗都會執行)
其他
any
-
接口定義的其他參數

回呼函數的參數

success,fail,complete函數調用時會傳入一個Object類型參數,包含以下欄位:

内容
類型
說明:
errMsg
string
錯誤訊息,如果呼叫成功返回 ${apiName}:ok
errCode
number
錯誤碼,僅部分API支持,具體含義請參攷對應API文件,成功時為0
其他
any
接口返回的其他數據

代碼示例:

js
wx.login({
  success(res) {
    console.log(res.code)
  }
})