参考

最佳实践:https://taro-docs.jd.com/taro/docs/best-practice
性能优化:https://taro-docs.jd.com/taro/docs/optimized

官方规范:

组件传递函数属性名以 on 开头

在 v1.3.0-beta.0 之后,自定义组件间的事件传递可以不用 on 开头,但内置组件的事件依然是以 on 开头的,为了一致性我们仍然推荐你以 on 开头命名你的事件。
在 Taro 中,父组件要往子组件传递函数,属性名必须以 on 开头

  1. // 调用 Custom 组件,传入 handleEvent 函数,属性名为 onTrigger
  2. class Parent extends Component {
  3. handleEvent () {
  4. }
  5. render () {
  6. return (
  7. <Custom onTrigger={this.handleEvent}></Custom>
  8. )
  9. }
  10. }

这是因为,微信小程序端组件化是不能直接传递函数类型给子组件的,在 Taro 中是借助组件的事件机制来实现这一特性,而小程序中传入事件的时候属性名写法为 bindmyevent 或者 bind:myevent

  1. <!-- 当自定义组件触发 myevent 事件时,调用 onMyEvent 方法 -->
  2. <component-tag-name bindmyevent="onMyEvent" />
  3. <!-- 或者可以写成 -->
  4. <component-tag-name bind:myevent="onMyEvent" />

所以 Taro 中约定组件传递函数属性名以 on 开头,同时这也和内置组件的事件绑定写法保持一致了。

小程序端不要将在模板中用到的数据设置为 undefined

由于小程序不支持将 data 中任何一项的 value 设为 undefined ,在 setState 的时候也请避免这么用。你可以使用 null 来替代。

小程序端不要在组件中打印 this.props.children

在微信小程序端是通过 来实现往自定义组件中传入元素的,而 Taro 利用 this.props.children 在编译时实现了这一功能, this.props.children 会直接被编译成 标签,所以它在小程序端属于语法糖的存在,请不要在组件中打印它。

props 传入 JSX属性名必须以 render 开头

例如,子组件写法

  1. class Dialog extends Component {
  2. render () {
  3. return (
  4. <View className='dialog'>
  5. <View className='header'>
  6. {this.props.renderHeader}
  7. </View>
  8. <View className='body'>
  9. {this.props.children}
  10. </View>
  11. <View className='footer'>
  12. {this.props.renderFooter}
  13. </View>
  14. </View>
  15. )
  16. }
  17. }

父组件调用子组件是传入 JSX

  1. class App extends Component {
  2. render () {
  3. return (
  4. <View className='container'>
  5. <Dialog
  6. renderHeader={
  7. <View className='welcome-message'>Welcome!</View>
  8. }
  9. renderFooter={
  10. <Button className='close'>Close</Button>
  11. }
  12. >
  13. <View className="dialog-message">
  14. Thank you for using Taro.
  15. </View>
  16. </Dialog>
  17. </View>
  18. )
  19. }
  20. }

组件属性传递注意

不要以 id、class、style 作为自定义组件的属性与内部 state 的名称,因为这些属性名在微信小程序小程序中会丢失。

组件 state 与 props 里字段重名的问题

不要在 state 与 props 上用同名的字段,因为这些字段在微信小程序中都会挂在 data 上。

小程序中页面生命周期 componentWillMount 不一致问题

由于微信小程序里页面在 onLoad 时才能拿到页面的路由参数,而页面 onLoad 前组件都已经 attached 了。因此页面的 componentWillMount 可能会与预期不太一致。例如:

  1. // 错误写法
  2. render () {
  3. // 在 willMount 之前无法拿到路由参数
  4. const abc = this.$router.params.abc
  5. return <Custom adc={abc} />
  6. }
  7. // 正确写法
  8. componentWillMount () {
  9. const abc = this.$router.params.abc
  10. this.setState({
  11. abc
  12. })
  13. }
  14. render () {
  15. // 增加一个兼容判断
  16. return this.state.abc && <Custom adc={abc} />
  17. }

对于不需要等到页面 willMount 之后取路由参数的页面则没有任何影响。

JS 编码必须用单引号

在 Taro 中,JS 代码里必须书写单引号,特别是 JSX 中,如果出现双引号,可能会导致编译错误。

