Taro小程序跨端開發入門實戰

語言: CN / TW / HK

Tech

導讀

隨着業務不斷擴張以及大小程序平台的崛起,針對每個平台都去寫一套代碼是不現實的,且原生的小程序開發模式有很多弊端。 為了讓小程序開發更簡單、高效,採用Taro作為首選框架,本文將分享Taro的實踐經驗,主要內容圍繞什麼是Taro以及Taro如何使用(正確使用的姿勢),還有Taro背後的一些設計思想來展開,讓讀者能夠對Taro有較為完整的認識。Taro3.0已經逐漸成熟,實踐項目已經進行Taro3.0的升級,因此本文代碼示例以Taro3.0作為基礎。

01

什麼是Taro

Taro 是一個多端統一的開發框架。使用 Taro 它可以支持 React 的開發方式,編寫一次可以運行多端的代碼,就能夠生成可以在各種小程序,H5 甚至 React Native 等多端應用。

Taro的官方介紹

Taro 是一個開放式跨端跨框架解決方案,支持使用 React/Vue/Nerv 等框架來開發 微信 / 京東 / 百度 / 支付寶 / 字節跳動 / QQ 小程序 / H5/ React Native 等應用。現如今市面上端的形態多種多樣,Web、React Native、微信小程序等各種端大行其道,當業務要求同時在不同的端都要求有所表現的時候,針對不同的端去編寫多套代碼的成本顯然非常高,這時候只編寫一套代碼就能夠適配到多端的能力就顯得極為需要。

Taro的主要特點

快:可以快速開發小程序,解決小程序開發的各種痛點;

多:可以實現多終端適配,一套代碼適配小程序、H5、RN等多終端。

02

為什麼用Taro

隨着應用規模逐漸龐大,複雜度也隨之越來越高,原生小程序開發的痛點逐漸暴露出來。

  • 代碼組織複雜:寫一個頁面的文件結構繁多(四個之多);

  • 規範不統一:組件、方法命名規範不統一,各種書寫方式、語法結構不一致,既像React,又像Vue;

  • 孱弱的字符串模板:邏輯表現力不強,不支持eslint;

  • 依賴管理混亂:缺少npm包依賴管理;

  • 不完全的ES Next:僅支持部分ES Next語法,比較新的ES2020,ES2021+都不支持;

  • 落後的開發方式:前端工程體系不完善,webpack打包,css預處理等缺失,對於前端來説比較落後,對個人成長也不利

03

可選技術方案

對於以上微信小程序開發模式的痛點,業界給出了一些可選方案,mpvue、WePY、Chame Leon及Taro,以下進行簡要的對比分析。

框架 技術棧 案例 小程序轉換能力 微信小程序 百度小程序 京東小程序 H5 其它小程序/快應用 App
mpvue React/Vue 豐富
WePY Vue 豐富 × ×
Chame Leon Vue 豐富 × × × × ×
Taro Vue 豐富 × × × × × ×
  • myvue: 美團研發的框架,多端適配效果不好,很久的問題無人維護;

  • WePY: 騰訊研發的組件化框架,但是無法適配多端;

  • Chame Leon:在多端適配方面表現很突出,缺點是不支持京東小程序,無法轉換原生小程序(若想使用只能重寫項目);

  • Taro :遵循React/Vue語法規範,引入現代化的開發流程,讓研發更專注核心代,提供健全的代碼檢查方式。

多端需求

圖一 多端需求

Taro支持平台最全面,獨具轉換能力,性能方面優於其它框架,總結特點如下:

1.可以實現微信小程序原生代碼轉換到微信平台、百度平台等;

2.Taro框架是唯一一款實現京東小程序適配的框架;

3.支持React/Vue語法,更好地支持組件化和TypeScript;

4.行業影響力大,社區活躍,京東內部優秀團隊研發的框架,支持有保障;

5.更加完善的UI組件庫,支持多端同步調試,能夠適配更多終端。

一處編寫,多端運行

圖二 一處編寫,多端運行

04

設計思想

主要採用React開發方式,使用React編寫多端應用。

圖三 React開發方式的優勢

圖四 React編寫多端應用

核心思想

