taro初探:使用taro构建微信小程序基础教程

u=1650344933,1086893001&fm=173&app=25&f=JPEG.jpg

背景

众所周知如今市面上端的形态多种多样,手机Web、ReactNative、微信小程序, 支付宝小程序, 快应用等,每一端都是巨大的流量入口,当业务要求同时在不同的端都要求有所表现的时候,针对不同的端去编写多套代码的成本显然非常高,这时候只编写一套代码就能够适配到多端的能力就显得极为需要。目前比较流行的框架有wepy, mpvue ,taro
WEPY tencent.github.io/wepy/document腾讯团队开源的一款类vue语法规范的小程序框架,借鉴了Vue的语法风格和功能特性,支持了Vue的诸多特征,比如父子组件、组件之间的通信、computed计算属性、wathcer监听器、props传值、slot槽分发,Mixin混入等。WePY发布的第一个版本是2016年12月份,也就是小程序刚刚推出的时候,到目前为止,WePY已经发布了52个版本, 最新版本为1.7.2;MpVue mpvue.com/mpvue/#-html美团团队开源的一款使用 Vue.js 开发微信小程序的前端框架。使用此框架,开发者将得到完整的 Vue.js 开发体验,同时为 H5 和小程序提供了代码复用的能力。mpvue在发布后的几天间获得2.7k的star,上升速度飞起,截至目前为止已经有13.7k的star;Taro taro.aotu.io/京东凹凸实验室开源的一款使用 React.js 开发微信小程序的前端框架。它采用与 React 一致的组件化思想,组件生命周期与 React 保持一致,同时支持使用 JSX 语法,让代码具有更丰富的表现力,使用 Taro 进行开发可以获得和 React 一致的开发体验,同时因为使用了react的原因所以除了能编译h5, 小程序外还可以编译为ReactNative;对比如下:


16287204-e1b97e9b228f8464.jpg

本文主要讲一下京东凹凸实验室的Taro.个人感觉是这三种框架中最好用的。

Taro 是什么?

Taro 是由京东 - 凹凸实验室打造的一套遵循 React 语法规范的多端统一开发框架。
Taro 是一套遵循 React语法规范的 多端开发 解决方案。

