原文: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();
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。