代碼轉換:使代碼可以在不同平台上運行;

運行時適配:使代碼在不同平台上有相同表現。

以微信小程序為示例

// Taro 代碼
import Taro from '@tarojs/taro'
import { Text, View, Button } from '@tarojs/components'
import React from 'react'
import './A.scss'


type Props = {
onClick: () => void
tip: string
}
export default class A extends React.PureComponent<Props> {
componentWillUnmount() {}
componentDidMount() {}
componentWillReceiveProps(nextProps) {}
shouldComponentUpdate() {}
componentDidShow() {}
componetDidHide() {}

onClickHandler = () => {
this.props.onClick()
}


render(): JSX.Element {
return (
<View className="a">
<Button onClick={this.onClickHandler}></Button>
<Text> a component {this.props.tip}</Text>
</View>
)
}
}

Taro代碼

Component({
properties: {
myProperty: { // 屬性名
type: String
},
myProperty2: String // 簡化的定義方式
},
data: {}, // 私有數據,可用於模板渲染


// 生命週期函數,可以為函數,或一個在 methods 中定義的方法名
ready: function() {},


attached: function() {},


moved: function(){},


detached: function(){},


onShow(): function() {},


onHide(): function() {},


methods: {
onButtonTap: function{
this.setData(){
// 更新屬性和數據的方法與更新頁面數據的方法類似
}
}
}
})

小程序代碼

render(): JSX.Element {
return (
<View className="index">
{this.state.list.map((item) => {
<View key={item.id}>{item.name}</View>
})}
<Button onClick={this.onClickHandler}>Hello JSX </Button>
<Text> a component {this.props.tip}</Text>
</View>
)
}

JSX

<view class="index">
<view wx:key={item.id} wx:for="{{list}}" wx:for-item="item">{{item.name}}</view>
<button bindtap="onClickHandler">Hello JSX</button>
<text>{{tip}}</text>
</view>

WXML

05

Taro代碼編譯原理

圖五   Taro代碼編譯原理

Taro 的編譯原理:就是對輸入的源代碼進行語法分析,語法樹構建,隨後對語法樹進行轉換操作再解析生成目標代碼的過程。

首先是 Parse,將代碼解析(Parse)成抽象語法樹(Abstract Syntex Tree),然後對 AST 進行遍歷(traverse)和替換(replace)(這對於前端來説其實並不陌生,可以類比 DOM 樹的操作),最後是生成(generate),根據新的 AST 生成編譯後的代碼。

開發時遵循 React 語法標準,結合編譯原理的思想,對代碼文件進行一系列轉換操作,最終獲得可以在小程序運行的代碼。而 React 最開始就是為了解決 Web 開發而生的,所以對代碼稍加改動,也可以直接生成在 Web 端運行的代碼,而同屬 React 語法體系下的 React Native,也能夠很便捷地提供支持。同理其他平台,如快應用、百度小程序等,將源碼進行編譯轉換操作,也能獲得該平台下的對應語法代碼。

圖六  小程序與React組件的生命週期對比

圖七 小程序與React組件的狀態對比

圖八  小程序組件與web組件之間的差異

圖九 小程序 API 與 Web API 之間的差異

可以看出小程序和 Web 端上組件標準與 API 標準有很大差異,這些差異僅僅通過代碼編譯手段是無法抹平的,例如你不能直接在編譯時將小程序的 <view/> 直接編譯成 <div/>,因為他們雖然看上去有些類似,但是他們的組件屬性有很大不同的,僅僅依靠代碼編譯,無法做到一致,同理,眾多 API 也面臨一樣的情況。針對這樣的情況,Taro 採用了定製一套運行時標準來抹平不同平台之間的差異。

這一套標準主要以三個部分組成,包括標準運行時框架、標準基礎組件庫、標準端能力 API,其中運行時框架和 API 對應 @taro/taro,組件庫對應 @tarojs/components,通過在不同端實現這些標準,從而達到去差異化的目的。

06

多端適配基礎標準

  • 基礎框架(生命週期、組件API): 以React的生命週期、組件api為基礎,小程序的特性作為補充

  •  標準組件庫(View、Button): 以微信小程序組件為標準,各端模擬實現

  • 標準API (request、setState): 擴展的小程序標準Api,各端模擬實現

