午夜91福利视频,午夜成人在线观看,午夜在线视频免费观看,午夜福利短视频,精品午夜成人免费视频APP

小程序模板網

微信小程序 App() 和 Page() 函數作用

發布時間:2021-06-01 08:42 所屬欄目:小程序開發教程

在微信開發者工具中,編(bian)譯運行(xing)你的(de)小程(cheng)序項目,然后打開控(kong)制臺,輸入 document 并(bing)回車,就可以看(kan)到小程(cheng)序運行(xing)時,WebView 加載的(de)完整的(de) page-frame.html,如下圖:

063ae10a5f8524d17436f9eefacad11f6d7650a8

通(tong)過(guo)分析(xi)這個 HTML 文件,我們可(ke)以得到小程序的啟動執行流(liu)程大致(zhi)如下:

f8765bd5baa57613f0a172fd5d97558a095280d1

此圖(tu)來自上述(shu)(shu)文章,我們這里(li)不再(zai)重(zhong)復贅述(shu)(shu)這些流程,下面(mian)我們來看一下其中的(de) App() 和 Page() 的(de)細節。這兩(liang)個函數在小程序(xu)框(kuang)架 WAService.js 中定(ding)義,并在 app.js 和每個頁面(mian)的(de) page.js 中進行調(diao)用(yong)實(shi)例(li)化。

在微信開發者工具的控(kong)制臺(tai)中(zhong)執行 openVendor() 方法,可以打開小程序框架(jia)所在目錄,如下:

/Users/用戶名/Library/Application Support/微信web開發者工具/WeappVendor/基礎庫版本號目錄

本(ben)文以 1.9.94 基礎(chu)庫(ku)為例進行分析。WAService.js 文件的結構如(ru)下:

;(function(global) {

    // WeixinJSBridge 的定義和加載

    // NativeBuffer 的定義和加載

    // wxConsole 的定義和加載

    // WeixinWorker 的定義和加載

    // Reporter 的定義和加載

    // __appServiceSDK__ 的定義和加載

    wx = __appServiceSDK__.wx,

    // exparser 的定義和加載

    // __virtualDOM__ 的定義和加載

    // __appServiceEngine__ 的定義和加載

    Page = __appServiceEngine__.Page,
    Component = __appServiceEngine__.Component,
    Behavior = __appServiceEngine__.Behavior,
    __webview_engine_version__ = .02,
    App = __appServiceEngine__.App,
    getApp = __appServiceEngine__.getApp,
    getCurrentPages = __appServiceEngine__.getCurrentPages,
    __createPluginGlobal = __appServiceEngine__.__createPluginGlobal,

    // __wxModule__ 的定義和加載

    definePlugin = __wxModule__.definePlugin,
    requirePlugin = __wxModule__.requirePlugin;

    // define 方法的定義

    // require 方法的定義

    global.App = App;
    global.Page = Page;
    global.Component = Component;
    global.Behavior = Behavior;
    global.__webview_engine_version__ = 0.02;
    global.getApp = getApp;
    global.getCurrentPages = getCurrentPages;
    global.wx = wx;
    global.definePlugin = __wxModule__.definePlugin;
    global.requirePlugin = __wxModule__.requirePlugin;

})(this);

我們發現,WAService.js 中定義了(le) WeixinJSBridge 和(he)(he) wx 這兩個基(ji)礎 API 集合(he),同時也包含的(de)其他一些框架(jia)(jia)核心,如(ru) exparser,__virtualDOM__,__appServiceEngine__ 等(deng)。其中__appServiceEngine__ 提(ti)(ti)供(gong)(gong)了(le)框架(jia)(jia)最基(ji)本(ben)的(de)對(dui)(dui)(dui)外接口,如(ru) App,Page,Component,Behavior 等(deng)方(fang)法(fa);exparser 提(ti)(ti)供(gong)(gong)了(le)框架(jia)(jia)底層(ceng)的(de)能力,如(ru)實(shi)例化組(zu)件,數據變(bian)化監聽,View 層(ceng)與(yu)邏輯層(ceng)的(de)交互等(deng);__virtualDOM__ 則起著(zhu)連接 __appServiceEngine__ 和(he)(he) exparser 的(de)作用(yong),如(ru)對(dui)(dui)(dui)開發者傳(chuan)入 Page 方(fang)法(fa)的(de)對(dui)(dui)(dui)象進行格式化再傳(chuan)入 exparser 的(de)對(dui)(dui)(dui)應方(fang)法(fa)處理。(此段分析(xi)摘自上述文章)

