编程开源技术交流,分享技术与知识

网站首页 > 开源技术 正文

使用Taro开发微信小程序(typescript开发微信小程序)

wxchong 2024-08-05 02:03:03 开源技术 20 ℃ 0 评论

原文:https://www.jianshu.com/p/dc4a1b17ff53

一.什么是taro?

Taro 是一套遵循 React 语法规范的 多端开发 解决方案。通过一套react的代码,就可以分别编译出微信小程序、H5、支付宝小程序。。。 我根据taro redux模板创建了一套自己写的H5种子项目,大家可以一起学习,项目地址:https://github.com/WangxinsHub/taro-seed

二.如何安装taro?

1.首先全局安装taro命令行:

$ npm install -g @tarojs/cli

$ yarn global add @tarojs/cli

2.创建taro种子项目

$ taro init myApp

3.编译taro,在创建的种子项目中,package文件如下:

"scripts": {
"build:weapp": "taro build --type weapp",//打包小程序
"build:h5": "taro build --type h5", //打包H5
"dev:weapp": "npm run build:weapp -- --watch",//编译小程序
"dev:h5": "npm run build:h5 -- --watch",//编译H5
},

三、开发前注意

小程序工具:

需要设置关闭 ES6 转 ES5 功能,开启可能报错

需要设置关闭上传代码时样式自动补全,开启可能报错

需要设置关闭代码压缩上传,开启可能报错

四、项目说明

1.dist是编译(dev/build)结果目录

2.config配置目录

index.js(默认配置)

const path = require('path')
const config = {
 projectName: 'Taro-time-bus',
 date: '2019-1-8',
 designWidth: 750,//设计稿以 iPhone6 750px 作为设计尺寸标准。
 //目前 Taro 支持 750、 640 、 828 三种尺寸设计稿,他们的换算规则如下:
 deviceRatio: {
 '640': 2.34 / 2,
 '750': 1,
 '828': 1.81 / 2
 },
 // 项目源码目录
 sourceRoot: 'src',
 // 项目产出目录
 outputRoot: 'dist',
 // 通用插件配置
 plugins: {
 //plugins 用来设置一些各个端通用的编译过程配置,例如 babel 配置,JS/CSS 压缩配置等。
 babel: {
 sourceMap: true,
 presets: ['env'],
 plugins: ['transform-decorators-legacy', 'transform-class-properties', 'transform-object-rest-spread']
 }
 /*
 //设置打包过程中的 JS 代码压缩
 uglify: {
 enable: true,
 config: {
 // 配置项同 https://github.com/mishoo/UglifyJS2#minify-options
 }
 },
 //设置打包过程中的 CSS 代码压缩
 csso: {
 enable: true,
 config: {
 // 配置项同 https://github.com/css/csso#minifysource-options
 }
 }*/
 },
 // 全局变量设置
 defineConstants: {
 context:{
 iconPath:'xxx'
 }
 },
 alias: {
 '@components': path.resolve(__dirname,'../src/components'),
 '@icons': path.resolve(__dirname,'../src/icons'),
 '@src': path.resolve(__dirname,'../src/'),
 '@utils': path.resolve(__dirname, '..', 'src/utils')
 },
 weapp: {
 //小程序编译过程的相关配置。
 compile: {
 compressTemplate: true,//决定小程序打包时是否需要压缩 wxml
 },
 module: {
 postcss: {
 autoprefixer: {
 enable: true,
 config: {
 browsers: [
 'last 3 versions',
 'Android >= 4.1',
 'ios >= 8'
 ]
 }
 },
 pxtransform: {
 enable: true,
 config: {
 onePxTransform: true, //设置 1px 是否需要被转换
 unitPrecision: 5,//REM 单位允许的小数位。
 selectorBlackList: [],//黑名单里的选择器将会被忽略。
 replace: true,//直接替换而不是追加一条进行覆盖。
 mediaQuery: false,//允许媒体查询里的 px 单位转换
 minPixelValue: 0//设置一个可被转换的最小 px 值
 }
 },
 url: {
 enable: true,
 config: {
 limit: 10240 // 设定转换尺寸上限
 }
 },
 cssModules: {
 enable: false, // 默认为 false,如需使用 css modules 功能,则设为 true
 config: {
 namingPattern: 'module', // 转换模式,取值为 global/module
 generateScopedName: '[name]__[local]___[hash:base64:5]'
 }
 }
 }
 }
 },
 h5: {
 devServer: {
 port: 10086
 },
 publicPath: '/', //设置输出解析文件的目录。
 staticDirectory: 'static',//h5 编译后的静态文件目录。
 esnextModules: ['taro-ui'],//配置需要额外的编译的源码模块,比如taro-ui:
 miniCssExtractPluginOption: {
 filename: 'css/[name]/[hash].css',
 chunkFilename: 'css/[name]/[hash].css'
 },
 module: {
 postcss: {
 autoprefixer: {
 enable: true,
 config: {
 browsers: [
 'last 3 versions',
 'Android >= 4.1',
 'ios >= 8'
 ]
 }
 },
 cssModules: {
 enable: false, // 默认为 false,如需使用 css modules 功能,则设为 true
 config: {
 namingPattern: 'module', // 转换模式,取值为 global/module
 generateScopedName: '[name]__[local]___[hash:base64:5]'
 }
 }
 }
 }
 }
}
module.exports = function (merge) {
 if (process.env.NODE_ENV === 'development') {
 return merge({}, config, require('./dev'))
 }
 return merge({}, config, require('./prod'))
}