圖十 多端適配基礎架構圖(上)

圖十一 多端適配基礎架構圖(下)

07

快速上手

初始化項目

環境準備:node環境,運行npm命令。

# 使用 npm 安裝 CLI
$ npm install -g @tarojs/cli
$ taro init myTaroApp


# 使用 npx 初始化項目
$ npx @tarojs/cli init myTaroApp

開始使用Taro編寫頁面。

// pages/index/index


import React from 'react'
import { View, Text } from '@tarojs/components'


export default class Index extends React.Component {
state = {
msg: 'Hello World!'
}


render () {
return (
<View>{this.state.msg}</View>
)
}
}

運行項目

# 啟動指定平台代碼,可以同時運行於多平台
# 僅限全局安裝
$ taro build —-type {weapp/h5/swan/tt/jd/rn} —-watch

多平台啟動命令示例

# 開發調試命令:


# 京東小程序
npm run dev:jd
# 百度小程序
npm run dev:swan
# 微信小程序
npm run dev:weapp


# 打包發佈命令:


# 京東小程序
npm run build:jd
# 百度小程序
npm run build:swan
# 微信小程序
npm run build:weapp

如果同時看三端效果,分別運行以上命令即可。

微信原生小程序轉換Taro小程序

# 只運行一次即可
$ npx @tarojs/cli convert

Taro項目的組成

圖十二 Taro項目組成

Taro項目目錄結構

基本的目錄結構:

├── dist                   編譯結果目錄
├── config 配置目錄
| ├── dev.js 開發時配置
| ├── index.js 默認配置
| └── prod.js 打包時配置
├── src 源碼目錄
| ├── components 公共組件目錄
| ├── pages 頁面文件目錄
| | ├── index index 頁面目錄
| | | ├── banner 頁面 index 私有組件
| | | ├── index.js index 頁面邏輯
| | | └── index.css index 頁面樣式
| ├── utils 公共方法庫
| ├── app.css 項目總通用樣式
| └── app.js 項目入口文件
└── package.json 項目包信息

比較完整的多端項目結構:

├── dist                                編譯結果目錄
| ├── weapp 微信平台編譯目錄
| ├── swan 百度平台編譯目錄
| ├── jd 京東平台編譯目錄
| ├── ... 其它平台編譯目錄
├── config 配置目錄
| ├── dev.js 開發時配置
| ├── index.js 默認配置
| └── prod.js 打包時配置
├── src 源碼目錄
| ├── assets 公共資源目錄(內含圖標等資源)
| ├── components 公共組件目錄
| | └── Btn 公共組件 Btn 目錄
| | ├── Btn.tsx 公共組件 Btn 邏輯
| | └── Btn.scss 公共組件 Btn 樣式
| ├── pages 頁面文件目錄
| | └── index index 頁面目錄
| | ├── components index 頁面的獨有組件目錄
| | | └── Banner index 頁面的 Banner 組件目錄
| | | ├── Banner.tsx index 頁面的 Banner 組件邏輯
| | | └── Banner.scss index 頁面的 Banner 組件樣式
| | ├── index.js index 頁面邏輯
| | └── index.scss index 頁面樣式
| ├── subpackages 分包目錄(項目過大時建議分包)
| | └── profile 一個叫 profile 的分包目錄
| | └── pages 該分包的頁面文件目錄
| | └── index 該分包的頁面 index 目錄(其下結構與主包的頁面文件一致)
| ├── utils 項目輔助類工具目錄
| | └── api.js 比如輔助類 api 等
| ├── store Redux 狀態管理
| | ├── reducers Redux Reducers
| | └── actions Redux Actions
| ├── app.scss 項目總通用樣式
| ├── types 項目 TS 類型聲明
| └── app.config.js 項目入口配置文件
| └── app.js 項目主入口文件
└── package.json 依賴管理包信息

注:完整的文檔請訪問: https://taro-docs.jd.com/

多端適配

