Taro爬坑血泪史
一、介绍
- Taro 是一个开放式跨端跨框架解决方案,支持使用 React/Vue/Nerv 等框架来开发 微信 / 京东 / 百度 / 支付宝 / 字节跳动 / QQ 小程序 / H5 等应用。现如今市面上端的形态多种多样,Web、React Native、微信小程序等各种端大行其道,当业务要求同时在不同的端都要求有所表现的时候,针对不同的端去编写多套代码的成本显然非常高,这时候只编写一套代码就能够适配到多端的能力就显得极为需要。
- Taro 2.X 支持react
- Taro 3.0 支持vue/vue3
二、安装
# 使用 npm 安装 CLI
$ npm install -g @tarojs/cli
# 使用命令创建模板项目
$ taro init myApp
# 安装依赖
$ npm install
复制代码
++注意:依赖版本保持一致++
三、编译以及打包
"scripts": {
"build:weapp": "taro build --type weapp", //微信
"build:swan": "taro build --type swan", // 百度
"build:alipay": "taro build --type alipay", //阿里
"build:tt": "taro build --type tt", //字节
"build:h5": "taro build --type h5", //H5
"build:qq": "taro build --type qq", //qq
"build:quickapp": "taro build --type quickapp",
"dev:weapp": "npm run build:weapp -- --watch",
"dev:nopre:weapp": "set NODE_ENV=devNoPre && npm run build:weapp -- --watch",
"dev:swan": "npm run build:swan -- --watch",
"dev:alipay": "npm run build:alipay -- --watch",
"dev:tt": "npm run build:tt -- --watch",
"dev:h5": "npm run build:h5 -- --watch",
"dev:rn": "npm run build:rn -- --watch",
"dev:qq": "npm run build:qq -- --watch",
"dev:quickapp": "npm run build:quickapp -- --watch",
"lint-staged": "lint-staged"
},
复制代码
四、项目目录结构
├── dist 编译结果目录
├── config 配置目录
| ├── dev.js 开发时配置
| ├── index.js 默认配置
| └── prod.js 打包时配置
├── src 源码目录
| ├── pages 页面文件目录
| | ├── index index 页面目录
| | | ├── index.js index 页面逻辑
| | | └── index.css index 页面样式
| ├── app.css 项目总通用样式
| └── app.js 项目入口文件
└── package.json
复制代码
五、多端编译
let pages = []
if (process.env.TARO_ENV === 'weapp') {
pages = [
'/pages/index/index'
]
}
if (process.env.TARO_ENV === 'swan') {
pages = [
'/pages/indexswan/indexswan'
]
}
export default {
pages
}
复制代码
六、单位转化
小程序、H5尺寸单位统一
- 把rpx替换成px
- run dev:h5后,会自动编译成rem单位(行内样式无法自动转换,一些Taro-ui框架内的scss无法自动转化,需要手动调整,原因未知)
/config/index.js
const config = {
projectName: 'myProject',
date: '2018-4-18',
designWidth: 640,
....
}
复制代码
七、优化
1.分包
config:[
pages:[],
subpages:[]
]
复制代码
2.预渲染
- 将页面初始化的状态直接渲染为无状态(dataless)的 wxml,在框架和业务逻辑运行之前执行渲染流程。经过 Prerender 的页面初始渲染速度通常会和原生小程序一致甚至更快。
const config = {
...
mini: {
prerender: {
match: 'pages/shop/**', // 所有以 `pages/shop/` 开头的页面都参与 prerender
include: ['pages/any/way/index'], // `pages/any/way/index` 也会参与 prerender
exclude: ['pages/shop/index/index'] // `pages/shop/index/index` 不用参与 prerender
}
}
};
module.exports = config
复制代码
3.长列表渲染
- 只渲染当前可视区域(visible viewport)的视图
<VirtualList
height={500} /* 列表的高度 */
width='100%' /* 列表的宽度 */
itemData={data} /* 渲染列表的数据 */
itemCount={dataLen} /* 渲染列表的长度 */
itemSize={100} /* 列表单项的高度 */
>
{Row} /* 列表单项组件,这里只能传入一个组件 */
</VirtualList>
复制代码
八、技术选型
React、Typescript、Mobx、Hooks
九、小程序
1.第三方H5网页跳转
- 需要配置第三方https证书,且第三方服务器需要添加一个业务域名校验文件,并小程序后台配置业务域名,详情查看小程序后台开发配置
2.input卡顿问题
输入框快速输入,或者快速删除数据卡顿闪屏问题
- 绑定旧值,监听onChange事件设置旧值的拷贝值,==避免组件依赖值更新==,即可解决方法
const [formData, setFormData] = useState(initState)
const [selfFormState, setSelfFormState] = useState(initState)
const handleChange = (type, value) => {
const newState = {
...selfFormState,
[type]: value,
}
setSelfFormState(newState)
//小程序需要return value
return value
}
复制代码
<AtInput
name='name'
title='名称'
type='text'
required
disabled
placeholder='请输入名称'
value={formData.name}
onChange={(val) => {
handleChange('name', val)
}}
/>
复制代码
3.textArea层级最高,涉及到弹窗覆盖问题
弹窗被textArea遮挡的奇怪现象
- 控制textArea的显示隐藏
<View>
<AtForm onSubmit={onSubmit}>
<View>
<View style={{ visibility: show ? 'hidden' : 'visible' }}>
<AtTextarea
count={false}
value={formData.tel}
onChange={(val) => {
handleChange('tel', val)
}}
maxLength={1000}
placeholder={'请输入联系电话'}
/>
</View>
</View>
</AtForm>
{show && (
<View>
弹窗内容
</View>
)}
</View>
复制代码
4.小程序后退页面刷新问题
例如从详情页进入编辑页,编辑完成后返回的情况下,小程序是不会重新请求新的数据。如果继续前进,会涉及到页面栈最大层级问题
- 小程序返回的页面会触发==useDidshow==
function Index () {
useDidShow(() => {
// 校验用户状态
checkUserStatus()
})
return (
<View>
测试
</View>
)
}
复制代码
5.弹窗打开时,固定背景隐藏背景滚动条
- 弹窗打开时背景添加css,隐藏滚动条
.at-modal__content {
overflow-y: hidden;
::-webkit-scrollbar{
width: 0;
height: 0;
color: transparent;
}
}
复制代码
6.用户数据获取
授权操作弹窗,首次拒绝后 不会再次弹出
- 非必要情况下建议使用开放组件==openData==展示用户头像及昵称
<OpenData type='userAvatarUrl'/>
复制代码
十、H5
1.Taro.request()H5端不返回数据
- 用axios重新封装
export function generateTaroReq (config) {
return async (data?: AjaxData) => {
const res = await Taro.request({
...config,
data,
})
const { data: resData } = res
return resData.data
}
}
复制代码
export function generateTaroReq(axiosConfig:axiosConfig,config?:any): Function{
const dataName = axiosConfig.method&&axiosConfig.method.toLowerCase() == 'post' ? 'data' : 'params'
return (data?: Object) =>{
return axios({
method:axiosConfig.method,
url:'/xxxx/'+axiosConfig.url,
[dataName]:{
...data
}
}).then(res => {
return res.data
})
}
}
const reqBankInfo = generateTaroReq({
url: 'wx/api/weixin/jrManage/editBankInfo',
method: 'POST'
})
reqBankInfo(_ajaxData)
复制代码
2.登录Taro.login()不可用
H5端无法调用
- 替换成其他登录形式
3.position:fixed状态下ScrollView无法滚动
顶部tabs超出屏幕宽度时无法左右滑动
- 如固定再头部的导航菜单左右滚动,则设置需要设置css属性(left和right)
.className{
position:fixed;
top:0;
left:0;
right:0;
}
复制代码
4.Taro.uploadFile()
- H5端需要多加一个参数:fileName:’xxxx.png’,不加接口会报错
const config = {
url: '/xxxxx/uploadxImage',//上传接口
filePath: path,
name: 'file',
fileName:'file.' + type,
header: {
Authorization: Taro.getStorageSync('token'),
},
}
Taro.uploadFile(config)
复制代码
5.tabs切换报错
Failed to execute ‘replaceChild’ on ‘Node’: The node to be replaced is not a child of this node.
- 原因是用了同一套数据,把list和showData分开就行
<AtTabs current={current} tabList={tabList} onClick={handleClick}>
<AtTabsPane current={current} index={0}>
<View key="0">
{
showData&&!loading?(
view.map(item => {
return <JinrongItem item={item}></JinrongItem>
})):empty
}
</View>
</AtTabsPane>
</AtTabs>
复制代码
==改成==
<AtTabs current={current} tabList={tabList} onClick={handleClick}>
<AtTabsPane current={current} index={0}>
<View key="0">
{showData&&!loading?(
list.map((item, i) => {
return <JirongItem value={item}></JirongItem>
})):empty
}
</View>
</AtTabsPane>
<AtTabsPane current={current} index={1}>
<View key="1">
{showData2&&!loading?(
list2.map((item, i) => {
return <XuqiuLow xuqiukey={_keys[current]} key={item.id} isedit value={item}></XuqiuLow>
})):empty
}
</View>
</AtTabsPane>
</AtTabs>
复制代码
6.Taro.getCurrentPages()在H5和小程序中表现不同
- H5中没有setData方法
7.Picker组件
onChange钩子,选择下标的取值方法
- 小程序:const value = event.detail.value[0]
- H5:const value = event.detail.value
8.Editor组件替换为zx-editor
9.Testarea组件绑定的value不能为null,否则会报length of null错误
<AtTextarea
className="AtTextareaFix"
count={false}
value={textareaProps.value}
onChange={textareaProps.onChange}
maxLength={textareaProps.maxLength}
placeholder={textareaProps.placeholder}
/>
复制代码
10.微信浏览器项目更新后拿不到最新的js文件
h5: {
publicPath: '/',
output: {
filename: 'js/[name].[hash].js',
chunkFilename: 'js/[name].[chunkhash].js'
},
miniCssExtractPluginOption: {
filename: 'css/[name].[hash].css',
chunkFilename: 'css/[name].[chunkhash].css',
}
}
复制代码
© 版权声明
文章版权归作者所有,未经允许请勿转载。
THE END