Taro实战

本文的示例代码参考hello-taro

目录

准备

安装

1
2
3
4
5
6
7
node -v
# v12.14.1

cnpm i -g @tarojs/cli

taro -v
# 3.0.17

初始化

1
2
3
4
5
6
7
8
9
10
11
12
taro init hello-taro
# ? 请输入项目介绍!
# ? 请选择框架 React
# ? 是否需要使用 TypeScript ? No
# ? 请选择 CSS 预处理器(Sass/Less/Stylus) Sass
# ? 请选择模板源 Gitee(最快)
# ✔ 拉取远程模板仓库成功!
# ? 请选择模板 taro-ui

cd hello-taro

cnpm run dev:h5

小程序

1
cnpm run dev:weapp
  • 微信开发者工具 => 导入项目 => hello-taro/dist

登录页

1
mkdir src/pages/login/
1
vim src/pages/login/index.jsx
1
2
3
4
5
6
7
8
9
10
11
12
import React, { Component } from 'react'
import { View, Text } from '@tarojs/components'

export default class Index extends Component {
render() {
return (
<View className='index'>
<Text>登录页面</Text>
</View>
)
}
}
1
vim src/pages/login/index.config.js
1
2
3
export default {
navigationBarTitleText: '登录'
}
1
vim src/app.config.js
1
2
3
4
5
6
7
export default {
pages: [
'pages/index/index',
'pages/login/index'
],
// 省略未修改代码
}
1
vim src/pages/index/index.jsx
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
import React from 'react'
import { View } from '@tarojs/components'
import Taro from '@tarojs/taro'
import { AtButton } from 'taro-ui'

import "taro-ui/dist/style/components/button.scss" // 按需引入

export default function Index() {
return (
<View className='index'>
<AtButton type='primary' onClick={() => {
Taro.navigateTo({
url: '/pages/login/index'
})
}}>登录</AtButton>
</View>
)
}

状态管理

1
vim src/pages/login/index.jsx
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
import React, { useState } from 'react'
import { View, Text } from '@tarojs/components'
import { AtButton, AtInput } from 'taro-ui'

import "taro-ui/dist/style/components/input.scss"
import "taro-ui/dist/style/components/button.scss"

export default function Login() {
const [username, setUsername] = useState()
const [password, setPassword] = useState()

const handleUsernameChange = (value) => {
setUsername(value)
}

const handlePasswordChange = (value) => {
setPassword(value)
}

const handleLogin = () => {
console.log('login onclick')
}

return (
<View className='index'>
<AtInput
name='username'
title='用户名'
type='text'
placeholder='请输入用户名'
value={username}
onChange={handleUsernameChange}
/>
<AtInput
name='password'
title='密码'
type='password'
placeholder='请输入密码'
value={password}
onChange={handlePasswordChange}
/>
<AtButton
type='primary'
size='normal'
onClick={handleLogin}
>
登录
</AtButton>
<Text>{username} | {password}</Text>
</View >
)
}
1
2
3
cnpm i --save dva-core dva-loading redux react-redux redux-logger

mdkir src/utils src/models
1
vim src/utils/dva.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
import { create } from 'dva-core'
import createLoading from 'dva-loading'
import { createLogger } from 'redux-logger'

let app, store, dispatch, registered

function createApp(options) {
options.onAction = [createLogger()]

app = create(options)
app.use(createLoading({}))

if (!global.registered) {
options.models.forEach(model => app.model(model))
}
registered = true
app.start()

store = app._store
app.getStore = () => store

dispatch = store.dispatch
app.getDispatch = () => dispatch

return app
}

export default { createApp }
1
vim src/models/login.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
const namespace = 'login'

export default {
namespace,
state: {
count: 0
},
reducers: {
overrideStateProps(state, { payload }) {
return {
...state,
...payload
}
}
},
}
1
vim src/models/index.js
1
2
3
import login from './login'

export default [login]
1
vim src/app.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
import React, { Component } from 'react'
import { Provider } from 'react-redux'
import dva from './utils/dva'
import models from './models'

import './app.scss'

const dvaApp = dva.createApp({
initialState: {},
models: models
})

const store = dvaApp.getStore()

class App extends Component {
render() {
return <Provider store={store}>{this.props.children}</Provider>
}
}

export default App
1
vim src/pages/login/index.jsx
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
// 省略未修改代码
import { useDispatch, useSelector } from 'react-redux'

export default function Login() {
const dispatch = useDispatch()
const { count } = useSelector(store => store.login)

// 省略未修改代码

const handleLogin = () => {
dispatch({
type: 'login/overrideStateProps',
payload: {
count: count + 1
}
})
}

return (
<View className='index'>
// 省略未修改代码
<Text>{username} | {password} | {count}</Text>
</View >
)
}

请求接口

1
vim src/utils/request.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
import Taro from '@tarojs/taro'

export default (options = { method: 'GET', data: {}, url: '' }) => {
return Taro.request({
url: options.url,
data: {
...options.data
},
header: {
'Content-Type': 'application/json'
},
method: options.method.toUpperCase()
}).then(res => res.data)
}
1
2
3
mkdir src/services

vim src/services/login.js
1
2
3
4
5
6
7
8
9
10
11
12
13
import request from '../utils/request'

export default class Login {
static login(params) {
return request({
url: 'http://test.nuozhilin.site/demo/login',
method: 'POST',
data: {
...params
}
})
}
}
1
vim src/models/login.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
import Login from '../services/login'
import Taro from '@tarojs/taro'

// 省略未修改代码

export default {
// 省略未修改代码
effects: {
*login({ payload }, { call }) {
const { username, password } = payload
const response = yield call(Login.login, { username, password })
if (response.code === 0) {
Taro.showToast({
title: '登录成功',
icon: 'none'
})
} else {
Taro.showToast({
title: '密码错误',
icon: 'none'
})
}
}
}
}
1
vim src/pages/login/index.jsx
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
// 省略未修改代码

export default function Login() {
// 省略未修改代码

const handleLogin = () => {
dispatch({
type: 'login/overrideStateProps',
payload: {
count: count + 1
}
})
dispatch({
type: 'login/login',
payload: {
username,
password
}
})
}

// 省略未修改代码
}

参考