多終端配置文件編寫

  • 微信的配置文件 project.config.json,文件內容可以自定義微信小程序的選項,運行的目錄和 appid 等;

  • 百度小程序的配置文件 project.swan.json 內容和微信類似;

  • 京東小程序的配置文件 project.jd.json 內容和微信類似;

  • 其它平台的小程序都有獨立的配置文件便於運行的調試;

圖十三 不同的項目配置文件

多終端入口文件

每個平台有不同的頁面配置信息:

  • 微信小程序頁面是全量的,有微信登錄頁面(其它平台不需要);

  • 百度小程序有專門的登錄頁面有些頁面百度不支持需隱藏比如:圖片裁剪,達達同城,打印等;

  • 京東小程序:不支持批量寄,不需要登錄頁面,不支持分包,都要寫入主包中;

# 多端適配入口文件目錄結構


├── app.js # 默認入口信息
├── app.h5.ts # H5 入口信息
├── app.jd.ts # 京東小程序 入口信息
├── app.swan.ts # 百度小程序 入口信息
├── app.tt.ts # 頭條小程序 入口信息
├── app.weapp.ts # 微信小程序 入口信息

文件目錄結構

差異化配置

不同平台加載對應的文件:

  • 每個平台差異化配置信息;

  • 地圖類型;

  • 渠道信息;

  • 請求頭信息……

# 多端適配的文件目錄結構


├── config # 多端適配配置文件目錄
| ├── config.h5.ts # H5 特有配置信息
| ├── config.jd.ts # 京東小程序 特有配置信息
| ├── config.swan.ts # 百度小程序 特有配置信息
| ├── config.tt.ts # 頭條小程序 特有配置信息
| ├── config.weapp.ts # 微信小程序 特有配置信息

文件目錄結構

代碼差異化處理

平台特定 js 代碼塊兒實現,在任意 js 代碼中加入如下語法:

// 京東邏輯
if (process.env.TARO_ENV === 'jd') {
// 如果是京東小程序,需要處理的內容,比如分享
}
// 百度邏輯
if (process.env.TARO_ENV === 'swan') {
// 如果是百度小程序,需要處理的內容,比如支付
// ...
}
// 微信邏輯
if (process.env.TARO_ENV === 'weapp') {
// 如果是微信小程序,需要處理的內容,比如跳轉其它微信小程序
// ...
}
// H5 邏輯
if (process.env.TARO_ENV === 'h5') {
// ...
}
// 頭條小程序 邏輯
if (process.env.TARO_ENV === 'tt') {
// ...
}

平台特定 css 代碼塊實現, 在任意 css 代碼中加入如下語法:

# 如果是多個平台,之間可以使用空格隔開。


/* #ifdef weapp */
// 樣式代碼
/* #endif */
/* #ifdef swan */
// 樣式代碼
/* #endif */


/* #ifdef jd */
// 樣式代碼
/* #endif */


/* #ifdef jd weapp */
// 樣式代碼
/* #endif */
# 代碼在打包時不會增加包體積,針對不同平台提取相應代碼;

提示:代碼在打包時不會增加包體積,針對不同平台提取相應代碼。

多端適配案例

一些典型的多端通用解決方案:

1.樣式解析:

  • 微信是 rpx,百度小程序 vw,京東小程序 px;

  • Taro 統一使用 px 通過框架處理轉換成對應平台的像素,因此 px 值不要使用單數;

  • 1px(像素)的邊框通常會轉換成平台對應單位會導致無法顯示, 可以使用大寫的PX單位,例如:1PX ;

  • 百度小程序和京東小程序不支持 externalClasses,其它小程序也可能不支持避免使用;

2.模塊導入和導出:

  • 導入模塊需要使用ES6 的 import, 不要使用 require 到 JS 文件(有些平台不支持);

  • 內聯本地圖片資源可以使用 require 動態導入;

  • 導入外部資源的 url 必須使用 https,有些平台或機型不支持 http ;

  • 小程序插件導入可以使用 require 但是要做多平台適配和兼容性處理;

3.組件開發細節:

  • 組件 key 取值,不要使用 index ,對象的 id 屬性要先解構出來;

  • 組件渲染條件取 length 屬性頁面不更新;

  • dataset 問題:百度和微信獲取的不一樣,都要用小寫來保持代碼一致:這種駝峯的:data-goodsIndex={index} ,微信會轉成全小寫 goodsindex, 百度會保留駝峯 ,正確地寫法:data-goodsindex={index} ;

