参考
最佳实践: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 开头
// 调用 Custom 组件,传入 handleEvent 函数,属性名为 onTrigger
class Parent extends Component {
handleEvent () {
}
render () {
return (
<Custom onTrigger={this.handleEvent}></Custom>
)
}
}
这是因为,微信小程序端组件化是不能直接传递函数类型给子组件的,在 Taro 中是借助组件的事件机制来实现这一特性,而小程序中传入事件的时候属性名写法为 bindmyevent 或者 bind:myevent
<!-- 当自定义组件触发 myevent 事件时,调用 onMyEvent 方法 -->
<component-tag-name bindmyevent="onMyEvent" />
<!-- 或者可以写成 -->
<component-tag-name bind:myevent="onMyEvent" />
所以 Taro 中约定组件传递函数属性名以 on 开头,同时这也和内置组件的事件绑定写法保持一致了。
小程序端不要将在模板中用到的数据设置为 undefined
由于小程序不支持将 data 中任何一项的 value 设为 undefined ,在 setState 的时候也请避免这么用。你可以使用 null 来替代。
小程序端不要在组件中打印 this.props.children
在微信小程序端是通过
props 传入 JSX属性名必须以 render 开头
例如,子组件写法
class Dialog extends Component {
render () {
return (
<View className='dialog'>
<View className='header'>
{this.props.renderHeader}
</View>
<View className='body'>
{this.props.children}
</View>
<View className='footer'>
{this.props.renderFooter}
</View>
</View>
)
}
}
父组件调用子组件是传入 JSX
class App extends Component {
render () {
return (
<View className='container'>
<Dialog
renderHeader={
<View className='welcome-message'>Welcome!</View>
}
renderFooter={
<Button className='close'>Close</Button>
}
>
<View className="dialog-message">
Thank you for using Taro.
</View>
</Dialog>
</View>
)
}
}
组件属性传递注意
不要以 id、class、style 作为自定义组件的属性与内部 state 的名称,因为这些属性名在微信小程序小程序中会丢失。
组件 state 与 props 里字段重名的问题
不要在 state 与 props 上用同名的字段,因为这些字段在微信小程序中都会挂在 data 上。
小程序中页面生命周期 componentWillMount 不一致问题
由于微信小程序里页面在 onLoad 时才能拿到页面的路由参数,而页面 onLoad 前组件都已经 attached 了。因此页面的 componentWillMount 可能会与预期不太一致。例如:
// 错误写法
render () {
// 在 willMount 之前无法拿到路由参数
const abc = this.$router.params.abc
return <Custom adc={abc} />
}
// 正确写法
componentWillMount () {
const abc = this.$router.params.abc
this.setState({
abc
})
}
render () {
// 增加一个兼容判断
return this.state.abc && <Custom adc={abc} />
}
对于不需要等到页面 willMount 之后取路由参数的页面则没有任何影响。
JS 编码必须用单引号
在 Taro 中,JS 代码里必须书写单引号,特别是 JSX 中,如果出现双引号,可能会导致编译错误。
环境变量 process.env 的使用
不要以解构的方式来获取通过 env 配置的 process.env 环境变量,请直接以完整书写的方式 process.env.NODE_ENV 来进行使用
// 错误写法,不支持
const { NODE_ENV = 'development' } = process.env
if (NODE_ENV === 'development') {
...
}
// 正确写法
if (process.env.NODE_ENV === 'development') {
}
自定义组件样式不能写在外部
微信小程序的自定义组件样式默认是不能受外部样式影响的,例如在页面中引用了一个自定义组件,在页面样式中直接写自定义组件元素的样式是无法生效的。这一点,在 Taro 中也是一样,而这也是与大家认知的传统 Web 开发不太一样。
补充:
页面结构比较复杂使用CustomWrapper优化性能
import { View, Text, CustomWrapper } from '@tarojs/components'
export default function () {
return (
<View className='index'>
<Text>Demo</Text>
<CustomWrapper>
<GoodsList />
</CustomWrapper>
</View>
)
}
多个包含ifrmae的页面跳转,需要清除iframe
主要是taro跳转页面的时候,还会保留上一个页面的dom元素,只是display为none了,iframe不清除,会多一层历史记录。
使用scrollview自带的滚动
错误写法:
matchMedia代替手动判断
//bad
{
height>=400 && orientation==='landscape' && <View>...
}
//good
<MatchMedia minHeight="400" orientation="landscape">
<view>当页面高度不小于 400 px 且屏幕方向为纵向时展示这里</view>
</MatchMedia>
数据量较大时,使用跳转预加载
// A 页面
// 调用跳转方法前使用 Taro.preload
Taro.preload(fetchSomething())
Taro.navigateTo({ url: '/pages/B/B' })
// B 页面
componentWillMount () {
console.log(Taro.getCurrentInstance().preloadData)
}
taro3.1之前版本,删除楼层节点需要隔离
//bad
<View>
<!-- 轮播 -->
<Slider />
<!-- 商品组 -->
<Goods />
<!-- 模态弹窗 -->
{isShowModal && <Modal />}
</View>
//good
<View>
<!-- 轮播 -->
<Slider />
<!-- 商品组 -->
<Goods />
<!-- 模态弹窗 -->
<View>
{isShowModal && <Modal />}
</View>
</View>
基础组件的属性要保持引用
//bad
<Map
latitude={22.53332}
longitude={113.93041}
markers={[{
latitude: 22.53332,
longitude: 113.93041
}]}
/>
//good
<Map
latitude={22.53332}
longitude={113.93041}
markers={this.state.markers}
/>
基础组件不要设置非标准的属性
//bad
<Text something='extra' />
滑动蒙层、弹窗等覆盖式元素防止滚动穿透
解决办法:
1) 使用样式解决(推荐)
给需要禁用滚动的组件写一个样式,类似于:
{
overflow:hidden;
height: 100vh;
}
2) catchMove
对于 Map 等极个别组件,使用样式固定宽高也无法阻止滚动,因为这些组件本身就具有滚动的能力。所以第一种办法处理不了冒泡到 Map 组件上的滚动事件。
这时候可以为 View 组件增加 catchMove 属性:
// 这个 View 组件会绑定 catchtouchmove 事件而不是 bindtouchmove
<View catchMove />
不要频繁调用Taro.getCurrentInstance() ,将结果保存下来
class Index extends React.Component {
inst = Taro.getCurrentInstance()
componentDidMount () {
console.log(this.inst)
}
}