Taro 使用指南

Taro 就是可以用 React 语法写小程序的框架,拥有多端转换能力,一套代码可编译为微信小程序、百度小程序、支付宝小程序、H5、RN等

1、入门

1.1、安装 CLI 及项目初始化

npm install -g @tarojs/cli
taro init 项目名
Taro初始化项目.png

可以选择使用 SCSS 、TS、Redux

1.2、编译至各种平台

// 编译为小程序
npm run dev:weapp
npm run build:weapp
// 编译为 H5
npm run dev:h5
// 编译为 RN
npm run dev:rn

编译为小程序时,小程序代码位于 dist 目录下

1.3、微信小程序须知

  • 小程序注册
    注册地址,注意一个邮箱只能注册一个小程序
  • 小程序后台
    后台地址,后台可查看当前小程序版本,添加开发者,查看小程序 AppID 和 AppSecret 等功能
  • 小程序开发者工具
    下载地址
  • 小程序开发流程
    1、在开发者工具中新建项目,填入对应的AppID
    2、在小程序后台配置服务器域名(开发-服务器域名)
  • 小程序发布流程
    1、在开发者工具中上传代码
    2、在管理后台-版本管理-开发版本中提交审核,注意提交审核前可先生成体验版,确认体验版没问题后再提交审核

2、注意点

-由于 Taro 编译后的代码已经经过了转义和压缩,因此还需要注意微信开发者工具的项目设置


微信开发者工具配置.png
  • 只能在render里使用JSX语法
  • 不能在包含 JSX 元素的 map 循环中使用 if 表达式
    尽量在 map 循环中使用条件表达式或逻辑表达式
  • 不能使用 Array.map 之外的方法操作 JSX 数组
    先处理好需要遍历的数组,然后再用处理好的数组调用 map 方法。
  • 不能在 JSX 参数中使用匿名函数
    使用 bind类参数绑定函数。
  • 不能在 JSX 参数中使用对象展开符
    开发者自行赋值:
<View {...props} />  // wrong
<View id={id} title={title} />  // ok
  • 不允许在 JSX 参数(props)中传入 JSX 元素
  • 不支持无状态组件(Stateless Component)
  • 函数名驼峰,且不能包含数字,不能以下划线开始或结尾以及长度不超过20
  • 必须使用单引号,不支持双引号
  • 对于process.env,建议直接书写process.env.NODE_ENV,而不是解构
  • 组件传递函数属性名以 on 开头
  • 小程序端不要将在模板中用到的数据设置为 undefined
  • 小程序端不要在组件中打印 this.props.children
  • 组件属性传递注意
    不要以 id、class、style 作为自定义组件的属性与内部 state 的名称,因为这些属性名在微信小程序中会丢失。
  • 组件 state 与 props 里字段重名的问题
    不要在 state 与 props 上用同名的字段,因为这些被字段在微信小程序中都会挂在 data 上。
  • 小程序中页面生命周期 componentWillMount 不一致问题
  • 组件的 constructor 与 render 提前调用

3、Taro实战

3.1、相关库介绍

  • @tarojs/taro
    taro 核心库,相当于 react
import Taro, { Component } from '@tarojs/taro'
class App extends Component {}
Taro.render(<App />, document.getElementById('app'))
  • @tarojs/redux
    taro 状态管理辅助库,相当于 react-redux
import { Provider,connect  } from '@tarojs/redux'
  • @tarojs/components
    taro 为屏蔽多端差异而制定的标准组件库,在taro中不能直接写常规的HTML标签,而必须用这个组件库里的标签,就像写RN一样:
import { View, Button, Text } from "@tarojs/components";
<View className='index'>
   <Button className='add_btn' onClick={this.props.add}>
       +
   </Button>
   <Text> Hello, World </Text>
</View>
  • @tarojs/async-await
    taro 支持 async await 写法库
  • taro-ui
    taro 为屏蔽多端差异而制定的业务组件库,比如 Tabs,Modal,Menu之类的常用的业务组件
     import { AtTabs, AtTabsPane } from "taro-ui";
     <AtTabs
        current={this.state.current}
        tabList={tabList}
        onClick={this.handleClick.bind(this)}
      >
        <AtTabsPane current={this.state.current} index={0}>
          <AllContainer />
        </AtTabsPane>
        <AtTabsPane current={this.state.current} index={1}>
          <View style='padding: 100px 50px;background-color: #FAFBFC;text-align: center;'>
            标签页二的内容
          </View>
        </AtTabsPane>
        <AtTabsPane current={this.state.current} index={2}>
          <View style='padding: 100px 50px;background-color: #FAFBFC;text-align: center;'>
            标签页三的内容
          </View>
        </AtTabsPane>
      </AtTabs>

