論如何將 h5 頁面快速轉換成微信小程式
前言
微信小程式自開放出來到現在也有一段時間了,相信其底層架構也被琢磨得差不多了。微信小程式本身是雙執行緒執行的結構,而 h5 頁面是單執行緒的執行模式,因此兩者無法直接互通。微信小程式的執行模式如下:
微信小程式本身提供了 web-view 元件來支援在微信小程式中嵌入 h5 頁面,但是 web-view 元件在使用上還是有一些限制:不支援個人型別與海外型別的小程式、不支援全屏、頁面與小程式通訊不方便、很多小程式介面無法直接呼叫等。
如果無法使用 web-view,這裡還有一條路可以走,利用 h5-to-miniprogram 工具來將 h5 頁面轉換成小程式。
起步
假設你已經有一個 h5 頁面,包含四個檔案:
h5 頁面
|---- index.html
|---- index.css
|---- index.js
|---- index.png
複製程式碼
這種結構我們再熟悉不過了,具體每個檔案的內容可參考這裡:github.com/wechat-mini…。頁面渲染出來的效果如下:
頁面很簡單,但是值得一提的時,這個頁面引入了 jQuery 庫,所以 index.html 和 index.js 是這樣的:
<!doctype html>
<html lang="zh">
<head >
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1, user-scalable=no, minimal-ui">
<meta content="yes" name="apple-mobile-web-app-capable">
<meta content="black" name="apple-mobile-web-app-status-bar-style">
<meta name="format-detection" content="telephone=no, email=no">
<title>demo</title>
<style type="text/css">
html, body {
width: 100%;
height: 100%;
}
</style>
<link rel="stylesheet" href="./index.css">
</head>
<body>
<img class="logo" src="./index.png">
<div class="cnt"></div>
<script src="https://juneandgreen.github.io/test/h5-to-miniprogram-demo/demo2/js/jquery-1.12.4.min.js"></script>
<script src="./index.js"></script>
</body>
</html>
複製程式碼
$(document).ready(function() {
$('.cnt').text('h5 to miniprogram');
});
複製程式碼
微信小程式裡是不暴露 dom/bom 介面的,說想要使用 jQuery 是非常困難的。儘管難以置信,但是確實是有辦法的,後面會簡述一下原理,讓我先繼續看下要如何操作。
配置
因為執行環境的不同,為了在編譯時和執行時對兩者進行一些相容操作,我們需要一份配置檔案:
module.exports = {
index: 'h5', // 首頁
urlMap: { // 每個頁面對應的初始 url
h5: 'https://weixin.qq.com/index?a=1&b=2#hash',
},
resFilter(src, pageKey) {
// 資源過濾,用於替換 h5 中使用到的資源路徑
return pageKey === 'h5' && src === './index.png' ? 'https://raw.githubusercontent.com/wechat-miniprogram/h5-to-miniprogram-demo/master/h5/index.png' : src
},
}
複製程式碼
配置檔案很簡單,就是一個 js 檔案,裡面包含各種配置項。例如 index
配置項用於配置首頁;urlMap
用於配置每個頁面的初始 url,這個 url 會被解析到 window.location 中,通常用於頁面跳轉或單頁系統中;resFilter
配置項用於調整資源路徑,這裡是因為考慮到微信小程式包大小有限制,預設不會去處理圖片等資源,所以需要提供一個方法來替換資源路徑為網路路徑。
因為配置檔案需要拷貝到微信小程式專案中執行,所以配置檔案必須是一個純淨的沒有額外依賴的檔案(比如 require('fs')
在配置檔案中是不允許的)。
構建生成
有了原始的 h5,有了配置檔案,那就可以開始進行轉換並生成微信小程式專案了。我們來編寫一個構建指令碼,起名為 build.js:
const path = require('path')
const toMiniprogram = require('h5-to-miniprogram')
toMiniprogram({
entry: { // 入口 h5 頁面路徑
h5: path.join(__dirname, './h5/index.html'),
},
output: path.join(__dirname, './miniprogram'), // 輸出目錄
config: path.join(__dirname, './config.js'), // 配置檔案路徑
}).then(res => {
console.log('done')
}).catch(err => {
console.error(err)
})
複製程式碼
構建指令碼也很簡單,引入 h5-to-miniprogram 工具,此工具直接暴露一個 async 方法,呼叫時將必須的引數傳入即可。
可以看到引數中的入口配置是一個 key-value 物件,這裡的 value 不能理解,就是頁面的路徑,key 則是頁面的名稱。例子中這個頁面的 key 就是 h5,我們回到上面的配置檔案那裡就會發現,很多個地方都需要用到這個 key,這個 key 可以作為頁面的唯一標識。
寫完構建指令碼後,後續就簡單很多了,執行:
node build.js
複製程式碼
然後就會看到構建指令碼中指定的輸出目錄—— miniprogram 目錄被生成出來。完整的 demo 在這裡:github.com/wechat-mini…
使用
使用官方提供的開發者工具開啟 miniprogram 目錄,可以看到已經基本達到我們想要的效果了:
原理
原理其實很簡單,h5 頁面在瀏覽器執行的過程就是解析 html 到渲染 dom 樹的過程,然後提供一些 dom/bom 介面給 js 呼叫。那麼在小程式中我們把這一套給模擬一遍就行了,方法很暴力,但是卻意外的有效:因為給 h5 頁面提供了類似瀏覽器的環境,實現了最底層的適配,所以理論上來說那些通用的框架和庫也能支援執行。上面的例子中就表明了 jQuery 是能夠執行的,像 react、vue 也是可以做到支援的。
微信小程式是雙執行緒的執行模式,檢視層專注於渲染,邏輯層專注於邏輯。邏輯層是在一個純淨的 js 執行緒中跑,那裡沒有 dom/bom 介面,只能執行頁面邏輯層的程式碼。要模擬瀏覽器環境,最基本的就是要在邏輯層裡模擬出一棵 dom 樹,本質上和建立一棵虛擬樹類似,因為它並不是真實的 dom 樹。整個流程簡單來說是這樣的:
不管是頁面中的靜態 html 內容還是使用 innerHTML 等介面動態插入的 html 內容都可以走上面的流程來進行 dom 樹的建立。dom 樹建立比較簡單,只是細節比較多,此處的關鍵是將建立好的 dom 節點對映到微信小程式的自定義元件,利用自定義元件的特性可以輕易的將我們建立好的 dom 樹給渲染出來。
如果你還不清楚微信小程式的自定義元件是什麼的話,可以戳官方文件瞭解一下。
限制
受限於微信小程式本身的執行環境,所以這個轉換是無法做到非常完美的,比如動態執行 js 程式碼、動態插入修改 style 標籤等,所以使用此工具後一定要檢查轉換出來的微信小程式是否符合預期。
尾聲
本文更多的是為介紹 h5-to-miniprogram 工具的使用,後續會有更多實現上的介紹,有興趣的同學可以嘗試一下,有什麼好的建議可以在 issues 中提出,也歡迎推送 pull request 幫忙將此工具完善起來~
好評請 star 噢~