最近一直在學習taro,網上搜的重點知識總結不多,因此想着本身寫一篇我以爲比較重要的知識點總結一下。css
如下文件組織規範爲最佳實踐的建議html
全部項目源代碼請放在項目根目錄 src
目錄下,項目所需最基本的文件包括 入口文件 以及 頁面文件react
app.js
src/pages
目錄下一個可靠的 Taro 項目能夠按照以下方式進行組織json
├── 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 中普通 JS/TS 文件以小寫字母命名,多個單詞如下劃線鏈接,例如 util.js
、util_helper.js
小程序
Taro 組件文件命名遵循 Pascal 命名法,例如 ReservationCard.jsx
微信小程序
taro的書寫規範大概和Eslint的規範相似,具體可參考官網連接:taro-docs.jd.com/taro/docs/s…數組
在 Taro 組件中會包含類靜態屬性、類屬性、生命週期等的類成員,其書寫順序最好遵循如下約定(順序從上至下)bash
onClickSubmit()
或者 onChangeDescription()
import Taro, { Component } from '@tarojs/taro'
import { View, Input } from '@tarojs/components'
class MyComponent extends Component {
state = {
myTime: 12
}
render () {
const { isEnable } = this.props // ✓ 正確
const { myTime } = this.state // ✓ 正確
return (
<View className='test'>
{isEnable && <Text className='test_text'>{myTime}</Text>}
</View>
)
}
}複製代碼
因爲 this.setState 異步的緣故,這樣的作法會致使一些錯誤,能夠經過給 this.setState 傳入函數來避免微信
this.setState({
value: this.state.value + 1
}) // ✗ 錯誤
this.setState(prevState => ({ value: prevState.value + 1 })) // ✓ 正確複製代碼
list.map(item => {
return (
<View className='list_item' key={item.id}>{item.name}</View>
)
})複製代碼
由於在
componentDidMount
中調用this.setState
會致使觸發更新app
import Taro, { Component } from '@tarojs/taro'
import { View, Input } from '@tarojs/components'
class MyComponent extends Component {
state = {
myTime: 12
}
componentDidMount () {
this.setState({ // ✗ 儘可能避免,能夠在 componentWillMount 中處理
name: 1
})
}
render () {
const { isEnable } = this.props
const { myTime } = this.state
return (
<View className='test'>
{isEnable && <Text className='test_text'>{myTime}</Text>}
</View>
)
}
}
複製代碼
import Taro, { Component } from '@tarojs/taro'
import { View, Input } from '@tarojs/components'
class MyComponent extends Component {
state = {
myTime: 12
}
componentWillUpdate () {
this.setState({ // ✗ 錯誤
name: 1
})
}
componentDidUpdate () {
this.setState({ // ✗ 錯誤
name: 1
})
}
render () {
const { isEnable } = this.props
const { myTime } = this.state
this.setState({ // ✗ 錯誤
name: 11
})
return (
<View className='test'>
{isEnable && <Text className='test_text'>{myTime}</Text>}
</View>
)
}
}複製代碼
在 Taro 中全部默認事件如
onClick
、onTouchStart
等等,均以on
開頭
import Taro, { Component } from '@tarojs/taro'
import { View, Input } from '@tarojs/components'
class MyComponent extends Component {
state = {
myTime: 12
}
clickHandler (e) {
console.log(e)
}
render () {
const { myTime } = this.state
return (
<View className='test' onClick={this.clickHandler}> // ✓ 正確
<Text className='test_text'>{myTime}</Text>
</View>
)
}
}複製代碼
Taro 在小程序端實際上把 JSX 轉換成了字符串模板,而一個原生 JSX 表達式其實是一個 React/Nerv 元素(react-element)的構造器,所以在原生 JSX 中你能夠隨意地對一組 React 元素進行操做。但在 Taro 中你只能使用
map
方法,Taro 轉換成小程序中wx:for
在 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
組件能夠將 UI 切分紅一些的獨立的、可複用的部件,這樣你就只需專一於構建每個單獨的部件。
組件從概念上看就像是函數,它能夠接收任意的輸入值(稱之爲 props
),並返回一個須要在頁面上展現的 Taro 元素。
一個聲明的組件決不能修改它本身的 props
。
隨着應用日漸龐大,你能夠經過類型檢查捕獲大量錯誤。要檢查組件的屬性,你須要配置特殊的 propTypes
屬性:
import PropTypes from 'prop-types';
class Greeting extends Component {
render() {
return (
<h1>Hello, {this.props.name}</h1>
);
}
}
Greeting.propTypes = {
name: PropTypes.string
};複製代碼
關於 setState() 這裏有三件事情須要知道:
例如,此代碼不會從新渲染組件:
// Wrong
this.state.comment = 'Hello'
複製代碼
應當使用 setState()
:
// Correct
this.setState({ comment: 'Hello' })複製代碼
Taro 能夠將多個 setState()
調用合併成一個調用來提升性能。
由於 this.state
和 props
必定是異步更新的,因此你不能在 setState
立刻拿到 state
的值,例如:
// 假設咱們以前設置了 this.state.counter = 0
updateCounter () {
this.setState({
counter: 1
})
console.log(this.state.counter) // 這裏 counter 仍是 0
}
複製代碼
正確的作法是這樣,在 setState
的第二個參數傳入一個 callback:
// 假設咱們以前設置了 this.state.counter = 0
updateCounter () {
this.setState({
counter: 1
}, () => {
// 在這個函數內你能夠拿到 setState 以後的值
})
}複製代碼
當你調用 setState()
,Taro 將合併你提供的對象到當前的狀態中。
例如,你的狀態可能包含幾個獨立的變量:
constructor(props) {
super(props)
this.state = {
posts: [],
comments: []
}
}
複製代碼
而後經過調用獨立的 setState()
調用分別更新它們:
componentDidMount() {
fetchPosts().then(response => {
this.setState({
posts: response.posts
});
});
fetchComments().then(response => {
this.setState({
comments: response.comments
})
})
}
複製代碼
合併是淺合併,因此 this.setState({comments})
不會改變 this.state.posts
的值,但會徹底替換 this.state.comments
的值。
有時渲染的條件很是多,不論是 if-else
仍是 switch-case
來作條件渲染都會顯得太麻煩。這時咱們可使用「表驅動法」:枚舉渲染。
function Loading (props) {
const { loadingText, LOADING_STATUS, loadingStatus, onRetry } = props
return (
<View className='loading-status'>
{
{
'loading': loadingText,
'fail': <View onClick={onRetry}> 加載失敗, 點擊重試 </View>,
'no-more': '沒有更多了'
}[loadingStatus] /** loadingStatus 是 `loading`、`fail`、`no-more` 其中一種狀態 **/
}
</View>
)
}複製代碼
下面,咱們使用 JavaScript 中的 map()
方法遍歷 numbers
數組。對數組中的每一個元素返回 <Text>
標籤,最後咱們獲得一個數組 listItems
:
const numbers = [...Array(100).keys()] // [0, 1, 2, ..., 98, 99]
const listItems = numbers.map((number) => {
return <Text className='li'> 我是第 {number + 1} 個數字</Text>
})
複製代碼
這段代碼生成了一個 1 到 100 的數字列表。
可是在上面的代碼,你會獲得一個報錯:提醒你當循環一個數組時應該提供 keys。Keys 能夠在 DOM 中的某些元素被增長或刪除的時候幫助 Nerv/小程序 識別哪些元素髮生了變化。所以你應當給數組中的每個元素賦予一個肯定的標識。
taroKey
適用於循環渲染原生小程序組件,賦予每一個元素惟一肯定標識,轉換爲小程序的 wx:key
。
數組元素中使用的 key 在其兄弟之間應該是獨一無二的。然而,它們不須要是全局惟一的。當咱們生成兩個不一樣的數組時,咱們可使用相同的 key
自
v1.3.0-beta.0
起支持
因爲一個文件不能定義兩個組件,但有時候咱們須要組件內部的抽象組件,這時類函數式組件就是你想要答案。假設咱們有一個 Class 組件,它包括了一個 Header
一個 Footer
,咱們能夠這樣定義:
class SomePage extends Taro.Component {
renderHeader () {
const { header } = this.state
return <View>{header}</View>
}
renderFooter (footer) {
return <View>{footer}</View>
}
render () {
return (
<View>
{this.renderHeader()}
{...}
{this.renderFooter('footer')}
</View>
)
}
}
複製代碼
在 renderHeader
或 renderFooter
函數中,咱們能夠訪問類的 this
,也能夠傳入不限量的參數,這類型的函數也能夠調用無限次數。但這樣的寫法也存在一些限制:
render
開頭,render
後的第一個字母須要大寫Sidebar
和 Dialog
這樣的容器組件。咱們建議在這樣的狀況使用 this.props.children
來傳遞子元素:
class Dialog extends Component {
render () {
return (
<View className='dialog'>
<View className='header'>Welcome!</View>
<View className='body'>
{this.props.children}
</View>
<View className='footer'>-- divider --</View>
</View>
)
}
}
複製代碼
這樣就能容許其它組件在 JSX 中嵌套任意子組件傳遞給 Dialog
:
class App extends Component {
render () {
return (
<View className='container'>
<Dialog>
<View className="dialog-message">
Thank you for using Taro.
</View>
</Dialog>
</View>
)
}
}
複製代碼
在 <Dialog />
JSX 標籤內的任何內容都會做爲它的子元素(Children)都會傳遞到它的組件。
請不要對 this.props.children
進行任何操做。Taro 在小程序中實現這個功能使用的是小程序的 slot
功能,也就是說你能夠把 this.props.children
理解爲 slot
的語法糖,this.props.children
在 Taro 中並非 React 的 ReactElement
對象,所以形如 this.props.children && this.props.children
、this.props.children[0]
在 Taro 中都是非法的。
this.props.children
沒法用 defaultProps
設置默認內容。因爲小程序的限制,Taro 也沒法知道組件的消費者是否傳入內容,因此沒法應用默認內容。
不能把 this.props.children
分解爲變量再使用。因爲普通的 props
有一個確切的值,因此當你把它們分解爲變量運行時能夠處理,this.props.children
則不能這樣操做,你必須顯性地把 this.props.children
所有都寫完整才能實現它的功能。
自
1.1.9
開始支持
有些狀況你不只僅須要只傳遞一個子組件,可能會須要不少個「佔位符」。例如在這個 Dialog
組件中,你不只須要自定義它的 body
,你但願它的 header
和 footer
都是給 Dialog
組件的使用者自由定製。這種狀況能夠這樣作:
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>
)
}
}
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>
)
}
}
複製代碼
在咱們聲明 Dialog
組件時,header
和 footer
部分咱們分別增長了 this.props.renderHeader
和 this.props.renderFooter
做爲佔位符。相應地,咱們在使用 Dialog
組件時,就能夠給 renderHeader
和 renderFooter
傳入 JSX 元素,這兩個分別傳入的 JSX 元素將會填充它們在 Dialog
組件中的位置——就像在 Dialog
JSX 標籤裏寫入的內容,會填充到 this.props.children
的位置同樣。
組件的組合須要遵照 this.props.children
的全部規則。組合這個功能和 this.props.children
同樣是經過 slot
實現的,也就是說 this.props.children
的限制對於組件組合也都一樣適用。
全部組合都必須用 render
開頭,且遵照駝峯式命名法。和咱們的事件規範以 on
開頭同樣,組件組合使用 render
開頭。
組合只能傳入單個 JSX 元素,不能傳入其它任何類型。當你須要進行一些條件判斷或複雜邏輯操做的時候,可使用一個 Block
元素包裹住,而後在 Block
元素的裏面填充其它複雜的邏輯。