百度小程序開發注意事項

(1) 層次較深的狀態不會更新時,需要解構變量;

(2) 轉換成 vw 樣式有偏差,確保樣式的通用性;

(3) 個別組件 height: auto 有bug,不寫沒事;

(4) line-height 居中有偏差,用 flex 比較穩妥;

(5)fixed 佈局居底要設置 left: 0, bottom: 0 ,不寫默認會有問題(默認在中間渲染);

(6)mask 組件層級較深時,可能不會更新狀態,可以使用 tt-modal 代替;

(7)圖片裁剪,語音識別,打印功能等依賴原生 API 不支持;

(8)狀態更新從有到無需要顯性設置 null ,例如將列表組件隱藏:this.setState({list: null}) {list && <組件實例>}。

京東小程序開發注意事項

(1) 不支持全局覆蓋組件樣式,如果想兼容需要單寫加上拼接樣式名;

(2)不支持小程序分包,需要單獨配置頁面路由信息;

(3)showModal 彈窗不能定製 confirmColor 屬性;

(4)storagesync 不支持存儲 json 數據,讀取需要自己手動JSON.parse;

(5)不支持 canvas繪畫API:微信自定義分享功能,圖片裁剪,訂單條形碼等功能都做不了;

(6)不支持同層渲染,原生組件上只能使用 Cover 組件;

(7)ios 內嵌H5,如果url帶參數,需要手動做一下urlencode編碼;

(8)H5頁面使用小程序 webview 不具備全部京東 app webview 功能,有些功能不支持;

(9)京東小程序分享 URL 和 其它小程序分享的 URL 不一樣,要注意路徑的差異區分。例如:shareURL: 京東小程序:page/index/index 微信小程序:/pages/index/index

多端同步調試

在 config/index.js 配置:outputRoot: dist/${process.env.TARO_ENV}

多端同步調試需要在終端工具中打開多個 Tab 來同時執行 taro 命令進行同步調試,比如:編譯成微信小程序和百度小程序,可以同時打開兩個終端分別執行不同的命令即可:

# 終端1
$ npm run dev:weapp


# 終端2
$ npm run dev:swan

08

生態與規劃

物流風格的 Taro UI組件庫—Tarot(已適配Taro3.0)

另附內部組件庫,歡迎共建,請關注:

http://star.jdwl.com/star/tarot/components/

圖十四 星雲平台的網站界面

圖十五 組件庫的部分UI示例界面

定製化Taro模板工程

模板工程主要特性:

  • 自帶按需引入的 Tarot 組件庫及組件使用示例;

  • 自帶 pandora-tools  中的工具,如網關調用插件等;

  • 登陸適配多端,小程序端自動引入京東無線登陸插件,h5端自動跳轉無線統一登錄M頁等;

  • 網關調用適配多端,自帶 Demo 示例;

  • 包含 TypeScript 和 Redux等更多高級API及用法示例……

小程序 Mini Debug 工具

MiniDebug 是一款多端小程序調試工具,旨在提高小程序開發、測試效率的工具庫。 主要功能包括環境切換、身份Mock、應用信息獲取、位置模擬、緩存管理、掃一掃、H5跳轉、更新版本等。工具部分頁面如下圖所示:

圖十六 MiniDebug 工具的部分功能截圖

注:京東商城已經實現了小程序可視化拖拽平台:

https://ling.jd.com/atom/cms/pc/06599

圖十七 京東羚瓏智能設計平台的部分功能截圖

Taro V3.0.0 目前支持 React Nerv Vue  三類框架,在未來 Taro 將開放拓展能力,使得開發者可以通過 Taro 拓展更多的框架支持,(比如: 適配 Flutter 將成為可能  )。目前Taro框架完善社區活躍,即使沒有多端需求,僅用 Taro 開發 H5 也是個不錯的選擇(未來可以 0 成本接入小程序平台),想了解更多 Taro 3.0 實踐經驗歡迎線下交流。