taro
taro原理
- 1、语法转换, 底层会将这些语法转换为各个端所支持的语法
- 2、定制api标准化, 对各个端的 API 进行了封装,提供了一致的 API 接口
- 3、虚拟DOM,可以更好的进行跨平台渲染对对应的组件
Taro 是一个跨端开发框架,其原理可以分为以下几个方面:
- 语法转换:Taro 支持使用类 React 语法进行开发,但是其底层会将这些语法转换为各个端所支持的语法。例如,对于小程序端,Taro 会将 JSX 转换为小程序模板语言 WXML,将 CSS 转换为小程序样式文件 WXSS。
Taro 在开发过程中,会先将使用类 React 语法编写的代码进行解析和转换,转换成对应端所支持的代码。对于小程序端,Taro 会将 JSX 转换为 WXML,将 CSS 转换为 WXSS,将 JavaScript 转换为小程序所支持的 JavaScript。这个过程主要使用了类似 Babel 的语法转换工具进行转换。
- API 封装:Taro 对各个端的 API 进行了封装,提供了一致的 API 接口,开发者无需了解每个端的具体实现细节,可以通过 Taro 提供的 API 接口来调用对应端的功能。
Taro 为了让开发者可以在不同端上调用相同的 API,对各个端的 API 进行了封装。例如,Taro 提供了
Taro.navigateTo函数来跳转到下一个页面,这个函数在小程序端会调用wx.navigateTo,在 H5 端会调用window.location.href,在其他端会调用相应的 API。
- 虚拟 DOM:Taro 使用了虚拟 DOM 的概念来进行跨端渲染,将 React 组件在各个端进行渲染时,先将组件转换为一棵虚拟 DOM 树,再根据具体端的渲染规则将其渲染为对应端的组件。
Taro 在跨端渲染过程中,会先将 React 组件转换为一棵虚拟 DOM 树,再根据各个端的实际渲染规则将其渲染为对应端的组件。这个过程使用了虚拟 DOM 的概念,可以避免直接操作 DOM 带来的性能问题
- 打包构建:Taro 通过类似 Webpack 的打包构建方式,将各个端的代码打包为对应端的代码,并且提供了一些优化方式,例如 tree shaking、code splitting 等,可以减小包体积,提高应用性能。
Taro 在构建过程中,会将各个端的代码打包为对应端的代码,并且提供了一些优化方式,例如 tree shaking、code splitting 等,可以减小包体积,提高应用性能。在打包构建时,Taro 会根据开发者所选择的端来选择对应的构建工具进行构建。例如,对于小程序端,Taro 会使用微信小程序原生的构建工具进行构建,而对于 H5 端,Taro 则会使用 Webpack 进行构建。
taro2和taro3的区别
Taro 2 和 Taro 3 是同一个跨端开发框架 Taro 的不同版本,它们之间存在以下一些区别:
- React 版本:Taro 2 默认使用 React 16.x 版本,而 Taro 3 默认使用 React 17.x 版本。React 17.x 版本主要改进了事件系统和组件渲染,提高了应用程序的性能。
- 支持的平台:Taro 2 支持的平台包括微信小程序、百度智能小程序、支付宝小程序、QQ 小程序、京东小程序、快应用、H5 和 RN 等,而 Taro 3 新增了对字节跳动小程序和 QQ 轻应用的支持,同时去除了对快应用的支持。
- 构建工具:Taro 3 将 Taro CLI 的构建工具从 Webpack 替换为了 Vite,可以提供更快的构建速度和更好的开发体验。
- TypeScript 支持:Taro 3 对 TypeScript 的支持更加完善,提供了更好的类型推导和类型检查。
- 生命周期:Taro 3 增加了一些生命周期函数,例如
componentDidCatch和getSnapshotBeforeUpdate等。
常用api
环境判断
- Taro.getEnv(), Taro.ENV_TYPE
- **Taro.getEnv()获取当前环境值,具体值如 **
Taro.ENV_TYPE - 常用于判断h5以及小程序,根据环境来指定组件以及方法
- **Taro.getEnv()获取当前环境值,具体值如 **
Taro.ENV_TYPE.WEAPP 微信小程序环境
Taro.ENV_TYPE.WEB WEB(H5)环境
.....
参考资料
具备taro开发多端经验
taro
配置
- defineConstants : 全局变量配置
config/index
const config = {
h5: {
publicPath: process.env.NODE_ENV === "production" ? "./" : "/",
staticDirectory: "static",
output: {
filename: "js/[name].[hash:8].js",
chunkFilename: "js/[name].[chunkhash:8].js",
},
postcss: {
autoprefixer: {
enable: true,
config: {
overrideBrowserslist: [
"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]",
},
},
},
miniCssExtractPluginOption: {
filename: "[name].css",
chunkFilename: "[name].css",
},
esnextModules: ["taro-ui", "@taroify"],
},
}
自定义tabbar
- h5不支持自定义tabbar,可在custom-tab-bar返回null,为了兼容h5和小程序,【这样就不会导致2个tabbar】,额外写一个自定义的tabbar组件在需要的页面引入
//隐藏tabbar
.taro-tabbar__tabbar-bottom {
display: none;
}
问题
h5生产环境出现白屏
- 在config/index.js配置
- **配置publicPath为 **
./
- **配置publicPath为 **
const config = {
h5:{
publickPath:process.env.NODE_ENV === 'production'?'./':'/'
}
}
监听路由
import Taro, { eventCenter } from '@tarojs/taro';
eventCenter.on("__taroRouterChange", ({ toLocation: { path } }) => {
console.log("目标路由path:" + path);
});
携带参数跳转tabbar
- 注意以下方式会出现问题:
- switchTab:需要跳转的 tabBar 页面的路径(需在 pages.json 的 tabBar 字段定义的页面),路径后****不能带参数
- reLaunch
- 需要跳转的应用内页面路径 , 路径后可以带参数。可以跳转到tabBar页面但是跳转到t****abBar页面拿不到传递的参数
- navigateTo
- 需要跳转的应用内****非 tabBar 的页面的路径 , 路径后可以带参数。** **注:页面跳转路径有层级限制,不能无限制跳转新页面
小程序页面栈最多十层!
解决方案:
- 利用缓存,把跳转参数放到数据缓存中,setStorage
使用 H5 标签编写 Taro 应用
Web 端沉淀了大量优秀的库和组件,希望能直接在小程序端进行复用,解放生成力
希望能减少 H5 应用迁移到小程序端的成本,甚至能够直接运行在小程序端。
配置插件:
- @tarojs/plugin-html
实现索引选择器
参考
- https://juejin.cn/post/6845166891883823112#heading-1
- https://github.com/yrobot-npm/react-mobile-indexList
- **基于 **
ScrollView实现一个索引选择器
思路:
- 1、获取左侧每个列表区块的高度
- 2、计算每个列表区块的高度区间
- 3、在dom元素加载完,计算右侧每个索引导航的高度:
- 4、在dom元素加载完,调用计算列表区块的高度区间的方法
- 5、
onScroll监听左侧ScrollView组件纵向滚动的值e.detail.scrollTop,计算e.detail.scrollTop落在DOMHeight数据的哪个区间,获取索引值,设置右侧索引导航的高亮: - **6、右侧索引导航添加 **
touchStart、touchMove事件,监听并计算出在索引导航上移动的距离和移动了几个索引值
**获取 **DOM 元素的兼容方法:
- H5、微信小程序 :
Taro.createSelectorQuery() - **支付宝小程序 **
my.createSelectorQuery()
小程序如何实现sessionStorage功能?
- 1、使用数据存储,在小程序退出后台的时候onHide,就清除变量
- 使用storage(),在小程序App onHide()时或者App重新启动时,上使用clearStorage(),清除存储
- 2、使用App中的globalData属性,作为一个全局变量缓存在App中,当App销毁时会自动垃圾回收
如何获取DOM节点?
多端同步调试
**可以在 dist 目录下创建一个与编译的目标平台名同名的目录,并将结果放在这个目录下,例如编译到微信小程序,最终结果是在 dist/weapp 目录下,这样做的好处是,各个平台使用独立的目录互不影响,从而达到多端同步调试的目的,在 **config/index.js 配置如下:
/config/index.js
outputRoot: `dist/${process.env.TARO_ENV}`
Input组件触发键盘事件
通常输入框,输入完之后,希望通过按回车键/搜索键就能直接进行搜索
- onKeyDown事件
- event.detail.keyCode
键盘码:
- 回车键: 13
收起键盘:
参考:https://segmentfault.com/a/1190000021622684
document.activeElement.blur()
自定义导航栏Navbar
taro的导航栏,在微信浏览器可以看到每个页面的导航标题,但是在钉钉上打开h5,发现导航标题没有更新,刷新才会更新,所以只能自己自定义导航栏了。。
- 1、在components文件夹定义Navbar导航组件
- 2、在需要的页面引入
小程序
注意事项
- Text不能嵌套View可能会有问题,用View嵌套View即可
开发小程序准备工作
- 1、申请账号,微信公众平台注册一个账号,因为无论是前期的开发,还是后期的发布、运营都需要使用到这个账号
- 2、获取AppID和Secrect,并获取token及存储刷新token
- 3、域名配置
appid按环境自动切换
微信的appid在正式环境和测试环境不同,需要手动切换appid,比较容易出错。最好实现执行指令的时候直接自动处理
- 利用cross-env
Taro打包小程序体积优化
- optimizeMainPackage:优化主包的体积大小
自定义hooks
useHeight
- 获取高度,用于动态获取高度
- 可用于赋值给ScrollView组件来指定高度
import { useRef, useEffect, useState } from 'react';
import Taro from '@tarojs/taro';
import { forEach, sumBy, map } from 'lodash-es';
// 获取高度,【用于动态高度来兼容不同设备】
export default function useHeight(domList = []) {
const query = Taro.createSelectorQuery();
const { windowHeight } = Taro.getSystemInfoSync();
const [heightMap, setHeightMap] = useState({});
const restHeight = useRef(0);
useEffect(() => {
Taro.nextTick(() => {
forEach(domList, (item, index) => {
query
.select(item)
.boundingClientRect(res => {
setHeightMap(state => ({ ...state, [item]: res.height }));
})
.exec();
});
});
}, []);
useEffect(() => {
restHeight.current = windowHeight - sumBy(map(heightMap));
}, [heightMap, windowHeight]);
return {
heightMap,
restHeight: restHeight.current, //页面剩余高度
windowHeight
};
}
接入腾讯有数无痕埋点能
腾讯有数无痕: 全自动埋点 【 全自动埋点则是不管需不需要,将所有的点都埋了】
腾讯和 Taro 团队共同推出 腾讯有数自动化埋点,接入超级简单。比如配置 proxyPage 为 true 即可 “上报所有页面的 browse 、leave、share 等事件”,配置 autoTrack 为 true 即可 “自动上报所有元素的 tap、change、longpress、confirm 事件
h5:文档:https://mp.zhls.qq.com/youshu-docs/develop/sdk/es6.html
- 安装SDK
taro小程序生命周期
- componentDidShow | useDidShow
- 组件展示出来时触发,与原生小程序的
onShow生命周期相对应。
- 组件展示出来时触发,与原生小程序的
- componentDidHide | useDidHide
- 组件被隐藏时触发,与原生小程序的
onHide生命周期相对应
- 组件被隐藏时触发,与原生小程序的
- onUnload | useUnload
- 在小程序环境中对应页面的
onUnload。
- 在小程序环境中对应页面的
问题总结
1、移动端表格问题
在移动端中很少有表格方案由于场景比较少,组件库也没有提供,尤其在taro多端的,需要兼容H5和小程序,可以自己写一个table
2、esnextModules
配置需要额外的编译的源码模块,比如 taro-usi:
- 让taro去通过postcss编译处理 taro-ui 模块
- **配置之后,代码中引入的处于 **
node_modules/taro-ui/路径下的样式文件均会经过 postcss 的编译处理
3、下拉刷新/上拉加载问题
注意:
- ScrollView的下拉刷新只支持微信小程序
- onRefresherPulling、onRefresherRefresh、onRefresherRestore等下拉相关api都只在小程序有效,h5不支持
- ScrollView的上拉加载,onScrollToLower回调事件的支持度
3、在弹出层中,usePageScroll不触发
- 如果要触发滚动事件,可在弹出层里面使用ScrollView组件的onScroll事件
4、弹出层,popup出现抖动,可把动画去掉
4、ios 低版本 出现 Cant find variable: globalThis
-
参考:https://blog.csdn.net/weixin_44176432/article/details/117257826
-
解决方法:
- 1、在html文件引入
<script src="https://unpkg.com/@ungap/global-this@0.4.4/min.js"></script>- 或在html引入script脚本
<script>//兼容低版本ios!function(t){function e(){var e=this||self;e.globalThis=e,delete t.prototype._T_}"object"!=typeof globalThis&&(this?e():(t.defineProperty(t.prototype,"_T_",{configurable:!0,get:e}),_T_))}(Object);</script>
5、解决 ios10 及以上 Safari 无法禁止缩放的问题
<script>
window.onload = function () {
var isIOS = navigator.userAgent.match(/(iPhone\sOS)\s([\d_]+)/);
if (isIOS) {
document.addEventListener("touchstart", function (event) {
if (event.touches.length > 1) {
event.preventDefault();
}
});
var lastTouchEnd = 0;
document.addEventListener(
"touchend",
function (event) {
var now = new Date().getTime();
if (now - lastTouchEnd <= 300) {
event.preventDefault();
}
lastTouchEnd = now;
},
false
);
document.addEventListener("gesturestart", function (event) {
event.preventDefault();
});
}
};
let _ENV = window.location.host;
console.log(_ENV);
// 非生产环境,额显示调试窗口
// if (_ENV !== 'minishop.by-health.com') {
// const vconsole = new VConsole();
// }
</script>
6、底部tabbar切换,不刷新问题
- 使用onShow/useDidShow
7、taro3 使用formType='submit'可能会有兼容问题
- 解决方式: 使用onClick, 建议不要使用Button的formType
8、样式加载问题,部分浏览器,加载不完整
- 可能由于缓存问题,清一下缓存
9、首页样式无法加载
- 首页样式,可以放在app.js引入来解决
10、缓存问题太严重,无法看到最新页面
参考:https://www.jianshu.com/p/1672ba03acb4
问题:
我们每次发布H5更新的时候总会遇到这样的问题,用户在微信中看到的H5页面是没有改动过的,但是我们明明已经更新了H5,只能清理缓存才能看到最新的修改。
原因:
因为微信官方的web-view 是会缓存页面静态资源的比如:js、css、图片等,优先显示的缓存中的资源,过一段时间(时间不定,一天或者几小时,无明显规律)是可以自动进行缓存清除的,但是对于当时用户来说想要第一时间就看到正确的页面。
const config = {
...
h5: {
publicPath: '/',
staticDirectory: 'static',
output: {
filename: 'js/[name].[hash].js',
chunkFilename: 'js/[name].[chunkhash].js'
},
imageUrlLoaderOption: {
limit: 5000,
name: 'static/images/[name].[hash].[ext]'
},
miniCssExtractPluginOption: {
filename: 'css/[name].[hash].css',
chunkFilename: 'css/[name].[chunkhash].css',
},
...
},
}
静态文件的目录,然后每次通过
npm run build:h5命令打包程序的时候,会自动将静态资源文件后面追加hash数值,这样静态文件发生变化的时候会生成新的hash值,这样每次发包的静态文件路径就是不同的了,所以升级版本就避免了缓存的问题
- 静态文件发生变化了,这样浏览器就不会去请求缓存的资源了
11、安卓手机加载报错: 'super' keyword unexpected here
- **看看报错信息是出自那个文件,哪里有 **
super关键词 - super关键词可能没有被编译,可以使用babel进行转换。或者修改代码把super去掉
12、尺寸单位问题
- **在 Taro 中尺寸单位建议使用 **
px、百分比 %,Taro 默认会对所有单位进行转换 - **即从设计稿上量的长度 **
100px,那么尺寸书写就是100px,当转成微信小程序的时候,尺寸将默认转换为100rpx,当转成 H5 时将默认转换为以rem为单位的值
rpx单位是微信小程序中css的尺寸单位,rpx可以根据屏幕宽度进行自适应
1rpx = 0.5px = 1物理像素
**Taro 会帮你对样式做尺寸转换操作,但是如果是在 JS 中书写了行内样式,那么编译时就无法做替换了,针对这种情况,Taro 提供了 API **Taro.pxTransform 来做运行时的尺寸转换
注意:
- pxTransform 是根据设备的宽度进行转换,如果要计算高度的话用pxTransform会出现问题,在h5端,高度的话可用px解决
13、h5和小程序高度沾满的问题
h5中:
- body,html{height:100%};将body和html设置为100%,这样我们就可以在他们的子元素中使用height:100%来使的我们的容器元素占满屏幕的高度
小程序中:
- 小程序没用dom对象,通过调试发现小程序的根节点是page, 那么将page的高度设置height:100%即可
//h5
body,html{height:100%}
//小程序
page{height:100%}
14、小程序不存在root根元素,如何动态改变css变量
- 小程序不存在root根元素,如果需要动态改变css变量,
- **小程序只能在 **
page根元素里覆盖 CSS 变量。
- **小程序只能在 **
// h5
:root {
--primary-color: #ff4847;
--loading-color:#ff4847;
}
// 小程序
page{
--primary-color: #ff4847;
--loading-color:#ff4847;
}
15、h5在钉钉导航标题问题
- 钉钉导航栏标题是用钉钉内封装好的方法,需要引入钉钉的api方法去修改标题 ,dingtalk-jsapi
- 参考:https://open.dingtalk.com/document/orgapp-client/set-the-navigation-bar-title
//如果是钉钉平台,修改钉钉标题
if (dd.env.platform != 'notInDingTalk') {
//根据iOS的设计规范,iOS的标题在导航栏正中央。根据Android的设计规范,标题显示在导航栏左侧
dd.ready(() => {
dd.biz.navigation.setTitle({title:'标题'})
})
}
16、ScrollView在ios滚动加载数据,出现闪烁问题
- 利用scrollview组件,在下拉加载数据时候,在ios设备会出现闪烁问题
可能产生原因:
- 1、组件里嵌套子组件,这个子组件直接写在了父组件里,这写法可能会出现兼容问题。在安卓是没有问题的
- 建议:子组件写在另外文件里,通过导入方式来加载组件,不要直接写在父组件里包裹
17、获取屏幕高度 【100vh在ios兼容问题】
- 由于100vh在ios的safari上有问题,因为100vh 在safari和chrome浏览器中,100vh是指去掉地址栏和工具的高度,所以会出现滚动条
- 可以使用window.innerHeight来替代100vh
- 由于是跨端,为了兼容H5和小程序可以使用Taro.getSystemInfoSync()
18、小程序使用scroll-view中使用sticky吸顶问题
参考:https://developers.weixin.qq.com/community/develop/article/doc/000202ebeb046859fc99548c756813
<ScrollView scrollY style={{height:'400px'}}>
<View style="position: sticky"> 1 </View>
<View> 2</View>
</ScrollView>
因为平台scroll-view的特性问题,sticky元素在离开了原定的scroll-view的height距离后,就不能识别scroll-view的距顶高度了,所以用一个无样式的view撑开整个scroll-view中元素的高度,让这个view以能够替代scroll-view被获取高度,从而达到样式正常
解决:
<ScrollView scrollY style={{height:'400px'}}>
<View>
<View style="position: sticky"> 1 </View>
<View> 2</View>
</View>
</ScrollView>
19、小程序的windowHeight的高度包不包括tabBar高度的问题
- Android系统,windowHeight包含tabBar的高度
- iOS系统, windowHeight不包括tabBar的高度
20、小程序tabbar的icon图片限制大小问题
- icon 大小限制为40kb,建议尺寸为 81px * 81px,不支持网络图片
21、微信浏览器iphone,底部tabbar横线适配
在钉钉打开h5,底部tabbar没有问题,在钉钉自动适配了,在微信浏览器需要自己去适配
通过css去设置:
viewport-fit-descriptor env() 和 constant() iOS11 新增特性,Webkit 的一个 CSS 函数,用于设定安全区域与边界的距离,有四个预定义的变量:
padding-bottom: constant(safe-area-inset-bottom);
padding-bottom: env(safe-area-inset-bottom);
第一步:设置网页在可视窗口的布局方式 新增 viweport-fit 属性,使得页面内容完全覆盖整个窗口:
H5网页设置viewport-fit=cover的时候才生效,小程序里的viewport-fit默认是cover
<meta name="viewport" content="width=device-width, viewport-fit=cover">
js如何获取底部安全区域是多少?
- 利用css变量
env()和constant(),是IOS11新增特性,Webkit的css函数,用于设定安全区域与边界的距离,有4个预定义变量:
- safe-area-inset-left:安全区域距离左边边界的距离
- safe-area-inset-right:安全区域距离右边边界的距离
- safe-area-inset-top:安全区域距离顶部边界的距离
- safe-area-inset-bottom :安全距离底部边界的距离
constant:兼容 IOS<11.2
env: 兼容 IOS>11.2
:root {
// iOS < 11.2
--sat: constant(safe-area-inset-top);
--sar: constant(safe-area-inset-right);
--sab: constant(safe-area-inset-bottom);
--sal: constant(safe-area-inset-left);
// iOS >= 11.2
--sat: env(safe-area-inset-top);
--sar: env(safe-area-inset-right);
--sab: env(safe-area-inset-bottom);
--sal: env(safe-area-inset-left);
}
在JavaScript中,通过以下方法,读取到css自定义变量
- 注意:返回的是带有px单位的
getComputedStyle(document.documentElement).getPropertyValue("--sat")
22、node-sass问题【使用dart-sass替换】
- taro已经从node-sass替换成dart-sass了
- taro对sass默认使用dart-sass,只需要安装sass即可
dart-sass是node-sass的替代品
Dart Sass是Sass的主要实现,这意味着它在其他实现之前先获得了新功能,它快速,易于安装,并且可以编译为纯JavaScript,从而可以轻松集成到现代Web开发工作流中。
Sass官方目前主力推dart-sass,最新的特性都会在这个上面先实现。
23、taro打包出来体积大,如何优化?
小程序编译优化指南
24、useReady/onReady使用问题
- useReady 只能用于最顶层的页面组件中。在子组件中不会调用。