小程序-Taro

851 阅读6分钟

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.运行项目

  1. 浏览器端
npm run dev:h5

npm run build:h5
  1. 微信小程序端
npm run dev:weapp

npm run build:weapp
  1. 其他类 百度小程序、支付宝小程序、字节跳动、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' 
],

9.购物车