用户
 找回密码
 立即注册

QQ登录

只需一步,快速开始

扫一扫,登录网站

小程序社区 首页 教程 实战教程 查看内容

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

Rolan 2020-9-23 14:20

Taro 是一套遵循 React语法规范的 多端开发 解决方案

背景

众所周知如今市面上端的形态多种多样,手机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;对比如下:

本文主要讲一下Taro.个人感觉是这三种框架中最好用的。

Taro 是什么?

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>
    )
  }
}

为什么要使用Taro?

1.一次编写,多端运行

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

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

2.现代前端开发流程

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

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.然后输入你的配置:

之后等待所有依赖安装完毕。

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:

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

一套代转生成多端的思路

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

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


以微信小程序为例,它由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}>asyncButton>
        <View><Text>{this.props.counter.num}Text>View>
        <View><Text>Hello, WorldText>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">asyncbutton>
        <view><text>{{counter.num}}text>
        view>
        <view><text>Hello, Worldtext>
        view>
    view>
block>

逻辑的转换

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

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

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

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

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

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

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

  • @tarojs/taro:只是一层空壳,提供API签名

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

  • @tarojs/taro-alipay:适配支付宝小程序

  • @tarojs/taro-h5:适配Web

  • @tarojs/taro-rn:适配ReactNative

  • @tarojs/taro-swan:适配百度小程序

  • @tarojs/taro-tt:适配头条小程序

  • @tarojs/taro-qapp:适配快应用

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

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

页面事件函数各端支持程度如下



以上成员方法在 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.编译时静态的环境区分足够应对大多数场景了,运行时的环境区分仅备不时之需

项目生命周期之间的匹配

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


1.小程序初始化完成后,页面首次加载触发onLoad,只会触发一次。

2.当小程序进入到后台,先执行页面onHide方法再执行应用onHide方法。

3.当小程序从后台进入到前台,先执行应用onShow方法再执行页面onShow方法。应用生命周期和页面生命周期不是分开的,两者一起进行,相互交叉使用,会用到相同的方法,比如onShow和onHide。

然后看一下react生命周期

一个例子说明小程序和taro生命周期的映射关系为:

不过当然也包含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*/ 的文件,插件不予处理。

作者:这个前端不太冷
来源:简书
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
鲜花
鲜花
鸡蛋
鸡蛋
分享至 : QQ空间
收藏