内容简介:所以闲话少叙,我们说回 Taro……Taro 的开发体个人又比较喜欢 React,Taro 的社区活跃度和版本迭代速度可喜,所以毫无意外选择了 Taro。你有过 React 的开发经验,可以毫无困难地顺滑上手;如果没有,直接看 Taro 的官方文档 来入门也是没有问题的。从安装到建立一个新项目使用——
为啥使用Taro
个人又比较喜欢 React,Taro 的社区活跃度和版本迭代速度可喜,所以毫无意外选择了 Taro。
Taro 起步
所以闲话少叙,我们说回 Taro……
Taro 的开发体个人又比较喜欢 React,Taro 的社区活跃度和版本迭代速度可喜,所以毫无意外选择了 Taro。你有过 React 的开发经验,可以毫无困难地顺滑上手;如果没有,直接看 Taro 的官方文档 来入门也是没有问题的。
从安装到建立一个新项目使用——
$ npm install -g @tarojs/cli $ taro init myApp $ cd myApp $ npm install # 开发 $ npm run dev:weapp # 编译 $ npm run build:weapp 复制代码复制代码
这里的开发和编译指令中的 weapp
换成 h5
/ swan
/ alipay
/ tt
/ rn
后,即可在对应的其他端编译运行。多端的代码逻辑可以不同,详情请看跨平台开发。
项目结构
官方有一篇基于 Redux 的项目最佳实践文章:《Taro深度开发实践》。
官方推荐的项目结构——
├── config 配置目录 | ├── dev.js 开发时配置 | ├── index.js 默认配置 | └── prod.js 打包时配置 ├── src 源码目录 | ├── components 公共组件目录 | ├── pages 页面文件目录 | | ├── index index 页面目录 | | | ├── banner 页面 index 私有组件 | | | ├── index.js index 页面逻辑 | | | └── index.css index 页面样式 | ├── utils 公共方法库 | ├── app.css 项目总通用样式 | └── app.js 项目入口文件 └── package.json 复制代码复制代码
我在项目中并没有用到 Redux / MobX,项目「发展壮大」后的结构也比较简单明了——
├── dist 编译结果目录 ├── config 配置目录 | ├── dev.js 开发时配置 | ├── index.js 默认配置 | └── prod.js 打包时配置 ├── src 源码目录 | ├── assets 公共资源目录(内含图标等资源) | ├── components 公共组件目录 | | └── Btn 公共组件 Btn 目录 | | ├── Btn.js 公共组件 Btn 逻辑 | | └── Btn.scss 公共组件 Btn 样式 | ├── pages 页面文件目录 | | └── index index 页面目录 | | ├── components index 页面的独有组件目录 | | | └── Banner index 页面的 Banner 组件目录 | | | ├── Banner.js index 页面的 Banner 组件逻辑 | | | └── Banner.scss index 页面的 Banner 组件样式 | | ├── index.js index 页面逻辑 | | └── index.scss index 页面样式 | ├── subpackages 分包目录(项目过大时建议分包) | | └── profile 一个叫 profile 的分包目录 | | └── pages 该分包的页面文件目录 | | └── index 该分包的页面 index 目录(其下结构与主包的页面文件一致) | ├── utils 项目辅助类 工具 目录 | | └── api.js 比如辅助类 api 等 | ├── app.css 项目总通用样式 | └── app.js 项目入口文件 └── package.json 复制代码复制代码
什……这也叫「简单明了」吗? (゚д゚≡゚д゚)
这是我个人比较喜欢的组织方式。我的项目已经不算小了,总计近 30 个页面,使用上面这种方式维护,确实感觉还挺省心舒服的。当然你也可以按照你的喜好组织文件~
编译配置文件
编译配置存放于项目根目录下 config
目录中,包含三个文件
index.js dev.js prod.js
下面说一些使用案例和某些坑的解决方案——
路径别名
在项目中不断 import
相对路径的后果就是,不能方便直观地明白目录结构;如果要迁移改动一个目录,IDE 又没有很准确的重构功能的话,需要手动更改每一个 import
的路径,非常难受。
所以我们想把:
import A from '../../componnets/A' 复制代码复制代码
变成
import A from '@/componnets/A' 复制代码复制代码
这种引用。
方式如下:
/* config/index.js */ const path = require('path') alias: { '@/components': path.resolve(__dirname, '..', 'src/components'), '@/utils': path.resolve(__dirname, '..', 'src/utils'), }, 复制代码复制代码
详见: nervjs.github.io/taro/docs/c…
在代码中判断环境
/* config/dev.js */ env: { NODE_ENV: '"development"', // JSON.stringify('development') }, 复制代码复制代码
/* config/prod.js */ env: { NODE_ENV: '"production"', // JSON.stringify('development') }, 复制代码复制代码
代码中可以通过 process.env.NODE_ENV === 'development'
来判断环境。
区分开发和线上环境的 API
/* config/dev.js */ defineConstants: { BASE_URL: '"https://dev.com/api"', }, 复制代码复制代码
/* config/prod.js */ defineConstants: { BASE_URL: '"https://prod.com/api"', }, 复制代码复制代码
如此一来,可以直接在代码中引用 BASE_URL
来基于环境获取不同的 API Gateway。
解决打包后样式丢失等问题
如果你在开发中遇到了开发环境时样式没有问题,但是编译打包后出现部分样式丢失,可能是因为 csso 的 restructure 特性。可以在 plugins.csso
中将其关闭:
/* config/prod.js */ plugins: { csso: { enable: true, config: { restructure: false, }, }, }, 复制代码复制代码
解决编译压缩过的 js 文件出错的问题
如果你遇到了编译时,压缩过的 js 文件过编译器报错,可以将其排除编译:
/* config/index.js */ weapp: { compile: { exclude: [ 'src/utils/qqmap-wx-jssdk.js', 'src/components/third-party/wemark/remarkable.js', ], }, }, 复制代码复制代码
解决编译后资源文件找不到的问题
如果你遇到了编译后,资源文件(如图片)没有被编译到 dist
目录中导致找不到,可以令其直接被复制过来:
/* config/index.js */ copy: { patterns: [ { from: 'src/assets/', to: 'dist/assets/', }, ], }, 复制代码复制代码
使用微信小程序原生第三方组件和插件
官方文档: nervjs.github.io/taro/docs/m… 。
需要注意的是,如果这么做了,项目就不能再多端编译了。
使用方式看官方文档描述即可,十分简单。但我实际在使用的过程中,还是踩了坑的。比如我尝试集成 wemark 来做 markdown 的渲染。发现了两个问题:
-
Taro 会漏编译仅在
wxss
中引用的wxss
文件。解决方式是需要copy
配置把所有文件在编译时全部拷贝过去。 -
在编译压缩过的 js 文件时,会再次经过一次编译导致出错,且无视
copy
配置。解决方式是需要exclude
配置把压缩的 js 文件排除。(如上面提到的那样。)
所以以 wemark 为例,项目集成原生组件,需要另加配置:
/* config/index.js */ copy: { patterns: [ { from: 'src/components/wemark', to: 'dist/components/wemark', }, ], }, weapp: { compile: { exclude: [ 'src/components/wemark/remarkable.js', ], }, }, 复制代码复制代码
然后可以引用了——
import Taro, { Component } from '@tarojs/taro' import { View } from '@tarojs/components' export default class Comp extends Component { config = { usingComponents: { wemark: '../components/wemark/wemark' } } state = { md: '# heading' } render() { return ( <View> <wemark md={this.state.md} link highlight type="wemark" /> </View> ) } } 复制代码复制代码
简而言之,如果你在集成原生组件中遇到了类似问题,可以试试直接 copy
整个组件目录,并且排除掉某些 js 文件防止过编译。
使用图标字体组件
我们希望在项目中拥有自己的图标字体组件,使用方法如下:
<UIcon icon="home" /> 复制代码复制代码
为什么是 UIcon
,而不是 Icon
?因为命名不能与官方自带的组件 Icon
冲突呀……(|||゚д゚) 你也可以管他叫 OhMyIcon
之类的。
这里先说实践,再说说坑……
实践就是,如果大家没有专业的设计师或者公司内部的图标库的话,可以使用Iconfont 的图表库,优点是图标多而优、CDN 开箱即用。你可以新建一个项目,选择适合你项目的图标后,直接获取到 @font-face
的引用代码:
Unicode 和 Font class 的引用效果几乎一样,后者的优势是 class name 的语义化,而由于我们需要再进行一层包装,将 class name 变得可定制,所以推荐大家选择 Unicode。
而 Symbol 的优势就在于支持多色图标,那为什么不用它呢……踩坑啦踩坑啦,微信小程序不兼容 svg 图标 QwQ。(在官方社区搜了很多帖子,官方只会说「好的,我们看看」、「请贴一下代码片段」然后就没动静了……类似的情况还有很多,提了几年的 bug,始终不修,留着当传家宝……(/‵Д′)/~ ╧╧ )
那么我们在组件的样式文件里加上上面这段 @font-face
的代码后,再写类似下面的这段:
/* UIcon.scss */ .u-icon { display: inline-block; &:before { font-family: 'iconfont' !important; font-style: normal; font-weight: normal; speak: none; display: inline-block; text-decoration: inherit; width: 1em; text-align: center; } } 复制代码复制代码
然后针对每个图标,给出它的 unicode 定义:
/* UIcon.scss */ .u-icon-add::before { content: '\e6e0'; } .u-icon-addition::before { content: '\e6e1'; } /* ... */ 复制代码复制代码
UIcon.js
如此包装:
/* UIcon.js */ import Taro, { Component } from '@tarojs/taro' import { View } from '@tarojs/components' import './UIcon.scss' export default class UIcon extends Component { static externalClasses = ['uclass'] static defaultProps = { icon: '', } render() { return <View className={`uclass u-icon u-icon-${this.props.icon}`} /> } } 复制代码复制代码
这里注意到我加了一个 externalClasses
的配置,以及一个 uclass
的 className
。原因是我想在组件外部定义内部的样式,如此定义后,可以这么调用:
<UIcon icon="home" uclass="external-class" /> 复制代码复制代码
详情可以看文档 组件的外部样式和全局样式 。(这篇文档就是我当时踩完这个坑帮忙给补上的 QwQ……)
包装一个汇报 formId 的组件
如果你有主动发送小程序模板消息卡片的需求,可能需要这样的组件。
小程序目前的策略是你只能在用户触发一个 button
点击事件后,汇报给你一个一次性的 7 天过期 formId
,你用它来发送一次模板消息。所以涌现一批机智的小程序开发者,把 button
包裹在整个页面上,用户每一次点击都汇报一个 formId
,存起来之后,七天之内反正不愁啦,慢慢发。而官方貌似也一直睁一只眼闭一只眼…… (●` 艸 ´)
Taro 中实现这样的包裹器也很简单:
/* FormIdReporter.js */ import Taro, { Component } from '@tarojs/taro' import { Button, Form } from '@tarojs/components' import './FormIdReporter.scss' export default class FormIdReporter extends Component { handleSubmit = e => { console.log(e.detail.formId) // 这里处理 formId } render() { return ( <Form reportSubmit onSubmit={this.handleSubmit}> <Button plain formType="submit" hoverClass="none"> {this.props.children} </Button> </Form> ) } } 复制代码复制代码
在调用时,把整个页面包裹上即可:
<FormIdReporter> {/* 一些其他组件 */} </FormIdReporter> 复制代码复制代码
需要注意的是,这里的 Button
需要使用下面的样式代码清除掉默认样式,达到「隐藏」的效果:
/* FormIdReporter.scss */ button { width: 100%; border-radius: 0; padding: 0; margin: 0; &:after { border: 0; } } 复制代码复制代码
利用 Decorator 实现快速分享/登录验证
由于这部分内容也是我从他处学到的,并且有既成的教程,我就不再添油加醋啦。参考:
下面说的这些,更多的是关于小程序自身的一些实践案例了。当然,也是以 Taro 为背景的。
i18n 国际化
由于项目需要实现小程序文本国际化,我找了很多案例,最终参考了这个比较简洁的方案的思路: weapp-i18n 。已经运用到两个项目中了。在 Taro 中,可以包装成下面这个类:
/* utils/i18n.js */ export default class T { constructor(locales, locale) { this.locales = locales if (locale) { this.locale = locale } } setLocale(code) { this.locale = code } _(line) { const { locales, locale } = this if (locale && locales[locale] && locales[locale][line]) { line = locales[locale][line] } return line } } 复制代码复制代码
新建一个 locales.js
,写上你的本地化语言, key
名要和微信系统语言的叫法一致:
/* utils/locales.js */ locales.zh_CN = { Discover: '发现', Schools: '学校', Me: '我', 'Courses of My Faculty': '我的院系课程', 'Popular Evaluations Monthly': '本月热门评测', 'Popular Evaluations': '热门评测', 'Recent Evaluations': '最新评测', 'Top Courses': '高分课程', /* ... */ } locales.zh_TW = { ...locales.zh_CN, Discover: '發現', Schools: '學校', Me: '我', 'Courses of My Faculty': '我的院系課程', 'Popular Evaluations Monthly': '本月熱門評測', 'Popular Evaluations': '熱門評測', 'Recent Evaluations': '最新評測', 'Top Courses': '高分課程', /* ... */ } 复制代码复制代码
使用方式是在 App.js
中先初始化:
/* App.js */ componentWillMount() { this.initLocale() } initLocale = () => { let locale = Taro.getStorageSync('locale') if (!locale) { // 初始化语言 const systemInfo = await Taro.getSystemInfo() locale = systemInfo.language // 默认使用系统语言 Taro.setStorage({ key: 'locale', data: locale }) } Taro.T = new T(locales, locale) // 初始化本地化工具实例并注入 Taro.T // 手动更改 TabBar 语言(目前只能这么做) Taro.setTabBarItem({ index: 0, text: Taro.T._('Discover'), }) Taro.setTabBarItem({ index: 1, text: Taro.T._('Me'), }) } 复制代码复制代码
组件中使用:
<Button>{Taro.T._('Hello')}</Button> 复制代码复制代码
如果小程序提供了更改语言的功能,用户更改后,储存配置,然后直接 Taro.reLaunch
到首页,并且依次如上所述更改 TabBar 的语言即可。
确实挫了一点,不过在我看来,已经是在小程序里实现国际化的最方便可行的办法啦……(*´ω`)人(´ω`*)
包装 API 方法
虽然 Taro 提供了 Taro.request
这个方法,但我还是选择了Fly.js 这个库,包装了一个自己的 request 方法:
/* utils/request.js */ import Taro from '@tarojs/taro' import Fly from 'flyio/dist/npm/wx' import config from '../config' import helper from './helper' const request = new Fly() request.config.baseURL = BASE_URL const newRquest = new Fly() // 这是用来 lock 时用的,详见后面 // 请求拦截器,我在这里的使用场景是:除了某些路由外,如果没有权限的用户「越界」了,就报错给予提示 request.interceptors.request.use(async conf => { const { url, method } = conf const allowedPostUrls = [ '/login', '/users', '/email', ] const isExcept = allowedPostUrls.some(v => url.includes(v)) if (method !== 'GET' && !isExcept) { try { await helper.checkPermission() // 一个用来检测用户权限的方法 } catch (e) { throw e } } return conf }) // 响应拦截器,我在这里的使用场景是:如果用户的 session 过期了,就锁定请求队列,完成重新登录,然后继续请求队列 request.interceptors.response.use( response => response, async err => { try { if (err.status === 0) { // 网络问题 throw new Error(Taro.T._('Server not responding')) } const { status } = err.response if (status === 401 || status === 403) { // 这两个状态码表示用户没有权限,需要重新登录领 session request.lock() // 锁定请求队列,避免重复请求 const { errMsg, code } = await Taro.login() // 重新登录 if (code) { const res = await newRquest.post('/login', { code }) // 使用新实例完成登录 const { data } = res.data const { sessionId, userInfo } = data Taro.setStorageSync('sessionId', sessionId) // 储存新 session if (userInfo) { Taro.setStorageSync('userInfo', userInfo) // 更新用户信息 } request.unlock() // 解锁请求队列 err.request.headers['Session-Id'] = sessionId // 在请求头加上新 session return await request.request(err.request) // 重新完成请求 } else { request.unlock() throw new Error(Taro.T._('Unable to get login status'), errMsg) return err } } } catch (e) { Taro.showToast({ title: e.message, icon: 'none' }) throw e } }, ) export default request 复制代码复制代码
你可以在这个的基础上,再包装一层 api.js
的 SDK。用起来很舒服~σ ゚∀ ゚) ゚∀゚)σ
使用第三方统计
第三方统计我目前用过两个,阿拉丁 和TalkingData。二者进行对比后,发现大同小异,阿拉丁社区更活跃一些,而 TalkingData 提供了数据获取的 API。但使用中发现,TalkingData 并不能很好地兼容 Taro,在我反馈后,得到的回复是由于小程序第三方开发框架太多,所以没有支持的计划 (´c_`);阿拉丁虽然之前也有这样的问题,但在几个月前的版本中已经修复,而且提供了集成的参考文档。
所以如果有这方面需求的话,可以考虑看看阿拉丁~
全局样式的统一配置文件
最后,说一个统一全局样式的实践吧。很简单,比如创建一个 _scheme.scss
的文件:
/* utils/_scheme.js */ $f1: 80px; // 阿拉伯数字信息,如:金额、时间等 $f2: 40px; // 页面大标题,如:结果、控状态等信息单一页面 $f3: 36px; // 大按钮字体 $f4: 34px; // 首要层级信息,基准的,可以是连续的,如:列表标题、消息气泡 $f5: 28px; // 次要描述信息,服务于首要信息并与之关联,如:列表摘要 $f6: 26px; // 辅助信息,需弱化的内容,如:链接、小按钮 $f7: 22px; // 说明文本,如:版权信息等不需要用户关注的信息 $f8: 18px; // 十分小 $color-primary: #ff9800; // 品牌颜色 $color-secondary: lighten($color-primary, 10%); $color-tertiary: lighten($color-primary, 20%); $color-line: #ececec; // 分割线颜色 $color-bg: #ebebeb; // 背景色 $color-text-primary: #000000; // 主内容 $color-text-long: #353535; // 大段说明的主要内容 $color-text-secondary: #888888; // 次要内容 $color-text-placeholder: #b2b2b2; // 缺省值 $color-link-normal: #576b96; // 链接用色 $color-link-press: lighten($color-link-normal, 10%); $color-link-disable: lighten($color-link-normal, 20%); $color-complete-normal: $color-primary; // 完成用色 $color-complete-press: lighten($color-complete-normal, 10%); $color-complete-disable: lighten($color-complete-normal, 20%); $color-success-normal: #09bb07; // 成功用色 $color-success-press: lighten($color-success-normal, 10%); $color-success-disable: lighten($color-success-normal, 20%); $color-error-normal: #e64340; // 出错用色 $color-error-press: lighten($color-error-normal, 10%); $color-error-disable: lighten($color-error-normal, 20%); 复制代码复制代码
之后在样式文件中引用这个配置文件,使用相应变量,而不使用绝对的数值即可。
对了,Taro 中的 px
其实指的就是 rpx
;如果你想要真实的 px
,可以大写 PX
。
以上就是这些,没能在开发的同时做笔记导致可能也遗漏了不少点,争取以后补上吧。写这么多一方面是总结,一方面也是分享。谢谢各位看到这里。如果有任何地方说的不对,欢迎指正教导。我要学习的还有很多!
以上所述就是小编给大家介绍的《使用Taro开发项目总结》,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对 码农网 的支持!
猜你喜欢:本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。
QBasic语言程序设计教程(第2版习题解答)
刘瑞新、丁爱萍 / 电子工业出版社 / 1999-6-1 / 13.00
本书是《QBasic语言程序设计教程》(第二版)一书的配套教材、本书第一部分以概要的形式,对全书进行了总结,以便学生复习。在第二部分中,对《QBasic语言程序设计教程》(第二版)中的习题做了详尽的分析与解答。 本书也可作为QBasic语言的习题研单独使用。一起来看看 《QBasic语言程序设计教程(第2版习题解答)》 这本书的介绍吧!