由上(shang)可知(zhi),本文要分析的(de)全局函數(shu) App() 和 Page() 是對 WAService.js 中定義(yi)的(de) __appServiceEngine__ 對象同名(ming)方法的(de)引用。下面我們簡(jian)要分析一下它們的(de)內部實現(xian)和初(chu)始化流(liu)程。

App() 和 getApp() 函數

根據(ju)微信小程序(xu)開發文檔,App() 函(han)數(shu)用來注冊一(yi)個(ge)(ge)小程序(xu),接(jie)收(shou)一(yi)個(ge)(ge) object 對(dui)象(xiang)參(can)數(shu),其指定小程序(xu)的生(sheng)命周(zhou)期函(han)數(shu)等。我們(men)從(cong)微信開發者(zhe)工具的函(han)數(shu)提(ti)示可(ke)以(yi)知道,App() 函(han)數(shu)的聲明如下(xia):

 

function App(options: _AppOptions): void
 

 

對于(yu)入參 object 對象(_AppOptions)的屬(shu)性說明如下:

37ce0c2a997dfe766c5bc9ce3fb127c5c0a0a537

此(ci)外,全(quan)局的 getApp() 函數可以用來獲取到(dao)小程序實例,它的聲明(ming)如下:

 

function getApp(): object

內部實現

 

在 __appServiceEngine__ 對象中,對 App 和 getApp 屬性的定義如(ru)下(xia):

 

// 其中的 t 就是 __appServiceEngine__ 對象

var i = n(17);

Object.defineProperty(t, "App", {

enumerable: !0,

get: function() {

return i.appHolder

}

}),

Object.defineProperty(t, "getApp", {

enumerable: !0,

get: function() {

return i.getApp

}

}),

 

而這(zhe)兩個屬(shu)性對應的實現分別(bie)為 appHolder() 和 getApp() 方法,定義如下:

 

l = void 0,

t.appHolder = (0, i.surroundByTryCatch)(function(e) {

l = new y(e)

}, "create app instance"),

t.getApp = function() {

return l

},
 

 

由(you)上可(ke)知,在(zai)(zai) appHolder() 方(fang)法中(zhong),把外部傳入(ru)的 object 對(dui)象傳給 y(...) 方(fang)法進行初始化一(yi)個小程(cheng)序(xu)實例對(dui)象,并把結(jie)果賦給變量 l 緩存起來,而在(zai)(zai) getApp() 方(fang)法中(zhong)則直接 return l,返回當前小程(cheng)序(xu)對(dui)象。

App 實例初始化流程

在上述 page-frame.html 中,我們(men)知道,在 app.js 被加載完后,小程序框架(jia)會立(li)即(ji)執行(xing) require('app.js') 進行(xing)注冊小程序實例(li),即(ji)對 App() 函數(shu)進行(xing)調(diao)用(開(kai)發者已經在 app.js 中定義好(hao)了入參(can)對象(xiang)),如下:

 

<script src="./app.js"></script>

<script>require("app.js")</script>
 

 

在 App() 函數中(zhong)(zhong),最終(zhong)會調用 y(...) 方(fang)法(fa)進行(xing)初(chu)始化,其中(zhong)(zhong) y(...) 的定義比較長(chang),我們這里不再貼出代碼,詳情請自行(xing)查閱 WAService.js,它(ta)的處(chu)理流程如下:

  • 聲明 App.getCurrentPage 方(fang)法將被廢棄,請使用 getCurrentPages() 全局方(fang)法;

  •  綁定(ding)(ding)生命周期函數,即把外部入參對象定(ding)(ding)義(yi)的屬(shu)性綁定(ding)(ding)到小程序實例對象中,包括 onLaunch,onShow,onHide,onUnlaunch 和 onPageNotFound;

  • 綁定(ding)開發者自定(ding)義(yi)的其(qi)他屬性(xing)(包括數據和方法),并校驗(yan)屬性(xing)名是否為 “getCurrentPage”,如果是則警告;

  •  根(gen)據(ju)外部是否有定義 onError 屬性判(pan)斷是否注冊錯誤上(shang)報(bao);

  • 檢查啟動參數(shu)(取自__wxConfig.appLaunchInfo)并依次調用 onLaunch 和 onShow 方法;

  • 注冊前(qian)后臺切換回調&nbsp;onShow&nbsp;和 onHide;

  • 注冊找不到頁面的回調 onPageNotFound;

  • 返(fan)回實(shi)例(li)給 App() 函數進行緩存。

Page() 和 getCurrentPages() 函數

