服務項目
品牌網站建設

數字營銷

係統平台開發

數字產品

安全運維

Menu
官网开云
官网开云
微信小程序架構分析《二》:view 模塊和 service 模塊的構成
時間:2020-07-15 10:36:30

 

你可以在app.nw/app/dist/weapp/tpl/pageFrameTpl.js 和app.nw/app/dist/weapp/tpl/appserviceTpl.js 文件內(nei) 找到頁麵的模板。

打開微信 web 開發者工具,然後輸入 openVendor() 便會(hui) 打開 WeappVendor這個(ge) 目錄,這裏包含了 view 模塊和 service 模塊使用的幾個(ge) 核心文件:

  • wcc 可執行程序,用於(yu) 將 wxml 轉為(wei) view 模塊使用的 js 代碼,使用方式為(wei) wcc xxx.wxml

  • wcsc 可執行程序,用於(yu) 將 wxss 轉為(wei) view 模塊使用的 css 代碼,使用方式為(wei) wcsc xxx.wxss

  • WAService.js 提供 service 模塊大部分功能,下麵會(hui) 有詳細介紹

  • WAWebview.js 提供 view 模塊大部分功能,下麵會(hui) 有詳細介紹

view 頁麵詳解

view 頁麵的 template 如下:

 

<!DOCTYPE html> <html lang="zh-CN"> <head> <link href="https://res.wx.qq.com/mpres/htmledition/images/favicon218877.ico" rel="Shortcut Icon"> <meta charset="UTF-8" /> <meta name="viewport" content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0" /> <script> var __webviewId__; </script> <!-- percodes --> <!--{{WAWebview}}--> <!--{{reportSDK}}--> <!--{{webviewSDK}}--> <!--{{exparser}}--> <!--{{components_js}}--> <!--{{virtual_dom}}--> <!--{{components_css}}--> <!--{{allWXML}}--> <!--{{eruda}}--> <!--{{style}}--> <!--{{currentstyle}}--> <!--{{generateFunc}}--> </head> <body> <div></div> </body> </html>

其中 <!-- percodes --> 會(hui) 在 dev 模式開啟後被替換為(wei) 一個(ge) 時間錨點,例如:

 

<script>var pageFrameStartTime = new Date();</script>

<!--{{WAWebview}}--> 會(hui) 被 WAWebview.js 內(nei) 代碼替換

<!--{{WAWebview}}--> 到 <!--{{generateFunc}}--> 之間暫時沒有被使用到

<!--{{generateFunc}}--> 會(hui) 被 wcc 命令生成後的 js 代碼替換

除了上麵這些,頁麵上還會(hui) 被插入頁麵和應用的 style 標簽,如:

 

<link rel="stylesheet" type="text/css" href="index.wxss">

這裏的 wxss 文件包含的是原始 wxss 文件轉換後的 css

以及生成 DOM 的啟動腳本:

 

<script> document.dispatchEvent(new CustomEvent("generateFuncReady", { detail: { generateFunc: $gwx('./page/index.wxml') } })) </script>

WAWebview.js 文件中的各個(ge) 模塊(行號為(wei) jsbeautify 之後代碼行號,開發者工具版本:092300):

  • 1-77 行: WeixinJSBridge 對象兼容層,這個(ge) 大概隻會(hui) 在調試時用到,因為(wei) 開發時和運行時頁麵都會(hui) 被後台以注入的方式添加 WeixinJSBridge 這個(ge) 對象。我們(men) 可以通過這段代碼看到它暴露的方法: invoke invokeCallbackHandleron publish subscribe subscribe subscribeHandler。

  • 78-235 行:Reporter 對象,它的作用就是發送錯誤和性能統計數據給後台

  • 236-596 行:wx 對象,頁麵的核心之一,一方麵封裝 WeixinJSBridge 的 invokeMethod 方位為(wei) 易於(yu) 調用的形式(例如 redirectTo, navigateTo等),另一方麵封裝 WeixinJSBridge 回調方法,調用者可以使用wx.onAppDataChange(callback) 添加數據變更的回調函數,最後提供wx.publishPageEvent 發送頁麵事件到後台

  • 607-1267 行:wxparser 對象,提供 dom 到 wx element 對象之間的映射操作,提供元素操作管理和事件管理功能

  • 1268-1285 行:轉發 window 上的 animation 和 transition 相關(guan) 的動畫事件到 exparser

  • 1286-1313 行:訂閱並轉發 WeixinJSBridge 提供的全局事件到 exparser

  • 1324-1345 行:轉發 window 上的 error 以及各種表單事件到 exparser

  • 1347-3744 行:使用 exparser.registerBehavior 和exparser.registerElement 方法注冊(ce) 各種以 wx- 做為(wei) 標簽開頭的元素到 exparser

  • 3744-4498 行:virtual dom 渲染算法實現,提供 diff apply render 等方法,該模塊接口基本與(yu) virtual-dom 一致,這裏特別的地方在於(yu) 它所 diff 和生成的並不是原生 DOM,而是各種模擬了 DOM 接口的 wx element 對象

  • 4599-4510 行:插入默認樣式到頁麵

從(cong) 頁麵 data 到 dom 的主要流程如下:

 

