Hippy 提供了 Navigator 组件,用于页面导航、跳转。
但是 Navigator组件有比较大的局限性, 该组件通过启动一个新的 Hippy 实例实现,在 2.0 下实例之间可能无法互相通信,iOS 上也必须作为根节点包裹所有子组件,使用有很大限制。
@hippy/react 以及 @hippy/react-web 中的 Navigator 组件功能相对比较欠缺,两端都没有比较好的实现页面跳转的功能。两端的功能也存在着差异,导致无法实现原生和web的同构
以下是 @hippy/react 和 @hippy/react-web 中的 Navigator 组件的实现方式
@hippy/react 路由实现Navigator 组件中,通过实例化一个 Hippy 实例进行渲染展示,同时对 Android 的回退键进行监听
// https://github.com/Tencent/Hippy/blob/312d0d963cac2d8cf60ff97ddd554a01e575cea0/packages/hippy-react/src/components/navigator.tsx#L125
constructor(props: NavigatorProps) {
super(props);
const { initialRoute } = props;
if (initialRoute && initialRoute.component) {
const hippy = new Hippy({
appName: initialRoute.routeName,
entryPage: initialRoute.component,
});
hippy.regist();
this.routeList[initialRoute.routeName] = true;
}
this.handleAndroidBack = this.handleAndroidBack.bind(this);
}通过调用原生 callUIFunction 执行页面返回
public pop(option: { animated: boolean }) {
if (this.stack.size > 1) {
const options = [option];
this.stack.pop();
callUIFunction(this.instance, 'pop', options);
}
}这种方式,两个页面之间无法进行数据互通,也无法传递数据
@hippy/react-web 路由实现相比于 @hippy/react, @hippy/react-web 中的 Navigator 组件则没有对应的实现功能
//https://github.com/Tencent/Hippy/blob/master/packages/hippy-react-web/src/components/navigator.tsx
/\* eslint-disable class-methods-use-this \*/
import React from 'react';
import { formatWebStyle } from '../adapters/transfer';
/\*\*
\* Simply router component for switch in multiple Hippy page.
\* @noInheritDoc
\*/
class Navigator extends React.Component {
pop() {
// TODO
}
push() {
// TODO
}
render() {
const { style } = this.props;
const newProps = Object.assign({}, this.props, {
style: formatWebStyle(style),
});
return (
<div {...newProps} />
);
}
}
export default Navigator;使用
react-router来管理多页面,实现Hippy原生和web的多页面切换
在 react 中,主要是由 react-router 来进行页面切换,支持多页面开发。同时也有native版的 react-router-native
react-router-native 是 react-router 的native版本,但是其基于 react-native 中比较完善的 Navigator 组件。经过分析和实现,无法在 Hippy 中直接使用 react-router-native
react-router 中的 MemoryRouter,基于纯js实现的路由,不需要依赖于 URL,这使得其可以应用在native
下面这个是关于 MemoryRouter 描述
A <Router> that keeps the history of your “URL” in memory (does not read or write to the address bar). Useful in tests and non-browser environments like React Native.因此使用 react-router 可以同时支持原生和web页面切换,进行多页面开发
Platform.OS 对当前平台进行判断MemoryRouter, 在web中使用 HashRouterreact-router 对多页面进行切换以下是 hippy 中 react-router 的使用方式
import React, { Component } from 'react';
import {
StyleSheet,
View,
} from '@hippy/react';
import {
MemoryRouter,
HashRouter,
Route,
} from "react-router-dom";
import routes from './route';
import { ISWEB } from './utils';
export default class App extends Component {
render() {
const Router = ISWEB ? HashRouter : MemoryRouter;
return (
<View>
<Router>
{
routes.map(item => {
return (
<Route key={item.path} exact path={`${item.path}`}><item.component meta={item.meta || {}} /></Route>
);
})
}
</Router>
</View>
);
}
}react-router 存在的问题react-router 能够在一定层度上解决 hippy 中多页面跳转的功能,是也存在一些问题
react-router-transition 动画hippy 项目Link 的使用过程中,需要传入 component。 原因是 Link 组件默认使用 a 标签,而 hippy 中不支持 a 标签// hippy 中 Link的使用方式
import { View } from '@hippy/react';
<Link to="/about" component={View}>About</Link>hippy 项目中页面切换除了项目中的页面切换,还存在着与客户端或者浏览器的交互
hippy 页面切换到客户端原生页面,需要客户端提供伪协议跳转支持。在web环境下,需要使用浏览器基础能力。因此需要进行兼容处理
hippy 项目中的页面切换主要有一下三种场景
场景 | 处理方式
---|---
hippy 项目内 | react-router
hippy -> 原生 | 原生伪协议支持
hippy -> web页面 | window.location 或者 window.open
* **原理分析**
react-router 通过 Context 将跳转路由的函数, 如 goback, push,传递给组件
当组件需要使用到 react-router 功能时,通过 withRouter 高阶组件,向组件注入路由跳转函数
// withRouter 使用方式
// https://reacttraining.com/react-router/web/api/withRoute
import React from "react";
import PropTypes from "prop-types";
import { withRouter } from "react-router";
class ShowTheLocation extends React.Component {
static propTypes = { // 声明propTypes,从而获取router方法
match: PropTypes.object.isRequired,
location: PropTypes.object.isRequired,
history: PropTypes.object.isRequired
};
}
const ShowTheLocationWithRouter = withRouter(ShowTheLocation);withRouter 实现原理
// https://github.com/ReactTraining/react-router/blob/402ecabdc94e5aeb657c593d8af200625a09cdfe/packages/react-router/modules/withRouter.js#L11
<RouterContext.Consumer>
{context => {
return (
<Component
{...remainingProps}
{...context}
ref={wrappedComponentRef}
/>
);
}}
</RouterContext.Consumer>从 withRouter 的源码分析来看,其中 context 包含了 router 所有的方式,提供给组件使用,因此可以在 context 这一层,按照不同的平台,进行个性化处理
* **解决方案**
通过实现 withRouter 的逻辑,在 context 进行劫持处理
import { Platform } from '@hippy/react';
import { withHippyHistory } from './history.hippy';
import { withWebHistory } from './history.web';
const ISWEB = Platform.OS === 'web';
const wrapper = ISWEB ? withWebHistory : withHippyHistory
return (
<Component
{...remainingProps}
{...wrapper(context)}
ref={wrappedComponentRef}
/>
);// history.hippy.js
import { callNativeWithPromise } from "@hippy/react";
import { parsePath } from './util';
const createHook = (history, ) => {
function push (path, state) {}
function replace () {}
function go () {}
function goBack () {}
function goForward () {}
function open ({ hippyUrl }) {
return callNativeWithPromise('TgclubJsModule', 'callNativeAction', hippyUrl)
}
return { push, go, goBack, goForward, replace, open }
}
export function withHippyHistory (context) {
const { history } = context;
return {
...context,
history: {
...history,
...createHook(history)
}
}
}open 函数,用于跳转到非本项目的页面,使得在对业务层无感知。// history.web.js
const createHook = (history) => {
function open ({ webUrl, config }) {
if (webUrl) {
window.open(webUrl);
}
}
return { open }
}
export function withWebHistory (context) {
const { history } = context;
return {
...context,
history: {
...history,
...createHook(history)
}
}
}通过对 context 中函数的改造,统一不同平台的页面切换调用方式。而在 wrapper 里面针对平台进行特殊处理
hippy 项目内页面跳转适配系统返回上一页动作replace 操作需要终端配合,维护页面路由栈原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。