3.2、常用工具类封装

  • 本地存储
import Taro from "@tarojs/taro";

class Store {
  removeItem(key) {
    return Taro.removeStorageSync(key);
  }
  getItem(key) {
    return Taro.getStorageSync(key);
  }
  setItem(key, value) {
    return Taro.setStorageSync(key, value);
  }
  clear() {
    return Taro.clearStorageSync();
  }
}

export default  new Store();
  • 请求封装
import Taro from '@tarojs/taro'
import {
  API_USER_LOGIN
} from '@constants/api'

const CODE_SUCCESS = '200'
const CODE_AUTH_EXPIRED = '600'

function getStorage(key) {
  return Taro.getStorage({
    key
  }).then(res => res.data).catch(() => '')
}

function updateStorage(data = {}) {
  return Promise.all([
    Taro.setStorage({
      key: 'token',
      data: data['3rdSession'] || ''
    }),
    Taro.setStorage({
      key: 'uid',
      data: data['uid'] || ''
    })
  ])
}

/**
 * 简易封装网络请求
 * // NOTE 需要注意 RN 不支持 *StorageSync,此处用 async/await 解决
 * @param {*} options
 */
export default async function fetch(options) {
  const {
    url,
    payload,
    method = 'GET',
    showToast = true
  } = options
  const token = await getStorage('token')
  const header = token ? {
    'WX-PIN-SESSION': token,
    'X-WX-3RD-Session': token
  } : {}
  if (method === 'POST') {
    header['content-type'] = 'application/json'
  }

  return Taro.request({
    url,
    method,
    data: payload,
    header
  }).then(async (res) => {
    const {
      code,
      data
    } = res.data
    if (code !== CODE_SUCCESS) {
      if (code === CODE_AUTH_EXPIRED) {
        await updateStorage({})
      }
      return Promise.reject(res.data)
    }

    if (url === API_USER_LOGIN) {
      await updateStorage(data)
    }
    return data
  }).catch((err) => {
    const defaultMsg = err.code === CODE_AUTH_EXPIRED ? '登录失效' : '请求异常'
    if (showToast) {
      Taro.showToast({
        title: err && err.errorMsg || defaultMsg,
        icon: 'none'
      })
    }

    return Promise.reject({
      message: defaultMsg,
      ...err
    })
  })
}

3.3 常用API介绍

  • 授权
<Button
   className='btn-max-w'
   plain
   type='primary'
   open-type='getUserInfo'
   onGetUserInfo={this.handleUserInfo}
>
    授权
</Button>
  • 获取位置
Taro.getLocation({type:'gcj02 '}).then(data=>console.log(data))
  • 操作反馈
   Taro.showToast({
      title: "成功",
      icon: "success"
    });

    Taro.setTabBarBadge({ index: 1, text: "1" });

    Taro.showLoading({
      title: "加载中..."
    }).then(res =>
      setTimeout(() => {
        Taro.hideLoading();
      }, 2000)
    );

4、其他问题记录

  • 设置页面全屏
// app.scss
page {
  height: 100%;
}
  • Css Modules 支持
    配置 config/index.js 下的 h5 和 weapp 中的 module.cssModules 即可
        // css modules 功能开关与相关配置
        cssModules: {
          enable: true, // 默认为 false,如需使用 css modules 功能,则设为 true
          config: {
            namingPattern: 'module', // 转换模式,取值为 global/module,下文详细说明
            generateScopedName: '[name]__[local]___[hash:base64:5]'
          }
        }
  • 配置路径别名
    配置 config/index.js 下的 alias
alias: {
    'components': path.resolve(__dirname, '..', 'src/components'),
    'pages': path.resolve(__dirname, '..', 'src/pages'),
    'store': path.resolve(__dirname, '..', 'src/store'),
    'constants': path.resolve(__dirname, '..', 'src/constants'),
    'api': path.resolve(__dirname, '..', 'src/api'),
    'assets': path.resolve(__dirname, '..', 'src/assets'),
    'utils': path.resolve(__dirname, '..', 'src/utils'),
  },

4、个人开发的 TaroCnode 小程序

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

推荐阅读更多精彩内容