根據文檔,Page() 函數(shu)(shu)用(yong)來(lai)注(zhu)冊一個頁面(mian),接收(shou)一個 object 對象參(can)數(shu)(shu),其指定頁面(mian)的初(chu)始(shi)數(shu)(shu)據、生命周期函數(shu)(shu)、事件處理函數(shu)(shu)等(deng)。Page() 函數(shu)(shu)的聲明如下:

 

function Page(page: PageOptions): void

對于入參 object 對象(PageOptions)的屬性說明如下:

 

b8cdb8bdd7d9f8f8e863d1b0a96ea0754a97ba93
 

此外,getCurrentPages() 函數用于獲取當前頁(ye)面(mian)棧的實例(li),以(yi)數組形式(shi)按棧的順序給出,第(di)一個元(yuan)素為首頁(ye),最后一個元(yuan)素為當前頁(ye)面(mian)。它的聲明如下(xia):

 

function getCurrentPages(): object[]
 

 

內部實現

同樣地,在 __appServiceEngine__ 對(dui)象中,對(dui) Page 和 getCurrentPages 屬性的(de)定(ding)義(yi)如下(xia):

 

var r = n(2);

Object.defineProperty(t, "Page", {

enumerable: !0,

get: function() {

return r.pageHolder

}

}),

Object.defineProperty(t, "getCurrentPages", {

enumerable: !0,

get: function() {

return r.getCurrentPages

}

}),

 

而(er)這(zhe)兩個屬(shu)性對應的實(shi)現分(fen)別為 pageHolder() 和 getCurrentPages() 方法,定義如下:

 

var k = void 0, // 保存當前顯示的頁面(棧頂)

x = [], // 保存已加載過的頁面歷史棧數組

// 其中的 t 就是 __appServiceEngine__ 對象

t.getCurrentPage = function() {

return k

},

t.getCurrentPages = function() {

var e = [];

return x.forEach(function(t) {

e.push(t.page)

}),

e

},



M = {}, // 緩存所有已經注冊的頁面

t.pageHolder = function(e) {

if (!__wxRouteBegin) throw (0, f.error)("Page 注冊錯誤", "Please do not register multiple Pages in " + __wxRoute + ".js"),

new a.AppServiceEngineKnownError("Please do not register multiple Pages in " + __wxRoute + ".js");

__wxRouteBegin = !1;

var t = __wxRoute;

if (!A(t)) throw (0, f.error)("Page 注冊錯誤", __wxRoute + " has not been declared in app.json."),

new a.AppServiceEngineKnownError(__wxRoute + " has not been declared in app.json.");

var n = "undefined" != typeof __wxAppCode__ ? __wxAppCode__[t + ".json"] || {}: {};

if ("Object" !== (0, f.getDataType)(e)) throw (0, f.error)("Page 注冊錯誤", "Options is not object: " + JSON.stringify(e) + " in " + __wxRoute + ".js"),

new a.AppServiceEngineKnownError("Options is not object: " + JSON.stringify(e) + " in " + __wxRoute + ".js"); (0, f.info)("Register Page: " + t),

void 0 !== n.usingComponents ? (__virtualDOM__.Page(e), M[t] = exparser.Component._list[t]) : M[t] = e

},

 

 

分析上述(shu)代碼,我(wo)們可以總結 pageHolder&nbsp;方法的處理(li)流程(cheng)如下(xia):

  • 小程序在每(mei)加載一個頁面(mian)前,會先設置 __wxRouteBegin = true,用(yong)于標記(ji)防重;

  • 判斷(duan) ;__wxRouteBegin 是否為 false,如果是,則拋出(chu)多次調用 Page 注冊錯誤;

  • 設置 __wxRouteBegin 為 false,避(bi)免(mian)被后(hou)續代碼被重復執行(xing);

  • 調(diao)用(yong)&nbsp;A(...) 方法檢(jian)查當前頁(ye)面是否在 app.json 中定義,如(ru)果沒有,則拋出錯誤;

  • 檢(jian)查外部入參(PageOptions)是(shi)否(fou)為 Object 對象,如果不(bu)是(shi),則(ze)拋出錯誤(wu);

  • 判斷(duan)當(dang)前頁面是否使用了(le)自(zi)定(ding)義組件(jian)(對于使用了(le)自(zi)定(ding)義組件(jian)的 Page 對象(xiang)會采用不同的配(pei)置(zhi)(zhi)),然(ran)后緩存當(dang)前 Page 的配(pei)置(zhi)(zhi)到 M 對象(xiang)中。

此外,我們可以發現,與 App() 不同的是,外部通過&nbsp;Page() 函數傳入(ru)的(生命周期)代碼并不會在這里被執(zhi)行(xing),而是等待頁(ye)面 Ready 并進入(ru)頁(ye)面進行(xing)實例化后才執(zhi)行(xing)。

