Taro小程序跨端开发入门实战
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 |
Taro | React/Vue | 丰富 | √ | √ | √ | √ | √ | √ | √ |
WePY | Vue | 丰富 | × | √ | √ | × | √ | √ | √ |
Chame Leon | Vue | 丰富 | × | √ | × | × | √ | × | × |
mpvue | 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
05Taro代码编译原理
图五 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
图十七 京东羚珑智能设计平台的部分功能截图
08结语
Taro V3.0.0 目前支持 React、Nerv、Vue 三类框架,在未来 Taro 将开放拓展能力,使得开发者可以通过 Taro 拓展更多的框架支持,(比如:适配 Flutter 将成为可能 )。目前Taro框架完善社区活跃,即使没有多端需求,仅用 Taro 开发 H5 也是个不错的选择(未来可以 0 成本接入小程序平台),想了解更多 Taro 3.0 实践经验欢迎线下交流。
HBase在人资数据预处理平台中的实践配运基础数据缓存瘦身实践基于遥感影像及轨迹数据融合的地图自动化生成器