Taro踩坑实践

7,723 阅读3分钟

背景

快狗合伙人技术部,在去年使用 Taro开发了两个微信小程序,现在均已上线。开发过程中也遇到了一些大大小小的问题,下面列出几个比较典型的,供在使用或者已经使用但是还没有遇到的同学做个参考。

使用 Mobx 的列表渲染

使用 Mobx 包装过的数组类型,要slice()一下,否则会导致列表渲染不成功。

// store.js
import { observable, action } from 'mobx'

class ListStore {
    @observable listData = []
    
    ...
}

export default new ListStore()

// List.jsx

import Taro, { Component } from '@tarojs/taro'
import { observer, inject } from '@tarojs/mobx'

@inject('ListStore')
@observer
export default class List extends Component {
    ...
    
   
    render() {
        let list = this.props.ListStore.listData
    
        list.slice()
        
        const renderList = list && list.map((item) => (<View>{item.name}</View>))

        return (
            <View>{renderList}</View>
        )
    }
}

微信小程序手机号码授权

在微信小程序手机号码授权登录使用onGetPhoneNumber获取否则获取实现不了。

export default class login extends Component {

    getPhoneNumber(event) {
 
    }
 
    render() {
        return (
            <Button  openType='getPhoneNumber' onGetPhoneNumber="this.onGetPhoneNumberHandler.bind(this)">获取手机号</Button>
        )
    }
}

条件编译

Taro 最方便的一点就是支持条件编译,使用Taro特定的文件命名方式就能实现,但是只是在Js方面支持,并不支持在 config 的 pages 选项去用。

// src/set_title

// set_title.h5.js

/**
 * H5 设置页面title
 * @param {String} title
 */
export default function setTitle (title) {
  document.title = title
}


// set_title.weapp.js

import Taro from '@tarojs/taro'

export default function setTitle (title) {
  Taro.setNavigationBarTitle({ title })
}

使用

import setTitle from src/set_title

export default class MobileLogin extends Component {
  
    ...
    
    componentWillMount () {
        setTitle('标题')
    }
  
    render() {
        return (<View />)
    }
}

条件编译虽然好使,但是在app.js里面对页面使用是不可以的,例如你想定制支付宝小程序跟微信小程序通过同一个路径去访问不同的页面,只能通过在页面内部,通过代码进行逻辑判断实现。

// app.js

config = {
    pages: [
        // 只能是具体的文件
        'pages/Home/index',
        'pages/List/index'
    ]
}

版本问题

之前有个此,初始化项目的时候,没有使用 @taro/Mobx 的模板初始化,而是后来单独装的,导致在ios低版本(ios9)上页面显示异常。原因是使用的 mobx 版本太新,应该使用 mobx@4.8.0。

// package.json

{
    "dependencies": {
        "@tarojs/mobx": "1.3.19",
        "@tarojs/mobx-h5": "1.3.19",
        "@tarojs/mobx-rn": "1.3.19",
        "mobx": "4.8.0",
        ...
    }
}

注意: 需要特别注意的是本地全局安装的taro-cli项目中依赖的@tarojs相关版本号必须一致,之前有小伙伴出现本地Taro版本很新,拉下代码之后,运行项目不成功,这个很坑。

环境变量

通常项目会运行在多个环境,每个环境有一份对应的配置,如接口服务,如果能在编译的时候自动生成那是最好不过的了,那么如何能在 Taro 中使用。

安装 cross-env 设置环境变量,然后修改package.json

// package.json
...
"scripts": {
    "test:weapp": "cross-env APP_NS=test npm run build:weapp",
    "sandbox:weapp": "cross-env APP_NS=sandbox npm run build:weapp",
    "online:weapp": "cross-env APP_NS=online npm run build:weapp"
    ...
}

修改 Taro 生产环境的配置,只有执行 npm run build:xx 的时候,才会执行此文件的代码,也就是说,在 npm run dev:xx 的时候其实是不受影响的,所以本地开发环境,APP_NS 没有做设置。

// config/prod.js

const APP_NS = JSON.stringify(process.env.APP_NS);

module.exports = {
  env: {
    NODE_ENV: '"production"',
    APP_NS: `${APP_NS}`
  },
  ...
}

这样每次在打包的时候,就能区分出环境了,通过环境设置的环境变量APP_NS的值,就能在编译的时候取到对应字符串,进行区分当前是什么环境的资源包。

// src/api.js

const _env = process.env.APP_NS

const oUrl = {
    test: 'https://test.suyun.com',
    sandbox: 'https://sandbox.suyun.com',
    online: 'https://online.suyun.com'
}

export const baseUrl = oUrl[_env] || '/api'

Mock 数据

本地开发,自己编写服务器,数据格式自己定义,使用Mockjs 实现,作为本地的一个单独的服务器使用。

// mock/server.js

/**
 * mock 服务器
 */

const express = require('express')
const apiMocker = require('mocker-api')
const Mock = require('mockjs')

const mock = Mock.mock;

const PORT = 3000

const app = express();

const mocker = {
    'GET /list': mock({
        "code": 0,
        "message": 'success',
        "data|10": [
            {
                "sid": "@id",
                "name": "@cname",
                "photo": "@image",
            }
        ]
    })
}


apiMocker(app, mocker)

app.listen(PORT, () => {
  console.log(`Mock Server listening on http://localhost:${PORT}`)
});

修改 package.js 脚本命令

"scripts": {
    "mock": "node ./mock/mock-server.js",
    ...
}

添加mock数据也可以单独放在一个文件中,方便维护。

// mocker.js

const Mock = require('mockjs');

const mock = Mock.mock;

const mocker = {
    'GET /list': mock({
        "code": 0,
        "message": 'success',
        "data|10": [
            {
                "sid": "@id",
                "name": "@cname",
                "photo": "@image",
            }
        ]
    })
}

module.exports = mocker

关注我们

关注公众号前端论道