三个比较重大的含义:
React Native 与一般 Web 样式支持度差异较大,web 与小程序端支持的 CSS 样式能力比 RN 大得多。样式上 H5 最为灵活,小程序次之,RN 最弱,统一多端样式即是对齐短板,也就是要以 RN 的约束来管理样式,同时兼顾小程序的限制,核心可以用三点来概括:
RN 下仅支持 flex 布局;web 与小程序端则正常布局属性;
RN 下默认为 relative,支持 absolute;web 与小程序端则正常定位属性;
目前在 Taro 项目当中使用的样式是 css modules 的形式,因此如果多个组件当中使用了相同的 class 名就有可能发生同名 class 的样式覆盖的问题,因此需要使用一个统一的规范对不同组件的样式进行一个区分,这里团队选用的规范是 BEM。
想要在组件外对组件内部样式进行覆盖的情况,在跨端当中透传 class 会存在着奇奇怪怪的问题,例如 RN 端是不会对相关样式进行覆盖处理。
// 目前 Taro RN 端还未实现往组件传递 className 对应样式
// CompA,样式不生效
因此想要在组件外对组件内部样式进行覆盖使用内联的 style 方式是相对方便、兼容性好的方式。
这个角度上,又回到了前面提到的样式形式问题,最好使用的方案应该是 CSS-in-JS(styled-compoment),但是很可惜,Taro 目前还不支持(好像是因为小程序端的原生的不支持的限制)。
这里使用的是 Taro 默认的方案(只管写 px 单位,taro 会根据不同平台和配置的转换对应平台的单位和数值)。
https://taro-docs.jd.com/docs/size
这里 Taro 的底层是使用了 postcss 的一个二开插件postcss-pxtransform
来进行不同编译平台的单位与数值的转换:
https://www.npmjs.com/search?q=postcss-pxtransform
在 taro 当中,已经对不同的编译平台之间会存在差异进行提供样式编写条件编译的 API 扩展了,Taro 对 postcss 进行了扩展并且封装为 npm 插件postcss-crossplatformcomments
来注入相关的平台环境变量,这样子就能在 scss 当中根据平台判断来编写一些平台的特殊样式代码以及扩展 mixin 的能力适配多端:
https://www.npmjs.com/package/postcss-crossplatformcomments
// 这里简单演示一下相关的用法
.safe-area {
/* #ifdef h5 weapp tt */
@include safe-area();
/* #endif */
}
@mixin box-sizing($val) {
/* #ifndef rn */
box-sizing: $val;
/* #endif */
}
ps:但是可惜的是,这个官方提供平台判断仅限于编译的各个平台值,还没具体划分到 ios 还是 android 这两种不同机型平台划分的粒度差异,因此在安卓和 ios 有差异的情况下,目前的解决办法还是只能通过 api 判断出具体的机型,然后赋值不同的 style 或者 class 样式类进行对样式差异的处理。
相较于样式,端能力的差异倒是还好,各端差异是客观存在的,更不用说 RN 在 iOS 与 Android 上就已存在大量差异。
应对端能力差异,要么改变实现思路,例如 RN 端还不支持 Taro.(get/set)StorageSync,那就改用 async / await + Taro.(get/set)Storage 实现,要么就得使用环境判断方式了。
Taro 提供 process.env.TARO_ENV 用于环境判断
function foo() {
if (process.env.TARO_ENV === 'weapp') {
// 微信小程序逻辑
}
if (process.env.TARO_ENV === 'h5') {
// H5 逻辑
}
if (process.env.TARO_ENV === 'rn') {
// RN 逻辑
}
}
在 Taro 当中提供了另一种能编写针对跨端不同平台差异的写法,使用不同平台的后缀名来进行区分平台的条件编译与引入。
/components
|--/test
|--index.js // 保底通用
|--index.rn.js
|--index.h5.js
|--index.weapp.js
|--xxx
// 例如原先有一个组件 test.js
// 若需要分别实现 h5 端、RN 端的组件,则将相应组件命名为:
// index.h5.js,index.rn.js
// 这样只需要引入 test,Taro 会根据环境自动引入相应的组件
// 就不需要写 process.env.TARO_ENV 的判断了
import Test from '../../components/test'
render() {
// 例如编译 h5 时,实际引入的组件是 test.h5.js
// 组件只需要遵循对外接口统一即可
return
}
App 端的过渡:
受限于篇幅和相关的内容模块划分和组织上面,这期就先和大家分享下 taro 在多端开发当中对多端平台上的适配方面的基础。下一期我们接着进一步对项目当中的对多端实际运行差异的总结与相关差异组件的封装处理的介绍。