var vtree var rootNode document.addEventListener("generateFuncReady", function(e) { var generateFunc = e.detail.generateFunc; wx.onAppDataChange(function(obj) { // 合並 data 到現有 data DataStore.setData(obj.data) // 生成 virtual dom 的 javascript plain object var props = generateFunc(DataStore.getData()) // 第一次渲染 if (obj.options.firstRender) { vtree = createVirtualTree(props, true) rootNode = vtree.render() rootNode.replaceDocumentElement(document.body) wx.initReady() } else { var other_vtree = createVirtualTree(props, false) var patches = vtree.diff(other_vtree) patches.apply(rootNode) vtree = other_vtree document.dispatchEvent(new CustomEvent("pageReRender", {})); } }) })

上麵的 DataStore 對象提供合並和獲取當前頁麵 data 對象的功能,其實現如下:

 

var DataStore = (function() { var data = {} return { getData: function() { return data }, setData: function(e) { for (var t in e) { for (var n = (0, parsePath)(t), o = data, a = void 0, s = void 0, c = 0; c < n.length; c++) Number(n[c]) === n[c] && Number(n[c]) % 1 === 0 ? Array.isArray(o) || (a[s] = [], o = a[s]) : "[object Object]" !== Object.prototype.toString.call(o) && (a[s] = {}, o = a[s]), s = n[c], a = o, o = o[n[c]]; a && (a[s] = e[t]) } } } })() // 解析 key 為(wei) data 內(nei) 對象的路徑字符串 function parsePath(e) { for (var t = e.length, n = [], i = "", r = 0, o = !1, a = !1, s = 0; s < t; s++) { var c = e[s]; if ("\\" === c) s + 1 < t && ("." === e[s + 1] || "[" === e[s + 1] || "]" === e[s + 1]) ? (i += e[s + 1], s++) : i += "\\"; else if ("." === c) i && (n.push(i), i = ""); else if ("[" === c) { if (i && (n.push(i), i = ""), 0 === n.length) throw new Error("path can not start with []: " + e); a = !0, o = !1 } else if ("]" === c) { if (!o) throw new Error("must have number in []: " + e); a = !1, n.push(r), r = 0 } else if (a) { if (c < "0" || c > "9") throw new Error("only number 0-9 could inside []: " + e); o = !0, r = 10 * r + c.charCodeAt(0) - 48 } else i += c } if (i && n.push(i), 0 === n.length) throw new Error("path can not be empty"); return n }

可以看到,每次 data 變化之後,小程序就會(hui) 開始整個(ge) 頁麵的 diff patch 過程。

對於(yu) 原生實現的組件, exparser 會(hui) 在監視到數據變化後發送對應事件到 WeixinJSBridge。

service 頁麵詳解

service 頁麵會(hui) 被被拚接為(wei) 以下的樣子:

 

<!DOCTYPE html> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> <link href="https://res.wx.qq.com/mpres/htmledition/images/favicon218877.ico" rel="Shortcut Icon"> <script> var __wxAppData = {} var __wxRoute var __wxRouteBegin </script> <script>var __wxConfig = {"pages":["page/index"], // app 相關(guan) 各種配置 }</script> <script src="https://70475629.appservice.open.weixin.qq.com/asdebug.js"></script> <script src="https://70475629.appservice.open.weixin.qq.com/WAService.js"></script> <script src="https://70475629.appservice.open.weixin.qq.com/app.js"></script> <script> __wxRoute = 'page/index'; __wxRouteBegin = true </script> <script src="https://70475629.appservice.open.weixin.qq.com/page/index.js"></script> </head> <body> <script> window._____sendMsgToNW({ sdkName: 'APP_SERVICE_COMPLETE' }) </script> </body> </html>

除了配置和開發者編寫(xie) 的頁麵、app.js,頁麵還在加載了 asdebug.js 和 WAService.js 兩(liang) 個(ge) 文件。

asdebug.js 文件位於(yu) nwjs 項目目錄下,路徑為(wei) app/dist/weapp/appservice/asdebug.js。 它包含了兩(liang) 個(ge) 部分,一個(ge) 是 WeixinJSBridge 針對 service 模塊的實現,另一塊是一些方便命令使用的接口, 例如:help() 會(hui) 告訴你一些可用的函數:

該文件隻會(hui) 在開發者工具內(nei) 被引入,如果小程序在微信內(nei) 運行,應該會(hui) 由微信底層提供 WeixinJSBridge。

WAService 負責 service 模塊的一些核心邏輯,它包含以下部分 (行號為(wei) jsbeautify 之後代碼行號,開發者工具版本:092300):

  • 1-78 行: 跟 WAWebview.js 一樣的 WeixinJSBridge 兼容模塊
  • 79-245 行: 跟 WAWebview.js 一樣的 Reporter 模塊
  • 246-1664 行:比 WAWebview.js 中 wx 功能更為豐富 wx 接口模塊
  • 1665-2304 行:appServiceEngine 模塊,提供 Page,App,GetApp 接口
  • 2305-2360 行: 為 window 對象添加 AMD 接口 require define

現在的 WAService 還有有很多地方依賴 window 對象,所以很有可能它在微信中和開發者工具內(nei) 一樣,依然運行於(yu) webview 標簽之內(nei) 。

Kaiyun体育官方全站入口服務SERVICE
谘詢
微信掃碼谘詢
電話谘詢
400-888-9358