Taro 介绍 这是 Taro 2.x 版本的文档,若要查看 1.x 版本的文档,请点击这里选择版本。
简介 Taro 是一套遵循 React 语法规范的 多端开发 解决方案。
现如今市面上端的形态多种多样,Web、React-Native、微信小程序等各种端大行其道,当业务要求同时在不同的端都要求有所表现的时候,针对不同的端去编写多套代码的成本显然非常高,这时候只编写一套代码就能够适配到多端的能力就显得极为需要。
使用 Taro,我们可以只书写一套代码,再通过 Taro 的编译工具,将源代码分别编译出可以在不同端(微信/百度/支付宝/字节跳动/QQ/京东小程序、快应用、H5、React-Native 等)运行的代码。
1.安装脚手架
使用 npm 安装 CLI
$ npm install -g @tarojs/cli
OR 使用 yarn 安装 CLI
$ yarn global add @tarojs/cli
OR 安装了 cnpm,使用 cnpm 安装 CLI
$ cnpm install -g @tarojs/cli
2.创建项目
taro init myApp
3.运行项目
- 浏览器端
npm run dev:h5
npm run build:h5
- 微信小程序端
npm run dev:weapp
npm run build:weapp
- 其他类 百度小程序、支付宝小程序、字节跳动、QQ、等。
4.配置路由
pages/home/index.jsx
pages/kind/index.jsx
pages/cart/index.jsx
pages/user/index.jsx
以首页为例
import Taro, { Component } from '@tarojs/taro'
// 为什呢 View 要单独引入,react 说明 组件的首字母一定要大写,小写被当做html标签
import { View } from '@tarojs/components'
class Index extends Component {
render () {
return (
<View>
首页
</View>
)
}
}
export default Index
配置底部选项卡
规范:key值一律不加引号, value只加单引号, key与value值之间需要冒号后加 空格, 图片使用相对路径。
tabBar: {
color: '#333',
selectedColor: '#f66',
backgroundColor: '#efefef',
borderStyle: 'white',
list: [ // 图片资源必须使用 相对路径
{
pagePath: 'pages/home/index',
text: '首页',
iconPath: './resources/home.png',
selectedIconPath: './resources/home_active.png'
},
{
pagePath: 'pages/kind/index',
text: '分类',
iconPath: './resources/kind.png',
selectedIconPath: './resources/kind_active.png'
},
{
pagePath: 'pages/cart/index',
text: '购物车',
iconPath: './resources/cart.png',
selectedIconPath: './resources/cart_active.png'
},
{
pagePath: 'pages/user/index',
text: '我的',
iconPath: './resources/user.png',
selectedIconPath: './resources/user_active.png'
}
]
}
5.页面配置
参考Taro文档地址。
https://taro-docs.jd.com/taro/docs/README.html
6 生命周期钩子函数
全局生命周期钩子函数
// app.jsx
// onLaunch 在微信/百度/字节跳动/支付宝小程序中这一生命周期方法对应 app 的 onLaunch
componentWillMount() {}
// onLaunch 在微信/百度/字节跳动/支付宝小程序中这一生命周期方法对应 app 的 onLaunch,在 componentWillMount 后执行
componentDidMount () {}
// onShow
componentDidShow () {}
// onHide
componentDidHide () {}
// onError
componentDidCatchError () {}
// onPageNotFound 404
componentDidNotFound () {}
页面级生命周期钩子函数
componentWillMount()
页面加载时触发,一个页面只会调用一次,此时页面 DOM 尚未准备好,还不能和视图层进行交互 ----- react一致 --- 一般不使用(以前的react版本支持在此处请求数据,但是现在不建议)
componentDidMount()
页面初次渲染完成时触发,一个页面只会调用一次,代表页面已经准备妥当,可以和视图层进行交互 - react一致 --- 请求数据、DOM操作
shouldComponentUpdate(nextProps, nextState)
页面是否需要更新,返回 false 不继续更新,否则继续走更新流程 --- react 一致 --- 提升react组件性能的关键
componentWillUpdate(nextProps, nextState)
页面即将更新 --- react一致 --- 一般不使用
componentDidUpdate(prevProps, prevState)
页面更新完毕 ---- react一致 --- 可以请求数据但是不建议,如果非要请求,必须得加判断 ---- 不能在此请求数据(错误的) -- https://zh-hans.reactjs.org/docs/react-component.html#componentdidupdate(如果你对更新前后的 props 进行了比较,也可以选择在此处进行网络请求)
其他的函数
onPullDownRefresh()
onReachBottom()
onPageScroll(Object)
onShareAppMessage(Object)
组件生命周期 参考的就是react的生命周期
7.项目首页的相关实现
实现首页轮播图
(轮播图状态、生命周期钩子中请求数据、修改状态、渲染数据)
状态设置
constructor 写了必写 super ,要不就不写 constructor,super事关 this指向的问题 --- es6的构造函数中的机制
constructor (props) {
super(props)
// 1.设置状态
this.state = {
bannerlist: []
}
}
2、请求数据
- 封装数据库的请求 src/utils/index.js
import Taro from '@tarojs/taro'
const baseUrl = '请求的地址'
export function request (options) {
const { url, data, method, header } = options
Taro.showLoading({
title: '加载中'
})
return new Promise((resolve, reject) => {
Taro.request({
url: baseUrl + url,
data: data || {},
method: method || 'GET',
header: header || {},
success: res => {
resolve(res)
},
fail: err => {
reject(err)
},
complete: () => {
Taro.hideLoading()
}
})
})
}
- pages/home/index.jsx 引入请求数据,修改状态
// 2.请求数据
import { request } from './../../utils'
componentDidMount () {
// vue /react axios /fetch ajax
// wx wx.request
// uni uni.request
// taro taro.request
request({
url: '/pro/banner'
}).then(res => {
console.log(res.data)
this.setState({
bannerlist: res.data.data
})
})
}
渲染数据
render () {
return (
<View>
<Swiper indicatorDots autoplay circular>
{
this.state.bannerlist.map((item, index) => (
<SwiperItem key={index}>
<Image className="bannerimg" style={ {width: '100%'} } mode="aspectFit" src={'http://daxun.kuboy.top' + item} />
</SwiperItem>
))
}
</Swiper>
</View>
)
}
实现列表的效果
自定义一个列表组件
// src/components/prolist/index.jsx
import Taro from '@tarojs/taro'
import { View } from '@tarojs/components'
class Index extends Taro.Component {
render () {
return (
<View>
列表
</View>
)
}
}
export default Index
首页引入列表组件测试
import Prolist from './../../components/prolist'
render () {
return (
<View>
<Swiper indicatorDots autoplay circular>
...
</Swiper>
<Prolist />
</View>
)
}
子组件接收数据并且校验数据 先行安装 prop-types 数据校验模块
cnpm i prop-types -S
import Taro from '@tarojs/taro'
import PropTypes from 'prop-types'
import { View, Image } from '@tarojs/components'
import './index.scss'
/**
* 子组件 使用 prop-types 进行数据的校验,校验完毕。
* 在子组件(类组件)通过 this.props.自定义的属性名 就可以访问数据
* 如果组件时函数式组件,通过 props.自定义的属性名 访问数据
*/
class Index extends Taro.Component {
render () {
return (
<View className="prolist">
....
</View>
)
}
}
// 校验数据格式
Index.propTypes = {
prolist: PropTypes.array
}
export default Index
``` 渲染列表数据
import Taro from '@tarojs/taro' import PropTypes from 'prop-types' import { View, Image } from '@tarojs/components' import './index.scss' /**
- 子组件 使用 prop-types 进行数据的校验,校验完毕。
- 在子组件(类组件)通过 this.props.自定义的属性名 就可以访问数据
- 如果组件时函数式组件,通过 props.自定义的属性名 访问数据 */ class Index extends Taro.Component { render () { return ( { this.props.prolist.map(item => ( <View className="proitem" key={ item.proid }> <Image className="img" src={ item.proimg }> { item.proname } { item.sales } / { item.stock } ¥{ item.price } )) } ) } }
校验数据格式 Index.propTypes = { prolist: PropTypes.array }
export default Index
下拉刷新 --- 不支持 h5模式
constructor (props) { super(props) // 1.设置状态 this.state = { bannerlist: [], prolist: [], pageCode: 1 } }
onPullDownRefresh () { // 不支持H5模式
request({
url: '/pro'
}).then(res => {
console.log(res.data)
this.setState({
prolist: res.data.data,
pageCode: 1 // 必须重置页码
})
Taro.stopPullDownRefresh() // 这句话一定要加,真机测试时一直处于加载状态
})
}
上拉加载实现
onReachBottom () {
request({
url: '/pro',
data: {
pageCode: this.state.pageCode
}
}).then(res => {
console.log(res.data)
if (res.data.code === '10000') {
Taro.showToast({
title: '没有更多数据了'
})
} else {
// 获取数据 处理数据 修改状态
let prolist = this.state.prolist
let pageCode = this.state.pageCode
prolist = [...prolist, ...res.data.data]
pageCode += 1
this.setState({
prolist,
pageCode
})
}
})
}
8.登录注册
设计登陆页面
// pages/login/index.jsx
import Taro, { Component } from '@tarojs/taro'
import { View } from '@tarojs/components'
class Index extends Component {
render () {
return (
<View>
登陆
</View>
)
}
}
export default Index
// app.jsx 注册路由
pages: [ // 路由
'pages/home/index',
'pages/kind/index',
'pages/cart/index',
'pages/user/index',
'pages/index/index',
'pages/detail/index',
'pages/login/index'
],