1. 程式人生 > >論如何將 h5 頁面快速轉換成微信小程式

論如何將 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 噢~