导读
背景
方案设计
详细内容参考( https://mp.weixin.qq.com/s/5pdUD9YNojgvZBSve5-2EA )
支持 React, Vue 开发,与小程序的设计思路一致,让 React Native 去模拟浏览器的 BOM/DOM API ,实现 React Native 的 render 支持 React 开发,通过编译和运行时去适配 Taro 的写法
基于小程序的方案,运行在 React Native 端,性能会有所下降,且方案更加复杂化,维护成本太高 脱离 React Native 生态,比如一些原本可直接使用的组件,需要做一层适配才可使用
详细设计
入口文件及配置,Taro 入口写法是基于小程序的方案,需将其转换为 React Native 的入口及路由导航系统 页面的配置,对下拉属性,滚动,页面 Title 等相关设置 生命周期, componentDidShow, componentDidHide 的支持 页面函数,onPullDownRefresh, onPageScroll 等 事件、Taro 自定义 Hooks、 Current 对象 -
样式的支持,这里不过多的赘述,后续会有详细的文章说明
方案实现
Resolution:构建模块的依赖图,处理模块的依赖关系 Transformation:负责将模块转换成目标平台可以理解的格式 Serialization:模块转换序列化,组合这些模块来生成一个或多个包
在编译阶段,页面源文件都会进入到自定义的 taro-rn-transformer ,在 rn-transformer 中,会根据编译配置,一是,入口及页面会
注入运行时处理函数, 二是,在 React Native 中,样式并没有全局概念,对于 Taro 中定义的全局样式,比如 app.scss 等,在进入到 rn- transformer,会全局样式引入到页面中,支持到全局样式。在代码运行阶段,运行时处理函数会适配到Taro的相关内容,包含动态构建导航,页面配置,生命周期函数等相关内容,完成对入口,导航与页面的支持。
taro-router-rn,基 React Navigation 对路由进行封装,提供动态创建导航的方法给运行时,并且封装导航相应的API内容。
taro-runtime-rn,运行时的核心内容,主要提供两个包装方法,一是 createReactNativeApp,用来对页面入口的相关处理,二是 createPageConfig,页面的包装方法,完成对页面的适配,包含生命周期,页面的配置等。
taro-rn-transformer, 编译时注入页面的包装方法和入口方法,并将入口的全局样式注入到页面中。
入口文件支持
//app.config.ts
export default {
pages:[
'pages/index/index',
'pages/index/about'
],
window:{
backgroundTextStyle: 'light',
....
},
tabBar:[...]
}
//app.tsx
export defalut class App extends Component{
...
render(){
return this.props.children
}
}
读取 app.config ,获取到对应的页面信息,将页面在入口文件引入,建立起引用关系,根据页面路径转换为驼峰的形式来作为页面名称,生成构建导航系统的路由配置。
import { AppRegistry } from 'react-native';
import { createReactNativeApp } from '@tarojs/runtime-rn'
import App from './src/app'
import pagesIndexIndex from './src/pages/index/index';
import pagesIndexAbout from './src/pages/index/about'
var config = {"appConfig":{"pages":["pages/index/index","pages/index/about"],
"window":{"backgroundTextStyle":"light","navigationBarBackgroundColor":"#fff"}}}
const routers = [
{
name:'pagesIndexIndex',
component: pagesIndexIndex
},{
name:'pagesTabbarHome',
component: pagesIndexAbout
}]
AppRegistry.registerComponent('app',createReactNativeApp(App,{config,routers})
根节点Provider的注入 导航初始化
function createReactNativeApp (App,config){
return class Entry extends React.Component{
...
render(){
return React.createElement(TCNProvider, { ...this.props },
React.createElement(App, { ...props },
createRouter(config.routerConfig)
))
}
}
}
对于根节点Provider注入,由于在 taro-component-rn 的 Picker 组件是封装的 Ant-Design 组件,需要注入 Ant-Design 的 Provider -
对于导航系统初始化,Taro 3 仍然是采用 React Navigation,和 Taro 1/2 的差别是,升级到了 5.x 的版本。封装导航模块,根据转换生成的路由配置,提供 createRouter 的方法,动态去创建路由节点,构建出导航系统
页面支持
import { createPageConfig } from '@tarojs/runtime-rn'
//页面文件
import pagesIndexIndex from './src/pages/index/index'
//页面config
import pageConfig from './src/pages/index/index.config'
export default createPageConfig(pagesIndexIndex,pageConfig)
页面函数,包括了 onReactBottom, onPullDownRresh 等 生命周期函数,包含了 componentDidShow, componentDidHide,这两个函数对应小程序的 onHide, onShow
disableScroll 是否可滚动, enablePullDownRresh 是否开启下拉刷新。
对于onPageScroll,onReachBottom , onPullDownRresh 都与页面滚动相关联, 当 config 配置 disablecroll 不为true时,对应的页面外层会用 ScrollView 包含对应的页面组件,实现对页面函数的支持
onPageScroll, 通过监听 ScrollView 的 onScroll 方法实现 onReachBottom, 监听页面滚动动画结束函数 onMomentumScrollEnd ,来判断当前的离底部高度,终来触发该函数 -
onPullDownRresh, 当enablePullDownRresh为 true 时,开启下拉刷新,通过封装 refreshControl 来实现 function createPageConfig(Component,config){
const WrapScreen = (PageComponent) => {
return class PageScreen extends React.Component{
...
render(){
return <ScrollView
...
onScroll={()=>{}}
refreshControl={<RreshControll />}
>
<PageComponent />
</ScrollView>
}
}
}
return WrapScreen(Component)
}
onResize , onTabItemTap ,是基于 React Native 现有方案的实现
onResize, 在 React Native中,可监听屏幕高度变化,在 Taro 中,是通过监听屏幕的宽高变化来触发该方法 -
onTabItemTap , TabBar 是和导航相关联,我们导航是基于 React Navigation 的封装,监听导航的 tabPress 方法来触发 onTabItemTap
当页面发生跳转时 当App进行前后台切换的时
App前后台切换时,通过监听 AppState 的状态变化,状态切换的变化,可判断是从前台到后台,从而来触发对应的函数 -
我们的路由导航系统是基于 React Navigation, 页面切换时,导航提供了页面聚焦和是失去焦点时触发 focus 与 blur 事件,通过监听这两个事件,判断当前页面是否可见来触发对应函数
Current.app,返回当前小程序应用实例 Current.page,返回当前小程序页面实例, Current.router,返回当前小程序路由信息
对于 app 和 page ,返回小程序规范实例,可通过此实例调用小程序规范生命周期。其实现思路是,当页面切换时创建一个对象,对象包含小程序的生命周期方法,当调用该方法时,通过 ref 关联到的当前页面,来 call 当前页面的方法。
const pageRef = this.screenRef
const inst: PageInstance = {
config: pageConfig,
route: pagePath,
onShow () {
const page = pageRef.current
if (page != null && isFunction(page.componentDidShow)) {
page.componentDidShow && page.componentDidShow()
}
},
...
}
-
对于 router,基于 React Navigation 导航 获取到路由参数,返回到 router 对象中,目前暂不支持 onReady 等生命周期方法
原生 React Native 应用支持
与原有页面一起打包方案结合 路由需要统一处理 支持 Taro 的编译配置,页面函数等
提供 tarojs/rn-supporter 的包, 导出Taro3 的 Metro 配置,可支持以下内容 支持Taro样式写法 支持Taro编译配置 支持Taro运行时配置 支持Taro跨平台开发方案
提供运行时的函数,通过直接的调用运行时的包装函数,完成对页面内容的支持 支持页面函数,生命周期函数等 支持页面配置
import { createPageConfig } from '@tarojs/runtime-rn'
import PagesTaroPageApi from './src/pages/taroPage/api'
import PagesTaroPageApiConfig from './src/pages/taroPage/api.config'
<Stack.Screen
name="PagesTaroPageApi"
component={createPageConfig(PagesTaroPageApi, { pagePath: '/pages/taroPage/api',...PagesTaroPageApiConfig})} />
业务需自行处理导航 -
页面组件需要运行时函数包装
总结