环境变量 process.env 的使用

不要以解构的方式来获取通过 env 配置的 process.env 环境变量,请直接以完整书写的方式 process.env.NODE_ENV 来进行使用

  1. // 错误写法,不支持
  2. const { NODE_ENV = 'development' } = process.env
  3. if (NODE_ENV === 'development') {
  4. ...
  5. }
  6. // 正确写法
  7. if (process.env.NODE_ENV === 'development') {
  8. }

自定义组件样式不能写在外部

微信小程序的自定义组件样式默认是不能受外部样式影响的,例如在页面中引用了一个自定义组件,在页面样式中直接写自定义组件元素的样式是无法生效的。这一点,在 Taro 中也是一样,而这也是与大家认知的传统 Web 开发不太一样。

补充:

页面结构比较复杂使用CustomWrapper优化性能

  1. import { View, Text, CustomWrapper } from '@tarojs/components'
  2. export default function () {
  3. return (
  4. <View className='index'>
  5. <Text>Demo</Text>
  6. <CustomWrapper>
  7. <GoodsList />
  8. </CustomWrapper>
  9. </View>
  10. )
  11. }

多个包含ifrmae的页面跳转,需要清除iframe

主要是taro跳转页面的时候,还会保留上一个页面的dom元素,只是display为none了,iframe不清除,会多一层历史记录。

使用scrollview自带的滚动

错误写法:
image.png

matchMedia代替手动判断

  1. //bad
  2. {
  3. height>=400 && orientation==='landscape' && <View>...
  4. }
  5. //good
  6. <MatchMedia minHeight="400" orientation="landscape">
  7. <view>当页面高度不小于 400 px 且屏幕方向为纵向时展示这里</view>
  8. </MatchMedia>

数据量较大时,使用跳转预加载

  1. // A 页面
  2. // 调用跳转方法前使用 Taro.preload
  3. Taro.preload(fetchSomething())
  4. Taro.navigateTo({ url: '/pages/B/B' })
  5. // B 页面
  6. componentWillMount () {
  7. console.log(Taro.getCurrentInstance().preloadData)
  8. }

taro3.1之前版本,删除楼层节点需要隔离

  1. //bad
  2. <View>
  3. <!-- 轮播 -->
  4. <Slider />
  5. <!-- 商品组 -->
  6. <Goods />
  7. <!-- 模态弹窗 -->
  8. {isShowModal && <Modal />}
  9. </View>
  10. //good
  11. <View>
  12. <!-- 轮播 -->
  13. <Slider />
  14. <!-- 商品组 -->
  15. <Goods />
  16. <!-- 模态弹窗 -->
  17. <View>
  18. {isShowModal && <Modal />}
  19. </View>
  20. </View>

基础组件的属性要保持引用

  1. //bad
  2. <Map
  3. latitude={22.53332}
  4. longitude={113.93041}
  5. markers={[{
  6. latitude: 22.53332,
  7. longitude: 113.93041
  8. }]}
  9. />
  10. //good
  11. <Map
  12. latitude={22.53332}
  13. longitude={113.93041}
  14. markers={this.state.markers}
  15. />

基础组件不要设置非标准的属性

  1. //bad
  2. <Text something='extra' />

滑动蒙层、弹窗等覆盖式元素防止滚动穿透

解决办法:

1) 使用样式解决(推荐)
给需要禁用滚动的组件写一个样式,类似于:

  1. {
  2. overflowhidden;
  3. height: 100vh;
  4. }

2) catchMove
对于 Map 等极个别组件,使用样式固定宽高也无法阻止滚动,因为这些组件本身就具有滚动的能力。所以第一种办法处理不了冒泡到 Map 组件上的滚动事件。
这时候可以为 View 组件增加 catchMove 属性:

  1. // 这个 View 组件会绑定 catchtouchmove 事件而不是 bindtouchmove
  2. <View catchMove />

不要频繁调用Taro.getCurrentInstance() ,将结果保存下来

  1. class Index extends React.Component {
  2. inst = Taro.getCurrentInstance()
  3. componentDidMount () {
  4. console.log(this.inst)
  5. }
  6. }