使用 Taro,我们可以只书写一套代码,再通过 Taro 的编译工具,将源代码分别编译出可以在不同端(微信/百度/支付宝/字节跳动小程序、QQ轻应用、 H5、React-Native React语法规范,它采用与 React 一致的组件化思想,组件生命周期与 React 保持一致,同时支持使用 JSX 语法,让代码具有更丰富的表现力,使用 Taro 进行开发可以获得和 React 一致的开发体验。

import Taro, { Component } from '@tarojs/taro'
import { View, Button } from '@tarojs/components'

export default class Index extends Component {
  constructor () {
    super(...arguments)
    this.state = {
      title: '首页',
      list: [1, 2, 3]
    }
  }

  componentWillMount () {}

  componentDidMount () {}

  componentWillUpdate (nextProps, nextState) {}

  componentDidUpdate (prevProps, prevState) {}

  shouldComponentUpdate (nextProps, nextState) {
    return true
  }

  add = (e) => {
    // dosth
  }

  render () {
    return (
      <View className='index'>
        <View className='title'>{this.state.title}</View>
        <View className='content'>
          {this.state.list.map(item => {
            return (
              <View className='item'>{item}</View>
            )
          })}
          <Button className='add' onClick={this.add}>添加</Button>
        </View>
      </View>
    )
  }
}

相关连接

Github:

https://github.com/NervJS/taro

官网

https://taro.aotu.io/

为什么要使用Taro?

1.一次编写,多端运行

既然是一个多端解决方案,Taro 最重要的能力当然是写一套代码输出多端皆可运行的代码。目前 Taro 已经支持一套代码同时生成 H5 和微信小程序,App(React Native)端也即将支持,同时诸如快应用等端也将于近期得到支持。


platforms (2).jpg

同时 Taro 也已经投入到了生产环境使用,目前已经支撑了一个 3 万行代码小程序 TOPLIFE 的开发,以及部分京东购物小程序和一起有局小程序,未来也将会支撑更多的京东核心业务小程序。


u=558497892,3943524215&fm=173&app=25&f=JPEG.jpg
2.现代前端开发流程

和微信自带的小程序框架不一样,Taro 积极拥抱社区现有的现代开发流程,Taro 立足于微信小程序开发,众所周知小程序的开发体验并不是非常友好,比如小程序中无法使用 npm 来进行第三方库的管理,无法使用一些比较新的 ES 规范等等,针对小程序端的开发弊端,Taro 具有以下的优秀特性

image.png
import Taro from '@tarojs/taro'

Taro.setStorage({ key: 'key', data: 'value' })
  .then(res => console.log(res))
3.和 React 完全一致的 API 和组件化系统

在 Taro 中,你不用像小程序一样区分什么是 App 组件,什么是 Page 组件,什么是 Component 组件,Taro 全都是 Component 组件,并且和 React 的生命周期完全一致。可以说,一旦你掌握了 React,那就几乎掌握了 Taro。而学习 React 的资源也几乎是汗牛充栋,完全不用担心学不会。

Taro 和 React 一样,同样使用声明式的 JSX 语法。相比起字符串的模板语法,JSX 在处理精细复杂需求的时候会更得心应手。

class LoginStatus extends Component {
  render () {
    const isLoggedIn = this.props.isLoggedIn
    // 这里最好初始化声明为 `null`,初始化又不赋值的话
    // 小程序可能会报警为变量为 undefined
    let status = null
    if (isLoggedIn) {
      status = <Text>已登录</Text>
    } else {
      status = <Text>未登录</Text>
    }

    return (
      <View>
        {status}
      </View>
    )
  }
}
// app.js
import LoginStatus from './LoginStatus'

// 这样会渲染 `已登录`
class App extends Component {
  render () {
    return (
      <View>
        <LoginStatus isLoggedIn={true} />
      </View>
    )
  }
}

Taro的安装

1.先全局安装@tarojs/cli

$ npm install -g @tarojs/cli
$ yarn global add @tarojs/cli

2.之后我们初始化一个名为myApp的项目:

$ taro init myApp

3.然后输入你的配置:


3790386-48803f4402a41530.png

之后等待所有依赖安装完毕。
taro项目目录如下:

├── 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

Taro的基本原理

初衷

用React写微信小程序。微信小程序原生方式开发起来太费劲。遂想用React开发微信小程序。

延伸

在React业务代码转微信小程序代码这个最初的需求实现之后,发现依靠同样的转换思路可以适配多端,即从1对1延伸到1对n:


5b307974Na1febb30.jpg

P.S.其中Nerv是一种类React框架,API与React类似
P.S.Taro组件库之所以以微信小程序为标准,也是初衷使然(都做完了不能浪费啊)

一套代转生成多端的思路

想要一份代码通吃n端,无非2种思路:

1.直接从1端向n - 1端转换
2.加一层抽象,从这层抽象转换到n端
Taro也采用了第二种思路,这层抽象就是Taro业务代码:


u=868937013,3662335744&fm=173&app=25&f=JPEG.jpg

核心实现

以微信小程序为例,它由4部分组成:
1.配置(JSON)
2.模板(WXML)
3.样式(WXSS)
4.逻辑(JS)

配置与样式没什么好说的,难点在于模板的转换和逻辑的转换

P.S.ReactNative样式转换另说,也是一个难题,因为RN在选择器、属性名/值及默认值,甚至CSS特性支持程度都存在较大差异

编译转换

要把一份代码A转换成另一份代码B,需要做3件事情:
1.解析代码A生成抽象描述(AST)
2.根据一些映射规则操作AST,生成新的AST
3.根据新的AST生成代码B


taro-compile.jpeg

模板的转换

以小程序为例,把 JSX 语法转换成可以在小程序运行的字符串模板。
输入JSX:

render () {
    return (
      <View className='index'>
        <Button className='add_btn' onClick={this.props.add}>+</Button>
        <Button className='dec_btn' onClick={this.props.dec}>-</Button>
        <Button className='dec_btn' onClick={this.props.asyncAdd}>async</Button>
        <View><Text>{this.props.counter.num}</Text></View>
        <View><Text>Hello, World</Text></View>
      </View>
    )
  }

@tarojs/transformer-wx转换,输出微信小程序模板:

<block wx:if="{{$taroCompReady}}">
    <view class="index">
        <button class="add_btn" bindtap="funPrivateEfvXr">+</button>
        <button class="dec_btn" bindtap="funPrivateWnhMJ">-</button>
        <button class="dec_btn" bindtap="funPrivateAdUGq">async</button>
        <view><text>{{counter.num}}</text>
        </view>
        <view><text>Hello, World</text>
        </view>
    </view>
</block>

逻辑的转换

类似于组件库需要做多端适配,各端能力差异也同样需要适配:

组件库以及端能力都是依靠不同的端做不同实现来抹平差异

运行时框架负责适配各端能力,以支持跑在上面的Taro业务代码,主要有3个作用:

  • 适配组件化方案、配置选项等基础API

  • 适配平台能力相关的API(如网络请求、支付、拍照等)

  • 提供一些应用级的特性,如事件总线(Taro.EventsTaro.eventCenter)、运行环境相关的API(Taro.getEnv()Taro.ENV_TYPE)、UI适配方案(Taro.initPxTransform())等

实现上,@tarojs/taro是API适配的统一入口,编译时分平台替换

平台适配相关的package有6个:

这些API都可以直接使用,不用关心当前平台是否支持,因为运行时框架的适配工作的一部分就是抹平平台能力API差异,例如:

H5 端就无法调用扫码、蓝牙等端能力,各个小程序对页面函数的事件支持的程度也不一样。例如;
页面事件函数各端支持程度如下

方法 作用 微信小程序 百度小程序 字节跳动小程序 支付宝小程序 H5 RN
onPullDownRefresh 页面相关事件处理函数--监听用户下拉动作 ✔️ ✔️ ✔️ ✔️
onReachBottom 页面上拉触底事件的处理函数 ✔️ ✔️ ✔️ ✔️
onShareAppMessage 用户点击右上角转发 ✔️ ✔️ ✔️ ✔️
onPageScroll 页面滚动触发事件的处理函数 ✔️ ✔️ ✔️ ✔️
onTabItemTap 当前是 tab 页时,点击 tab 时触发 ✔️ ✔️ ✔️ ✔️
onResize 页面尺寸改变时触发,详见 响应显示区域变化 ✔️
componentWillPreload 预加载 ✔️
onTitleClick 点击标题触发 ✔️
onOptionMenuClick 点击导航栏额外图标触发 ✔️(基础库 1.3.0)
onPopMenuClick ✔️(基础库 1.3.0)
onPullIntercept 下拉截断时触发 ✔️(基础库 1.11.0)

以上成员方法在 Taro 的页面中同样可以使用,书写同名方法即可,不过需要注意的,目前暂时只有小程序端支持(支持程度如上)这些方法,编译到 H5/RN 端后这些方法均会失效。

采用微信小程序标准,所以这些 API 在 H5 端运行的时候将什么也不做。

同时在业务层区分目标环境,保证这些平台相关的代码仅在预期的目标环境下执行:

  • 编译时:process.env.TARO_ENV

  • 运行时:Taro.getEnv()

例如:

// 分平台调用API或者分平台处理兼容性问题
if (process.env.TARO_ENV === 'weapp') {
  Taro.textToAudio()
}
// 分平台使用不同组件
<View>
  {process.env.TARO_ENV === 'weapp' && <ScrollViewWeapp />}
  {process.env.TARO_ENV === 'h5' && <ScrollViewH5 />}
</View>

P.S.编译时静态的环境区分足够应对大多数场景了,运行时的环境区分仅备不时之需

项目生命周期之间的匹配

首先一张图看一下小程序的生命周期


5712653-324180d5884ea119.png

1.小程序初始化完成后,页面首次加载触发onLoad,只会触发一次。
2.当小程序进入到后台,先执行页面onHide方法再执行应用onHide方法。
3.当小程序从后台进入到前台,先执行应用onShow方法再执行页面onShow方法。应用生命周期和页面生命周期不是分开的,两者一起进行,相互交叉使用,会用到相同的方法,比如onShow和onHide。
然后看一下react生命周期


ac9f0d1c9cacf270f481aa7aba580f7f (1).jpg

一个例子说明小程序和taro生命周期的映射关系为:
生命周期方法 作用 说明
componentWillMount 程序被载入 对应微信小程序onLaunch
componentDidMount 程序被载入 对应微信小程序onLaunch,在componentWillMount之后执行
componentDidShow 程序展示出来 对应微信小程序onShow
componentDidHide 程序被隐藏 对应微信小程序onHide
componentDidCatchError 错误监听函数 对应微信小程序 onError
componentDidNotFound 页面不存在 对应微信小程序 onPageNotFound

不过当然也包含componentWillUnmout和componentWillReceiveProps等react原始生命周期函数,用来编写自定义组件和h5页面。
在小程序中 ,页面还有一些专属的方法成员,如下:

  1. onPullDownRefresh: 页面相关事件处理函数–监听用户下拉动作

  2. onReachBottom: 页面上拉触底事件的处理函数

  3. onShareAppMessage: 用户点击右上角转发

  4. onPageScroll: 页面滚动触发事件的处理函数

  5. onTabItemTap: 当前是 tab 页时,点击 tab 时触发

  6. componentWillPreload: 预加载,只在微信小程序中可用

设计稿及尺寸单位

在 Taro 中尺寸单位建议使用 px、 百分比 %,Taro 默认会对所有单位进行转换。在 Taro 中书写尺寸按照 1:1 的关系来进行书写,即从设计稿上量的长度 100px,那么尺寸书写就是 100px,当转成微信小程序的时候,尺寸将默认转换为 100rpx,当转成 H5 时将默认转换为以 rem 为单位的值。

如果你希望部分 px 单位不被转换成 rpx 或者 rem ,最简单的做法就是在 px 单位中增加一个大写字母,例如 Px 或者 PX 这样,则会被转换插件忽略。

结合过往的开发经验,Taro 默认以 750px 作为换算尺寸标准,如果设计稿不是以 750px 为标准,则需要在项目配置 config/index.js 中进行设置,例如设计稿尺寸是 640px,则需要修改项目配置 config/index.js 中的 designWidth 配置为 640:

const config = {
  projectName: 'myProject',
  date: '2018-4-18',
  designWidth: 640,
  ....
}

目前 Taro 支持 750、 640 、 828 三种尺寸设计稿,他们的换算规则如下:

const DEVICE_RATIO = {
  '640': 2.34 / 2,
  '750': 1,
  '828': 1.81 / 2
}

建议使用 Taro 时,设计稿以 iPhone 6 750px 作为设计尺寸标准。

API

在编译时,Taro 会帮你对样式做尺寸转换操作,但是如果是在 JS 中书写了行内样式,那么编译时就无法做替换了,针对这种情况,Taro 提供了 API Taro.pxTransform 来做运行时的尺寸转换。

Taro.pxTransform(10) // 小程序:rpx,H5:rem

配置

默认配置会对所有的 px 单位进行转换,有大写字母的 PxPX 则会被忽略。

参数默认值如下:

{
  onePxTransform: true,
  unitPrecision: 5,
  propList: ['*'],
  selectorBlackList: [],
  replace: true,
  mediaQuery: false,
  minPixelValue: 0
}

Type: Object | Null

onePxTransform (Boolean)

设置 1px 是否需要被转换

unitPrecision (Number)

REM 单位允许的小数位。

propList (Array)

允许转换的属性。

replace (Boolean)

直接替换而不是追加一条进行覆盖。

mediaQuery (Boolean)

允许媒体查询里的 px 单位转换

minPixelValue (Number)

设置一个可被转换的最小 px 值

selectorBlackList (Number)

黑名单里的选择器将会被忽略。

配置规则对应到 config/index.js ,例如:

{
  h5: {
    publicPath: '/',
    staticDirectory: 'static',
    module: {
      postcss: {
        autoprefixer: {
          enable: true
        },
        pxtransform: {
          enable: true,
          config: {
            selectorBlackList: ['body']
          }
        }
      }
    }
  },
  weapp: {
    // ...
    module: {
      postcss: {
        pxtransform: {
          enable: true,
          config: {
            selectorBlackList: ['body']
          }
        }
      }
    }
  }
}

忽略

属性

当前忽略单个属性的最简单的方法,就是 px 单位使用大写字母。

 /* `px` is converted to `rem` */
.convert {
  font-size: 16px; // converted to 1rem
}

 /* `Px` or `PX` is ignored by `postcss-pxtorem` but still accepted by browsers */
.ignore {
  border: 1Px solid; // ignored
  border-width: 2PX; // ignored
}

文件

对于头部包含注释 /*postcss-pxtransform disable*/ 的文件,插件不予处理。

一起用Taro做一个demo

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 194,088评论 5 459
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 81,715评论 2 371
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 141,361评论 0 319
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 52,099评论 1 263
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 60,987评论 4 355
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 46,063评论 1 272
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 36,486评论 3 381
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 35,175评论 0 253
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 39,440评论 1 290
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 34,518评论 2 309
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 36,305评论 1 326
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,190评论 3 312
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 37,550评论 3 298
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 28,880评论 0 17
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,152评论 1 250
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 41,451评论 2 341
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 40,637评论 2 335

推荐阅读更多精彩内容