從?#65279字符看dede模板頁面編碼問題
1085
2025-03-31
動手實(shí)現(xiàn)微信小程序和小游戲編譯打包和運(yùn)行環(huán)境平臺 (核心篇三)
本章節(jié)就帶大家通過微信官方的創(chuàng)建項(xiàng)目部分代碼來講解一下這些對外 api 如何通過我們自己方式來實(shí)現(xiàn)和微信相同的功能操作,我們通過微信開發(fā)者工具來自動創(chuàng)建一個(gè)默認(rèn)的小程序項(xiàng)目 一個(gè)首頁和日志頁。
這個(gè)項(xiàng)目大家應(yīng)該都比較熟悉吧,應(yīng)該第一次接觸小程序開始時(shí)引入眼前的場景,具體的其他內(nèi)容我們就不在這里啰嗦了,直接看下它的 app.js 文件,編輯器打開后可以看到里面寫了這些。
//app.js App({ onLaunch: function () { // 展示本地存儲能力 var logs = wx.getStorageSync('logs') || [] logs.unshift(Date.now()) wx.setStorageSync('logs', logs) // 登錄 wx.login({ success: res => { // 發(fā)送 res.code 到后臺換取 openId, sessionKey, unionId } }) // 獲取用戶信息 wx.getSetting({ success: res => { if (res.authSetting['scope.userInfo']) { // 已經(jīng)授權(quán),可以直接調(diào)用 getUserInfo 獲取頭像昵稱,不會彈框 wx.getUserInfo({ success: res => { } }) } } }) }, globalData: { userInfo: null } })
先給大家把接下來部分要說明的消息事件整理出來讓大家可以看的清楚一些,后面的內(nèi)容主要是圍繞這個(gè)消息事件和代碼來說明
上面這個(gè)圖就是從微信開發(fā)者工具里面打開頁面時(shí)候出現(xiàn)的事件和消息類型以及有關(guān)數(shù)據(jù),分析一下可以看出:
1、首先調(diào)用了同步 api getSystemInfo,我們可以看到在我們的項(xiàng)目代碼里面沒有存在這個(gè) api,但是開發(fā)者工具第一步就調(diào)用了,所以在項(xiàng)目編譯初始化的時(shí)候就觸發(fā)了,至于 Receive 的數(shù)據(jù)返回的就是工具界面左上角的一些配置數(shù)據(jù),大家可以打開自己的開發(fā)者工具看看,一些參數(shù)是你可以直接從上面觀察到的,如手機(jī)型號 屏幕占比 網(wǎng)絡(luò)類型等,這個(gè)同步 api 是系統(tǒng)自動調(diào)用的不用我們做寫什么操作,而且它會比較頻繁的調(diào)用。(這點(diǎn)我也沒理解,當(dāng)我打開控制臺的時(shí)候他會調(diào)用很多次)
在前面的文章中講到同步的 api 都是通過走 http 協(xié)議’/apihelper/assdk’鏈接過來的,里面攜帶了 api 名和一些參數(shù),所以我們可以直接攔截’/apihelper/assdk’請求進(jìn)行處理
實(shí)例代碼展示
router.post('/apihelper/assdk', async (ctx, next) => { const { api, args } = JSON.parse(ctx.request.body); if (api === 'getSystemInfo') { ctx.body = { 'errMsg': 'getSystemInfo:ok', 'model': 'iPhone 7 Plus', 'pixelRatio': 3, 'windowWidth': 414, 'windowHeight': 624, 'system': 'iOS 10.0.1', 'language': 'en', 'version': '7.0.4', 'screenWidth': 414, 'screenHeight': 736, 'SDKVersion': '2.7.1', 'brand': 'devtools', 'fontSizeSetting': 16, 'benchmarkLevel': 1, 'batteryLevel': 100, 'statusBarHeight': 20, 'safeArea': { 'right': 414, 'bottom': 736, 'left': 0, 'top': 20, 'width': 414, 'height': 716 } }; } })
ctx.body 的結(jié)果集可以直接復(fù)制開發(fā)者工具中的數(shù)據(jù)就可以,如果要實(shí)際使用的話需要把部分參數(shù)改成動態(tài)獲取的。
2、當(dāng)代碼執(zhí)行 wx.getStorageSync(‘logs’) wx.setStorageSync(‘logs’, logs)的時(shí)候(標(biāo)簽二)通過前面的日志描述可以知道它們都是 appservice sdk 調(diào)用的同步的 api,就是我們普通使用的 Storage 它們包裝做了一層轉(zhuǎn)換,因?yàn)檫@個(gè)頁面是初始化的時(shí)候調(diào)用的所以這里面的數(shù)據(jù)都是空的。當(dāng)點(diǎn)擊 log 頁面的時(shí)候,就可以看到調(diào)用了 APPSERVICE_PUBLISH 事件類型,此類型是 view 層發(fā)給 service 層的我們看到它的 webviewID 存在值。
看出 data 里面的數(shù)據(jù)就是 Storage 存儲的 Date.now()時(shí)間, wx.setStorageSync wx.getStorageSync 在源碼對應(yīng)的地方。
var r = re.IS_IOS ? "setStorage" : "setStorageSync" var r = re.IS_IOS ? "getStorage" : "getStorageSync"
看出如果是 ios 的話就只能調(diào)用 setStorage getStorage 方式。
模擬代碼展示:
const storage = new Map(); const getStorage = function (key) { return storage.get(key); }; const setStorage = function (key, value) { storage.set(key, value); }; const removeStorage = function (key) { storage.delete(key); }; module.exports = { getStorage, setStorage, removeStorage };
如果想模擬全局的存儲簡單的可以直接使用 map 進(jìn)行操作,然后在調(diào)用的時(shí)候獲取對應(yīng)的 api 進(jìn)行獲取和設(shè)置操作,完善的話存儲可以采用瀏覽器的 LocalStorage,SessionStorage 或者一些 npm 包進(jìn)行處理。
3、我們比較常用的一個(gè) api 通過 wx.login 換取 code 可以看出(標(biāo)簽三)中,是通過邏輯層 service 自發(fā)自收的,發(fā)起一個(gè)請求通過 service 邏輯層處理后在回調(diào)回去,通過微信 api 源碼可以看到調(diào)用的地方
這一塊要想要弄的很好不是很容易,涉及到用戶體系就要和服務(wù)端徹底打通,好在登錄授權(quán)這塊微信也是采用 OAuth2 協(xié)議實(shí)現(xiàn)的。
如果有朋友對 OAuth2 還不是很了解明白的話,建議看下這個(gè)文檔(https://tools.ietf.org/html/rfc6749)比市面上 90%的相關(guān)內(nèi)容講的更徹底通透。
4、當(dāng)在小程序中打開頁面時(shí)觸發(fā)了 onAppRoute 事件,通過日志看出發(fā)送了 APPSERVICE_ON_EVENT 事件,path 表示當(dāng)前頁面,openType 表示操作類型,openType 如果不是很明顯的話我們試著點(diǎn)擊一下,從日志頁面返回首頁的后退操作。
看到"openType":"navigateBack"這個(gè)應(yīng)該比較好理解解釋了。
到這里我們會有一些不一樣的地方了,因?yàn)檫@里的操作的是事件處理不是簡單的 api 處理就 ok 了,所有前端頁面操作的控制器都是一個(gè)整體,首先我們要先搭建這個(gè)載體容器存放各個(gè)部分。
模擬代碼實(shí)例:
構(gòu)建一個(gè)總管理處理的信息
constructor(wxConfig = {}, socketPort) { super(); this.wxConfig = wxConfig; this.systemManager = new SystemManager(this, wxConfig); this.navigatorManager = new NavigatorManager(this, wxConfig); this.pageManager = new PageManager(wxConfig, socketPort); this.tabbarManager = new TabbarManager(this, wxConfig); this._render(); this._launch(); window.socketClient.setEmitter(this); }
然后 render 頁面信息,結(jié)合 node 后臺服務(wù)渲染前端展示
this.domElement = document.createElement('div'); this.domElement.id = 'container'; this.domElement.style = ` height: ${global.simulator.height}px; width: ${global.simulator.width}px;` // system this.domElement.appendChild(this.systemManager.domElement); // navigator this.domElement.appendChild(this.navigatorManager.domElement); // pages this.domElement.appendChild(this.pageManager.domElement); // tabbar this.domElement.appendChild(this.tabbarManager.domElement);
后面就是監(jiān)聽各個(gè)事件控制和各種業(yè)務(wù)處理,核心還是要按照開發(fā)者工具的消息順序和內(nèi)容來實(shí)現(xiàn)。
例如上面我們提到的 navigateBack 我們自己這邊實(shí)現(xiàn)按照平常的業(yè)務(wù)寫法就 ok。
navigateBack (path, query) { let currentWebview = this.domElement.children.item(0); let currentIndex = currentWebview.style['z-index']; this.domElement.removeChild(currentWebview); let targetPage = null; for (let i = 0; i < this.domElement.children.length; i++) { let webview = this.domElement.children.item(i); if (webview.style['z-index'] === `${currentIndex - 1}`) { let viewId = +webview.getAttribute('data-view-id'); let path = webview.getAttribute('data-view-path'); let query = JSON.parse(webview.getAttribute('data-view-query')); window.socketClient.send(WebsocketMessage.onAppRoute(viewId, path, query, 'navigateBack')); window.socketClient.send(WebsocketMessage.onAppRouteDone(viewId, path, query, 'navigateBack')); targetPage = path; break; } } return targetPage; }
重要的還是 socketClient.send 消息的正確傳遞才可以和基礎(chǔ)庫正確的交互
其他的很多對外的 api 實(shí)現(xiàn)方式都是大同小異,主要是在接收到消息后怎么處理設(shè)計(jì)
我們知道了核心的流程,下面要做的就是模仿設(shè)計(jì),模仿它的消息格式和返回結(jié)構(gòu),設(shè)計(jì)自己的各系統(tǒng)模塊的關(guān)聯(lián)
對于小游戲而言大致是一樣的,主要有幾個(gè)點(diǎn)不同:
小游戲是通過根目錄下的 game.json 來對小游戲進(jìn)行全局配置,決定相關(guān)界面渲染和屬性設(shè)置等;
在小游戲的運(yùn)行環(huán)境里面不存在 BOM 和 DOM API,只有 wx API 對它們進(jìn)行了包裝,所以無法直接使用;
小游戲的運(yùn)行層只有一層在 view 里面跑;
小游戲的大部分 api 主要都是對文件系統(tǒng)和網(wǎng)絡(luò)的處理。
上面的一些總結(jié)主要是根據(jù)一些 api 的實(shí)現(xiàn)來描述擴(kuò)展了一些,看完后希望大家對此有所了解,后面我打算從全局來講下怎么從代碼設(shè)計(jì)方面來設(shè)計(jì)整個(gè)瀏覽器運(yùn)行環(huán)境實(shí)現(xiàn)方案。
API 小程序
版權(quán)聲明:本文內(nèi)容由網(wǎng)絡(luò)用戶投稿,版權(quán)歸原作者所有,本站不擁有其著作權(quán),亦不承擔(dān)相應(yīng)法律責(zé)任。如果您發(fā)現(xiàn)本站中有涉嫌抄襲或描述失實(shí)的內(nèi)容,請聯(lián)系我們jiasou666@gmail.com 處理,核實(shí)后本網(wǎng)站將在24小時(shí)內(nèi)刪除侵權(quán)內(nèi)容。
版權(quán)聲明:本文內(nèi)容由網(wǎng)絡(luò)用戶投稿,版權(quán)歸原作者所有,本站不擁有其著作權(quán),亦不承擔(dān)相應(yīng)法律責(zé)任。如果您發(fā)現(xiàn)本站中有涉嫌抄襲或描述失實(shí)的內(nèi)容,請聯(lián)系我們jiasou666@gmail.com 處理,核實(shí)后本網(wǎng)站將在24小時(shí)內(nèi)刪除侵權(quán)內(nèi)容。