dev.js

module.exports = {
 env: {
 NODE_ENV: '"development"',
 API_HOSTNAME:JSON.stringify('https://appdev.ibuscloud.com'),//test环境地址
 },
 defineConstants: {
 },
 weapp: {
 },
 h5: {}
}

3.入口文件为 app.js

import '@tarojs/async-await'
import Taro, { Component } from '@tarojs/taro'
import { Provider } from '@tarojs/redux'
import 'taro-ui/dist/style/index.scss' // 全局引入一次即可
import Index from './pages/index'
import configStore from './store'
import './app.less'
// 如果需要在 h5 环境中开启 React Devtools
// 取消以下注释:
// if (process.env.NODE_ENV !== 'production' && process.env.TARO_ENV === 'h5') {
// require('nerv-devtools')
// }
const store = configStore()
class App extends Component {
 config = {
 pages: [
 'pages/index/index',
 'pages/search/index',
 'pages/lineDetail/index',
 'pages/page2/index'
 ],
 "permission": {
 "scope.userLocation": {
 "desc": "你的位置信息将用于小程序位置接口的效果展示"
 }
 },
 window: {
 backgroundTextStyle: 'light',
 navigationBarBackgroundColor: '#fff',
 navigationBarTitleText: 'WeChat',
 navigationBarTextStyle: 'black'
 }
 }
 componentDidMount () {}
 componentDidShow () {
 //获取用户位置,TODO:H5
 Taro.getLocation().then(data=>{
 console.log(data)
 const {latitude,longitude} = data ;
 Taro.setStorageSync('userLat', latitude);
 Taro.setStorageSync('userLng', longitude);
 })
 }
 componentDidHide () {}
 componentCatchError () {}
 componentDidCatchError () {}
 // 在 App 类中的 render() 函数没有实际作用
 // 请勿修改此函数
 render () {
 return (
 <Provider store={store}>
 <Index />
 </Provider>
 )
 }
}
Taro.render(<App />, document.getElementById('app'))

1??其中config主要参考微信小程序的全局配置而来,在编译成小程序时,这一部分配置将会被抽离成

app.json

,而编译成其他端,亦会有其他作用。 页面路由在此配置,页面背景色导航栏等也在此设置 2??app.js的生命周期、页面与组件的生命周期: 而且由于入口文件继承自 Component 组件基类,它同样拥有组件生命周期,但因为入口文件的特殊性,他的生命周期并 不完整 ,如下

3??普通页面生命周期与component一致

小程序专有的方法:(H5中暂不支持)

4??组件Taro 的组件同样是继承自 Component 组件基类,与页面类似,组件也必须包含一个 render 函数,返回 JSX 代码。 比页面多了一个componentWillReceiveProps。

注意 : 组件的 constructor 与 render 提前调用,所以componentWillMount这个生命周期有一个滞后性,不可以直接在render中用路由得来的数据

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} />
}

? 由于微信小程序里页面在 onLoad 时才能拿到页面的路由参数,而页面 onLoad 前组件都已经 attached 了。因此页面的 componentWillMount 可能会与预期不太一致。

五、开发中的问题

1.静态资源的引入

1??通过ES6的import引用图片、js、等文件(暂不支持svg),而且不需要安装任何 loader。 2??可以先上传到服务器,然后引用服务器的地址(在less中background用的多一点)

全局原始app.less 只会影响到页面级别的文件,组件的获取不到全局的样式 可以同过@import 让组件获得app.less全局样式

@import "../../app";

