Skip to content

Commit

Permalink
feat: add useAnimatedRoutes
Browse files Browse the repository at this point in the history
  • Loading branch information
qiqiboy committed May 14, 2022
1 parent 2ff39cf commit 09bfdca
Show file tree
Hide file tree
Showing 10 changed files with 667 additions and 424 deletions.
165 changes: 122 additions & 43 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,13 +1,25 @@
# react-animated-router

react 路由切换动画,支持嵌套路由 (nested routers)和动态路由(dynamic routers)
react 路由切换动画,支持嵌套路由 (nested routers)和动态路由(dynamic routers),对于`[email protected]`的路由嵌套有较好的支持,开箱即用!

> 当前版本要求`react-router-dom``v6`版本,如果您还在使用`v4``v5`,请查看 [[email protected]](https://github.com/qiqiboy/react-animated-router/tree/0.2.4)
> 当前版本要求`react-router-dom``v6`版本,如果您还在使用`v4``v5`,请查看安装 [[email protected]](https://github.com/qiqiboy/react-animated-router/tree/0.2.4)
<!-- vim-markdown-toc GFM -->

- [安装](#安装)
- [如何使用](#如何使用)
- [`AnimatedRouter`组件模式调用](#animatedrouter组件模式调用)
- [`useAnimatedRoutes` Hooks 模式调用](#useanimatedroutes-hooks-模式调用)
- [参数说明](#参数说明)
- [自定义动画](#自定义动画)
- [FAQ](#faq)

<!-- vim-markdown-toc -->

### 安装

```bash
npm install react-animated-router --save
npm install react-animated-router@latest --save
```

你可以直接通过`npm/yarn`安装,依赖包里带一个左右滑入滑出效果的`animate.css`,如果要使用该效果,需要在项目中一并引入。
Expand All @@ -30,34 +42,76 @@ import 'react-animated-router/animate.css'; //导入默认的切换动画样式
// 自己项目中的AnimatedRouter模块
import 'react-animated-router/animate.css'; //导入样式文件

export { default } from 'react-animated-router'; //直接将react-animated-route作为默认导出
export { default, useAnimatedRoutes } from 'react-animated-router'; //直接将react-animated-router作为默认导出
```

然后就可以直接引用该文件来使用 AnimatedRouter 了,不必每次都引入`animate.css`

### 如何使用

`react-animated-router`提供了与`Routes``useRoutes`类似的组件和 hooks 两种用法:

#### `AnimatedRouter`组件模式调用

`AnimatedRouter`是一个标准的 React 组件,它可以给一组`Route`组件增加动画切换效果,将它放入你的项目中,然后在需要支持动画的地方,使用`AnimatedRouter`替换你的`Routes`组件即可。

**`AnimatedRouter` 对于嵌套的路由声明也有效!**
```javascript
import React, { Component } from 'react';
import { render } from 'react-dom';
import { BrowserRouter, Routes, Route } from 'react-router-dom';
import { useAnimatedRoutes } from 'react-animated-router';
import 'react-animated-router/animate.css'; //导入默认的切换动画样式,如果需要其它切换样式,可以导入自己的动画样式定义文件

import Login from 'modules/Login';
import Signup from 'modules/Signup';
import NestLayout from 'modules/NestLayout';
import Nested from 'modules/Nested';

function App() {
/** 假如你的代码如此,则可直接使用最下方代码代替,即直接使用 AnimatedRouter 替换掉 Routes
* return (
* <Routes>
* <Route path="login" element={<Login />} />
* <Route path="signup" element={<Signup />} />
* <Route path="nested" element={<NestLayout />}>
* <Route path="1" element={<Nested id="1" />} />
* <Route path="2" element={<Nested id="2" />} />
* </Route>
* </Routes>
* );
**/

return (
<AnimatedRouter>
<Route path="login" element={<Login />} />
<Route path="signup" element={<Signup />} />
<Route path="nested" element={<NestLayout />}>
<Route path="1" element={<Nested id="1" />} />
<Route path="2" element={<Nested id="2" />} />
</Route>
</AnimatedRouter>
);
}

render(
<BrowserRouter>
<App />
</BrowserRouter>,
document.querySelector('#root')
);
```

#### `useAnimatedRoutes` Hooks 模式调用

| 属性 | 类型 | 默认值 | 描述 |
| :-----------: | :-------------------: | :---------------: | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| location | `Location` 对象,可选 | 当前页面地址 | 等同于`Routes`的同名属性 |
| prefix | 字符串,可选 | `animated-router` | 应用到 CSSTransition 组件的 classNames 前缀。如果要在同一个项目中使用不同的动画,可以通过设置前缀来定义不同的动画。关于如何自定义动画,请查看下方说明 |
| timeout | 数字,可选 || 动画持续时间(毫秒),可以不传,默认为监听 transitionend 时间来判断动画结束。如果有动画异常,可以尝试设置该值,需要注意的是,该值应该与动画样式中定义的过渡时间一致 |
| className | 字符串,可选 || 如果传入 className 则会添加到动画节点所在容器节点上 |
| transitionKey | 字符串,可选 || 该属性用于标识路由动画节点,默认情况下为变换的路由所对应的`pathname`地址;`AnimatedRouter`已经智能处理了路由嵌套的情形,一般无需特定制定该参数。如果在嵌套路由场景中,要控制子路由变换时,父级路由的动画方式,可以传递该参数 |
| component | 布尔,可选 | 'div' | AnimatedRouter 默认会 render 一个 div 节点,你可以通过该字段修改 render 的节点类型,例如,`component="section"`将会 render `<section>`节点。在 react v16+中,可以传入 `null` 来避免渲染该节点。 |
| appear | 布尔,可选 | false | [文档:appear](http://reactcommunity.org/react-transition-group/transition-group#TransitionGroup-prop-appear):是否启用组件首次挂载动画(启用的话将会触发 enter 进场动画) |
| enter | 布尔,可选 | true | [文档:enter](http://reactcommunity.org/react-transition-group/transition-group#TransitionGroup-prop-enter):是否启用进场动画 |
| exit | 布尔,可选 | true | [文档:exit](http://reactcommunity.org/react-transition-group/transition-group#TransitionGroup-prop-exit):是否启用离场动画 |
> **请注意,名字是`useAnimatedRoutes`,不是`useAnimatedRouter`!!**
你可以将项目中的`useRoutes`使用`useAnimatedRoutes`代替,就可以给页面切换带来动画效果!

```javascript
import React, { Component } from 'react';
import { render } from 'react-dom';
import { BrowserRouter, Routes, Route } from 'react-router-dom';
import AnimatedRouter from 'react-animated-router'; //导入我们的的AnimatedRouter组件
import { useAnimatedRoutes } from 'react-animated-router'; //导入我们的的AnimatedRouter组件
import 'react-animated-router/animate.css'; //导入默认的切换动画样式,如果需要其它切换样式,可以导入自己的动画样式定义文件

import Login from 'modules/Login';
Expand All @@ -66,31 +120,18 @@ import NestLayout from 'modules/NestLayout';
import Nested from 'modules/Nested';

function App() {
render() {
/** 假如你的代码如此,则可直接使用最下方代码代替,即直接使用 AnimatedRouter 替换掉 Routes
* return (
* <Routes>
* <Route path="login"` element={<Login />} />
* <Route path="signup" element={<Signup />} />
* <Route path="nested" element={<NestLayout />}>
* <Route path="1" element={<Nested id="1" />} />
* <Route path="2" element={<Nested id="2" />} />
* </Route>
* </Routes>
* );
**/

return (
<AnimatedRouter>
<Route path="login"` element={<Login />} />
<Route path="signup" element={<Signup />} />
<Route path="nested" element={<NestLayout />}>
<Route path="1" element={<Nested id="1" />} />
<Route path="2" element={<Nested id="2" />} />
</Route>
</AnimatedRouter>
);
}
return useAnimatedRoutes([
{ path: 'login', element: <Login /> },
{ path: 'signup', element: <Signup /> },
{
path: 'nested',
element: <NestLayout />,
children: [
{ path: '1', element: <Nested id="1" /> },
{ path: '2', element: <Nested id="2" /> }
]
}
]);
}

render(
Expand All @@ -101,6 +142,34 @@ render(
);
```

#### 参数说明

```typescript
// TransitionActions 为 react-transition-group 定义
interface AnimatedRouterProps extends TransitionActions {
className?: string;
transitionKey?: string | number;
timeout?: number;
prefix?: string;
component?: React.ElementType | null;
location?: Partial<Location> | string;
}
```

主要参数说明:

| 属性 | 类型 | 默认值 | 描述 |
| :-----------: | :-----------------------: | :---------------: | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| prefix | `string`,可选 | `animated-router` | 应用到 CSSTransition 组件的 classNames 前缀。如果要在同一个项目中使用不同的动画,可以通过设置前缀来定义不同的动画。关于如何自定义动画,请查看下方说明 |
| timeout | `number`,可选 || 动画持续时间(毫秒),可以不传,默认为监听 transitionend 时间来判断动画结束。如果有动画异常,可以尝试设置该值,需要注意的是,该值应该与动画样式中定义的过渡时间一致 |
| className | `string`,可选 || 如果传入 className 则会添加到动画节点所在容器节点上 |
| transitionKey | `string`,可选 || 开始该属性用于标识路由动画节点,默认情况下为变换的路由所对应的`pathname`地址;`AnimatedRouter`已经智能处理了路由嵌套的情形,一般无需特定制定该参数。如果在嵌套路由场景中,要控制子路由变换时,父级路由的动画方式,可以传递该参数 |
| component | `boolean`,可选 | 'div' | AnimatedRouter 默认会 render 一个 div 节点,你可以通过该字段修改 render 的节点类型,例如,`component="section"`将会 render `<section>`节点。在 react v16+中,可以传入 `null` 来避免渲染该节点。 |
| appear | `boolean`,可选 | false | [文档:appear](http://reactcommunity.org/react-transition-group/transition-group#TransitionGroup-prop-appear):是否启用组件首次挂载动画(启用的话将会触发 enter 进场动画) |
| enter | `boolean`,可选 | true | [文档:enter](http://reactcommunity.org/react-transition-group/transition-group#TransitionGroup-prop-enter):是否启用进场动画 |
| exit | `boolean`,可选 | true | [文档:exit](http://reactcommunity.org/react-transition-group/transition-group#TransitionGroup-prop-exit):是否启用离场动画 |
| location | `Location` `string`,可选 | 当前页面地址 | 等同于`Routes`的同名属性,一般无需指定,除非你要渲染匹配与当前页面地址不一样路由 |

### 自定义动画

如果不希望使用左右滑入动画,则可以自定义自己的路由动画。可以将默认的 animate.scss(css) 复制进自己的项目,然后修改不同阶段的样式值即可。
Expand All @@ -123,5 +192,15 @@ render(

### FAQ

- **Q: 动画执行异常?**
- **Q: 动画执行异常?**
A: 可以尝试设置 timeout 属性,并保持与动画样式中定义的过渡时间一致(默认的 animate.scss 中为 300)

- **Q: 控制台有警告?**
A: 如果使用路由嵌套,开发环境下在控制台可能会出现如下警告,这不会对实际路由渲染有任何影响。如果有您有更好地实现可以消除该警告,请`PR`

```bash
router.ts:11 You rendered descendant <Routes> (or called `useRoutes()`) at
"/invoices/" (under <Route path="">) but the parent route path has no trailing "*".
This means if you navigate deeper,the parent won't match anymore and
therefore the child routes will never render.
```
17 changes: 4 additions & 13 deletions dist/AnimatedRouter.d.ts
Original file line number Diff line number Diff line change
@@ -1,16 +1,7 @@
import React, { ReactType } from 'react';
import { Location, RouteObject } from 'react-router';
import { TransitionActions } from 'react-transition-group/Transition';
import React from 'react';
import { AnimatedRouterProps } from './useAnimatedRoutes';
import './animate.scss';
interface AnimatedRouterProps extends TransitionActions {
className?: string;
transitionKey?: string | number;
timeout?: number;
prefix?: string;
component?: ReactType | null;
location?: Location;
children: React.ReactNode | RouteObject[];
}
export * from './useAnimatedRoutes';
/**
* @desc 路由动画组件
* @author qiqiboy
Expand All @@ -20,6 +11,6 @@ interface AnimatedRouterProps extends TransitionActions {
* import 'react-animated-router/animate.css';
*/
declare const AnimatedRouter: React.FC<AnimatedRouterProps & {
_parentPath?: string;
children: React.ReactNode;
}>;
export default AnimatedRouter;
Loading

0 comments on commit 09bfdca

Please sign in to comment.