頁面初始化流程

同樣地,根據(ju) page-frame.html 的(de)(de)加(jia)載(zai)順(shun)(shun)序(xu)(xu),在 app.js 被加(jia)載(zai)并執行后(hou),小程序(xu)(xu)之(zhi)后(hou)會先依次按順(shun)(shun)序(xu)(xu)加(jia)載(zai)所有(you)的(de)(de)自定義組件代碼(如果有(you))并自動(dong)注冊。自定義組件(Component)在小程序(xu)(xu)開發中具有(you)重(zhong)要地位,它(ta)可以豐富小程序(xu)(xu)的(de)(de)基礎功(gong)能,擁有(you)的(de)(de)能力(li)比 Page 更(geng)強大,因此(ci)實現也更(geng)加(jia)復(fu)雜(za),篇幅(fu)有(you)限(xian),我們(men)后(hou)續再單獨寫文章進行分(fen)析(xi)。

在加載執(zhi)行(xing)(xing)完自定(ding)義組件(jian)的代(dai)(dai)碼后,小(xiao)程序緊接著會(hui)依次按(an)順序加載每個頁面的代(dai)(dai)碼,并執(zhi)行(xing)(xing) require(...) 進(jin)行(xing)(xing)頁面注(zhu)冊,如下:

 


<script>__wxRoute = "pages/index/index";__wxRouteBegin = true</script>

<script>__wxAppCurrentFile__ = "pages/index/index.js"</script>

<script src="./pages/index/index.js"></script>

<script>require("pages/index/index.js")</script>

<script>

if(__wxRouteBegin) {

console.group("Tue Jun 26 2018 17:53:09 GMT+0800 (CST) page 編譯錯誤")

console.error("pages/index/index.js 出現腳本錯誤或者未正確調用 Page()")

console.groupEnd()

}

</script>

<!-- 加載注冊下一個 Page -->

 

  • 設(she)置&nbsp;__wxRoute 為當前 Page 的路徑,設(she)置 __wxRouteBegin 為 true;

  • 設置 __wxAppCurrentFile__ 為(wei)當前加(jia)載的文件路徑;

  • 加載頁面(mian)代碼(ma)并執(zhi)行(xing)進行(xing)注冊(ce)頁面(mian)(參考上述 pageHolder&nbsp;的處理流程(cheng));

  • 判斷 __wxRouteBegin 是否(fou)為 false,來判斷該頁面是否(fou)被成功注冊(因為在&nbsp;pageHolder方法(fa)中,成功執行是,會把 __wxRouteBegin 置為 false);

  • 依次加載其他(ta) Page;

  • 等(deng)待頁面(mian) Ready 和(he) Page 實例(li)化,page Load 由 wx.onAppRoute 事件觸發。

 在(zai) page-frame.html 中,當 head 中的所有(you) JS 代碼都(dou)執行完畢后,會(hui)在(zai) body 中觸發(fa) DOCUMENT_READY&nbsp;事件,如下:

 

<body>

<script>

if (document.readyState == 'complete') {

window.__global.alert('DOCUMENT_READY')

} else {

var fn = function(event) {

window.__global.alert('DOCUMENT_READY')

window.removeEventListener("load", fn)

}

window.addEventListener('load', fn)

}

</script>

</body>

 

在(zai)小(xiao)程序(xu)框架(jia) WAService.js 中,最(zui)終 DOCUMENT_READY 會轉化為 wx.onAppRoute 事(shi)件(邏輯(ji)待驗證),最(zui)終在(zai) wx.onAppRoute 事(shi)件中進行(xing)頁面的實例(li)化或者(zhe)頁面切換。

PS:關于(yu)一個小程(cheng)(cheng)序頁面(mian)的完整初(chu)始化加載流程(cheng)(cheng),我們將(jiang)在下一篇(pian)文章中(zhong)詳解。

總結

本文(wen)簡要地(di)分(fen)析(xi)了(le) App() 、getApp() 和(he)(he) Page() 、getCurrentPages() 等幾個(ge)函(han)數的內(nei)部實現,希望能讓你更好地(di)理解小程(cheng)序實例對象(xiang)和(he)(he)頁面的加載過程(cheng),給你實際開發帶來幫助(zhu)。


易優小程序(企業版)+靈活(huo)api+前(qian)后(hou)代(dai)碼開(kai)源 碼云倉庫:
本文地址://www.jinyoudianli.com/wxmini/doc/course/25893.html 復制鏈接 如需(xu)定制請聯系易優客服咨詢:

工作日 8:30-12:00 14:30-18:00
周六及部分節假日(ri)提供值班服務

易小優
轉人工 ×