2.jsx的支持程度:

  • 不能在包含 JSX 元素的 map 循环中使用 if 表达式
  • 不能使用 Array#map 之外的方法操作 JSX 数组
  • [不能在 JSX 参数中使用匿名函数](自 v1.2.9 开始支持注意:在各小程序端,使用匿名函数,尤其是在 循环中 使用匿名函数,比使用 bind 进行事件传参用更大的内存,速度也会更慢。)(https://github.com/NervJS/taro/blob/master/packages/eslint-plugin-taro/docs/no-anonymous-function-in-props.md)
  • 暂不支持在 render() 之外的方法定义 JSX
  • 不能在 JSX 参数中使用对象展开符
<View {...this.props} />
<View {...props} />
<Custom {...props} />

以上是错误写法

  • 不支持无状态组件(必须return)

3.组件化 \& props \&state

1??使用 PropTypes 检查类型

Greeting.propTypes = {
 name: PropTypes.string
};

2??给组件设置 defaultProps

3??组件传递函数属性名以 on 开头

4??当组件传入jsx的时候必须用render开头,在小程序中其实是通过slot插槽来实现的,所以和this.props.children一样, this.props.children \&\& this.props.children、this.props.children[0] 在 Taro 中都是非法的。且组合只能传入单个 JSX 元素,不能传入其它任何类型。当你需要进行一些条件判断或复杂逻辑操作的时候,可以使用一个 Block 元素包裹住,然后在 Block 元素的里面填充其它复杂的逻辑。

state:

5??state this.state 和 props 一定是异步更新的,所以你不能在 setState 马上拿到 state 的值

6??不要在

state

props

上用同名的字段,因为这些被字段在微信小程序中都会挂在

data

上 7??尽量避免在 componentDidMount 中调用 this.setState 因为在 componentDidMount 中调用 this.setState 会导致触发更新 (尽量避免,可以componentWillMount 中处理) 不要在 componentWillUpdate/componentDidUpdate/render 中调用 this.setState

5.事件

事件类型参照微信小程序https://developers.weixin.qq.com/miniprogram/dev/framework/view/wxml/event.html

6.路由

1??传参:

Taro.navigateTo({
 url: '/pages/page/path/name?id=2&type=test'
})

接收:this.$router.params

2??预加载传参 在微信小程序中,从调用 Taro.navigateTo、Taro.redirectTo 或 Taro.switchTab 后,到页面触发 componentWillMount 会有一定延时。因此一些网络请求可以提前到发起跳转前一刻去请求。

传参:

this.$preload({
 x: 1,
 y: 2
})
Taro.navigateTo({ url: '/pages/B/B' })
(也能够绕过 componentWillMount 延时)
接收componentWillMount () {
 console.log('preload: ', this.$router.preload)
}

7异步编程 以及 接口请求

$ yarn add @tarojs/async-await import '@tarojs/async-await' 异步dispatch,action.js:

import '@tarojs/async-await'
import {
 ADD,
 MINUS,
 ASYNC,
 ASYNC_BEFORE
} from './action-type';
import Http from '../../api/Server'
import Url from '../../api/url';
export const add = () => {
 return {
 type: ADD
 }
}
export const minus = () => {
 return {
 type: MINUS
 }
}
export const asyncAdd = (params) => {
 // 返回函数,异步dispatch
 return async dispatch => {
 try{
 dispatch({
 type: ASYNC_BEFORE,
 })
 let result = await Http.request('post',Url.lineRecommendQuery,params);
 // 如果不成功,则将不成功的信息打印出来
 if(result){
 if(!result.success) console.error(result.message);
 dispatch({
 type: ASYNC,
 response: result,
 })
 }
 }catch(err){
 console.error(err);
 }
 }
}

Http 请求工具类:api.js

import Taro from '@tarojs/taro'
class Http {
 constructor(){
 const HOSTNAME = process.env.API_HOSTNAME
 this.url={
 }
 }
 request(method = 'post', url, params) {
 console.log(process.env.TARO_ENV)
 Taro.showNavigationBarLoading();
 return new Promise((resolve, reject) => {
 Taro.request({
 url,
 method,
 data: params,
 header: {
 'Content-Type': 'application/x-www-form-urlencoded',
 'Accept': '*/*'
 }
 }).then(res => {
 Taro.hideNavigationBarLoading()
 resolve(typeof res.data === 'object' ? res.data : JSON.parse(res.data))
 }, err => {
 Taro.hideNavigationBarLoading()
 reject(err)
 })
 })
 }
}
export default new Http();

Tags:

本文暂时没有评论,来添加一个吧(●'◡'●)

欢迎 发表评论:

最近发表
标签列表