在使用React开发web页面的时候,一般都会使用react-router
来实现路由功能,相较于native路由流畅丝滑的体验,web页面切换起来会很生硬。作为从 iOS 转前端的我来说,尤其不能接受,因此,在 react-router 的基础上,写了一个 Router 库 react-router-virgo,让使用者只需要一行代码 + 一个路由配置文件
就可以使 Web 页面切换能达到native路由切换的流畅体验。
react-router-virgo 简介
这个路由组件还没完全达到我的预期,后面有时间会继续迭代优化。目前这个路由组件支持以下功能:
- 无转场动画切换(现有的 web 页面切换体验)
- push 动画切换(右侧淡入,右侧淡出)
- present 动画切换(下方淡入,下方淡出的模态切换)
- 支持 HashRouter,BrowserRouter 两种路由
总体上,基本能达到 native 路由的切换体验,当然,毕竟是 web 页面,相对于 iOS 的原生的 native 路由体验还是有点差距,感兴趣的也可以 运行完整 demo体验下。。。
下面我们来简要看一下实现原理吧
简单来说,react-router-virgo
是在 react-router 和 react-transition-group 的基础上进行二次封装的 Router。这里也会分这两部分进行递进分析
一、react-router
首先,我们先简要介绍下 react-router 的基本用法(详细看官网介绍)。
我们主要使用到 react-router 提供的 HashRouter/BrowserRouter,Switch,Route 三个组件。
1.1 Router
react-router 主要提供了两种 Router
HashRouter: hash 形式实现的路由,使用
createHashHistory
创建的 historyBrowserRouter:以 html5 提供的 history api 形式实现的路由,使用
createBrowserHistory
创建的 history
1.2 Route
路由组件,path
指定匹配的路由,component
指定路由匹配时展示的组件(Route 也可以通过 children 和 render 的形式创建展示的组件)。
1.3 Switch
多个 Route 组件同时匹配时,默认都会显示,但是被 Switch 包裹起来的 Route 组件只会显示第一个被匹配上的路由。路由的转场动画,其实就是基于 Switch 进行封装,使页面切换时,具有动画效果。
1.4 代码演示
使用
react-router-dom
中的HashRouter/BrowserRouter
、Route
、Switch
实现的一个简单的无动画路由,代码如下:
import React from 'react';
import { HashRouter, Route, Switch } from 'react-router-dom';
import { RouterConfig } from './routerConfig';
const Router = () => (
// 这里使用 HashRouter , 也可以使用 BrowserRouter
{RouterConfig.map((config, index) => {
return ;
})}
);
export default Router;
那怎么让页面切换的时候,带有转场动画效果呢,这就需要结合 react-transition-group 了
二、react-transition-group
在介绍实现转场动画之前,我们得先学习如何使用 react-transition-group。这里仅对我们使用到的 CSSTransition
和 TransitionGroup
这两个组件展开简要介绍。
2.1 CSSTransition
CSSTransition 是会自动给包裹的组件添加样式的过渡动画组件。我们先来看下 CSSTransition 的属性:
属性 | 详情 |
---|---|
in |
取值 true/false ,决定包裹的元素是要进行出场动画还是入场动画 |
timeout |
设置动画时间 |
实际上,CSSTransition 并没有给组件任何动画效果,只是在一段时间内,给包裹的组件加上三个类,我们可以在这个三类中写动画效果。
- in 属性的值从 false 变为 true,就给元素加上下面的三个类(这里前缀
xxx
代指设置的 class,默认是fade
),即执行入场动画:
css 类 | 详情 |
---|---|
xxx-enter |
入场动画的第一个瞬间(帧)加入的,动画即将结束前消失 |
xxx-enter-active |
xxx-enter 加入后,第二个瞬间加入,持续到入场动画即将执行完成,动画即将结束前消失 |
xxx-enter-done |
入场动画结束瞬间,加入之后一直存在 |
- 相反地,当 in 属性置为 false 时,CSSTransition 会给子组件加上
xxx-exit
、xxx-exit-active
、xxx-exit-done
的 class。(更多详细介绍可以戳官网查看)
基于以上两点,我们给打开页面时的 class 设置为forward-from-right
,则对应的 css 样式:
/**
* 打开页面:右侧淡入,右侧淡出
*/
.forward-from-right-enter {
z-index: 2;
transform: translate3d(100%, 0, 0);
}
.forward-from-right-enter-active {
z-index: 2;
transform: translate3d(0, 0, 0);
transition: all 300ms;
}
.forward-from-right-enter-done {
z-index: 2;
}
.forward-from-right-exit {
z-index: 1;
transform: translate3d(0, 0, 0);
}
.forward-from-right-exit-active {
z-index: 1;
transform: translate3d(-30%, 0, 0);
transition: all 300ms;
}
.forward-from-right-exit-done {
z-index: 1;
}
2.2 TransitionGroup
用 CSSTransition 可以实现单个页面的动画,而路由的转场动画需要管理新旧两个页面的联动切换。那么如何让新旧页面在切换的过程中,同时存在两个 DOM 节点,在切换结束后,再移除旧节点呢?
为此我们再来介绍 react-transition-group 提供的TransitionGroup这个组件。
如官网介绍,TransitionGroup 组件就是用来管理一堆节点 mounting 和 unmounting 过程的组件,非常适合处理路由切换的情况。TransitionGroup 在感知到其 children 变化时,会先保存住即将要被移除的节点,而在其动画结束时才会真正移除该节点。
2.2 代码演示
使用
react-transition-group
中的TransitionGroup
和CSSTransition
对 Switch 进行封装,实现路由转场动画组件AnimatedSwitch
import React from 'react';
import { Switch, withRouter } from 'react-router-dom';
import { CSSTransition, TransitionGroup } from 'react-transition-group';
import './AnimatedSwitch.css'; // 动画样式
let oldLocation = null;
class AnimatedSwitch extends React.Component {
static propsTypes = {
routerConfig: PropsTypes.array.isRequired,
};
render() {
const { location, history, children, routerConfig } = this.props;
let classNames = '';
if (history.action === 'PUSH') {
// 打开页面的转场动画
classNames = 'forward-from-right';
} else if (history.action === 'POP' && oldLocation) {
// 关闭页面的转场动画
classNames = 'back-to-right';
}
oldLocation = location;
// 使用 TransitionGroup 和 CSSTransition 包裹 Switch,实现转场动画
return (
React.cloneElement(child, { classNames })}
>
{children}
);
}
}
// 通过 withRouter 包裹,可以从props中获取location,history等对象。
export default withRouter(AnimatedSwitch);
至此,路由转场动画算是基本实现了。
react-router-virgo 使用手册
一行代码 + 一个路由配置文件,就可以实现 react-router 的功能,并让你的Web页面切换达到匹配 Native 路由的转场动画体验
一、概述
react-router-virgo是在 react-router 和 react-transition-group 的基础上进行二次封装的 Router,使集成路由功能变得极其简单。此外,还增加了路由转场动画等扩展功能:
无转场动画
,Push 转场动画
,Present 转场动画
二、安装 Router
### 使用npm
npm install --save react-router-virgo
### 使用yarn
yarn add react-router-virgo
三、 设置路由配置文件
设置路由配置项
RouterConfig.js
3.1 代码演示
import { Home, Detail, PushDetail, PresentDetail } from './pages/index';
// 例举了无动画、push转场动画、present转场动画三种场景
export const RouterConfig = [
{ path: '/', component: Home },
// 无转场动画(新页面直接覆盖当前页面)
{
path: '/detail/:type',
component: Detail,
sceneConfig: {
enter: 'no-animation',
exit: 'no-animation',
},
},
// push 转场动画(打开时,从左往右覆盖;关闭时,从右往左收回)
{
path: '/push/detail/:type/:id',
component: PushDetail,
sceneConfig: {
enter: 'from-right',
exit: 'to-right',
},
},
// present 转场动画(打开时,从下往上弹起;关闭时,从上往下收起)
{
path: '/present/detail',
component: PresentDetail,
sceneConfig: {
enter: 'from-bottom',
exit: 'to-bottom',
},
},
];
3.2 配置项说明
key | 说明 | 类型 | 默认值 | |
---|---|---|---|---|
path |
路由路径,可以带参数,在/: 后的为参数,如 /detail/:id , 参数为 id |
string | 必传 | |
component |
路由路径映射的页面组件 | class | 必传 | |
sceneConfig |
路由转场动画配置,支持无动画、push 动画、present 动画三种场景,默认使用 push 动画 | object | {enter: 'from-right', exit: 'to-right'} |
可选 |
exact |
是否使用精准匹配 | bool | true | 可选 |
- 路由转场动画参数
sceneConfig
配置,支持以下三种场景
1.无动画配置:{
enter: 'no-animation',
exit: 'no-animation',
}
2.push动画配置: {
enter: 'from-right',
exit: 'to-right',
}
3.present动画配置: {
enter: 'from-bottom',
exit: 'to-bottom',
}
四、添加 Router
在入口文件
App.js
中添加Router
4.1 代码演示
import React from 'react';
import Router from './router/Router';
import { RouterConfig } from './RouterConfig';
import './index.css';
function App() {
// RouterConfig 为路由配置文件
return ;
}
export default App;
4.2 API 说明
属性 | 说明 | 类型 | 默认值 | |
---|---|---|---|---|
routerConfig |
路由配置数据 | array | [] | 必传 |
useBrowserRouter |
路由类型 BrowserRouter/HashRouter,默认使用 HashRouter | bool | false | 可选 |
useAnimatedSwitch |
是否使用转场过渡动画 | bool | true | 可选 |
如果
五. 常见问题
Q:支持哪些路由类型?
目前支持 BrowserRouter 和 HashRouter 两种类型,可通过属性useBrowserRouter
来设置,默认使用 HashRouter
Q:支持哪些转场动画?
目前支持无动画、从下往上弹起的 Present 动画,从右往左打开的 Push 动画三种场景。可以在路由配置文件中按规则配置sceneConfig
即可,如果未配置 sceneConfig 字段,则默认使用 Push 动画
Q:打开新页面后,上一级页面是否会被销毁?
会被销毁,返回上一级页面时,页面会重新渲染,后续版本迭代会支持 Stack 路由功能。
Q:安装后,编译失败的原因?
确认下项目里是否有 react-router-dom
、react-transition-group
这 2 个依赖,如果没有,请通过 yarn 或者 npm 引入依赖
yarn add react-router-dom react-transition-group
Q:是否支持 ts 开发的项目
后续迭代会支持
六. 其它
更具体的信息大家感兴趣的话去看代码吧,如果发现 bug,请提一个issue,我会第一时间进行修复和优化...
github: https://github.com/JackXJR/react-router-virgo
欢迎使用,觉得不错请给一个小小的 star 鼓励一下~