react | 您所在的位置:网站首页 › 页面跳转过渡效果 › react |
基本介绍
效果演示
简单介绍:本人实现了一个常见问题列表,点击列表项进入详情页,目标是在页面切换的时候加过渡效果,提升用户体验。
没加过渡效果的,进入详情页时很突兀:
官方文档 👉react-transition-group 文档 在 react 项目中可使用官网提供的动画过渡库 react-transition-group 来实现切换页面(路由切换)时的过渡效果。 react-transition-group 中,暴露了三个组件,分别是: Transition CSSTransition TransitionGroup其中最重要的是 CSSTransition,而 TransitionGroup 用于列表项的过渡动画。项目中我也是使用了这两个组件。 TransitionGroup 不提供任何形式的动画,具体的动画取决与我们包裹的 Transition || CSSTransition 的动画,所以我们可以在列表里面做出不同类型的动画。 CSSTransition 组件中较为重要的 api 有: in:boolean,控制组件显示与隐藏,true 显示,false 隐藏。 timeout:number,延迟,涉及到动画状态的持续时间。也可传入一个对象,如{ exit:300, enter:500 } 来分别设置进入和离开的延时。 classNames:string,动画进行时给元素添加的类名。一般利用这个属性来设计动画。这里要特别注意是 classNames 而不是className。 unmountOnExit:boolean,为 true 时组件将移除处于隐藏状态的元素,为 false 时组件保持动画结束时的状态而不移除元素。一般要设成 true。 appear:boolean,为 false 时当 CSSTransition 控件加载完毕后不执行动画,为 true 时控件加载完毕则立即执行动画。如果要组件初次渲染就有动画,则需要设成 true。 key:string,这个属性是配合 TransitionGroup 组件来使用的,可以通过key来判断是否需要触发动画。这个属性十分重要! classNames属性的作用是:当组件被应用动画时,不同的动画状态(enter,exits,done)将作为className属性的后缀来拼接为新的className,如为 CSSTransition组件设置了以下属性: /* 省略... */ 将会生成 fade-enter、fade-enter-active、fade-enter-done、fade-exit、fade-exite-active、fade-exit-done、fade-appear 以及 fade-appear-active多个className。每一个独立的className都对应着单独的状态。 react-router 冷知识关于 react-router 的基本知识可具体查看官方文档 👉react-router文档,这里就不再重复进行介绍。 这里介绍大家平时没注意的关于 Switch 组件的冷知识,也是实现路由切换动画的关键! Switch 有一个很重要的属性:location。一般我们不会给该组件设置 location 属性。有无该属性的区别: 不设置location属性: Switch 组件的子组件(一般是 Route 或 Redirect)会根据当前浏览器的 location 作为匹配依据來进行路由匹配。 设置location属性:Switch 组件的子组件会根据定义的 location 作为匹配依据。看完基本介绍,下面就看看如何在项目中使用 react-transition-group 实现页面切换过渡效果吧。 完整流程 首先,根据之前博客已经介绍的 👉 react + typescript 项目的定制化过程 搭建好项目后,在进行组件开发之前,即可在项目中引入 react-transition-group。同时,由于项目中我还使用了typescript,所以还要安装 @types/react-transition-group。安装命令如下: yarn add react-transition-group yarn add @types/react-transition-group --dev 在入口文件 App.tsx 中使用: import { createHashHistory } from 'history'; import React from 'react'; import { Router } from 'react-router'; import { Route, Switch, withRouter } from 'react-router-dom'; import { TransitionGroup, CSSTransition } from 'react-transition-group'; import routeData from './common/route'; // 路由配置 import NotFound from './views/Exception'; const history = createHashHistory(); const Routes = withRouter(({ location }) => ( {routeData.map(({ path, component, exact }: IRouterItem) => ( ))} )); const App: React.FC = () => { return ( ); }; export default App; withRouter的作用:可以包装任何自定义组件,可以把不是通过路由切换过来的组件中,将react-router 的 history、location 和 match 三个方法传入 props 对象上。默认情况下必须是经过路由匹配渲染的组件才存在 this.props,才拥有路由参数,才能使用编程式导航的写法。然而不是所有组件都直接与路由相连(通过路由跳转到此组件)的,当这些组件需要路由参数时,使用 withRouter 就可以给此组件传入路由参数,此时就可以使用 this.props。 比如 App.js 这个组件,一般是首页,不是通过路由跳转过来的,而是直接从浏览器中输入地址打开的,如果不使用 withRouter,此组件的 this.props 为空,没法执行 props 中的 history、location 和 match 等方法。 为了让入口文件 App.tsx 看起来更加简洁,我将使用了 react-transition-group 的路由切换相关代码封装成Routes组件。 修改后的入口文件 App.tsx 内容如下: import { createHashHistory } from 'history'; import React from 'react'; import { Router } from 'react-router'; import Routes from './components/Routes'; const history = createHashHistory(); const App: React.FC = () => { return ( ); }; export default App; Routes组件内容如下: import React from 'react'; import { Route, Switch, withRouter } from 'react-router-dom'; import { TransitionGroup, CSSTransition } from 'react-transition-group'; import routeData from '../../common/route'; import NotFound from '../../views/Exception'; interface IRouterItem { component?: React.ComponentType; path?: string; exact?: boolean; } class Routes extends React.Component { render () { const { location } = this.props; return ( {routeData.map(({ path, component, exact }: IRouterItem) => ( ))} ); } } export default withRouter(Routes); 决定是否有动画效果的关键步骤来了,就是完成动画的相关样式 !由于动画效果是作用的全局,所以应该写在全局样式里面。 关于模块化的 less 和全局的 less 的相关介绍可具体查看前一篇博客 👉 react + typescript 项目的定制化过程进行了解。 我们要做的就是在src目录下新建一个index.less文件,内容如下: /* 动画相关样式 */ .fade-enter, .fade-appear { opacity: 0; } .fade-enter.fade-enter-active, .fade-appear.fade-appear-active { opacity: 1; transition: opacity 300ms ease-in; } .fade-exit { opacity: 1; } .fade-exit.fade-exit-active { opacity: 0; } 然后在入口文件index.tsx进行引入即可: import './index.less'; 以上则可以实现在切换路由时呈现页面过渡效果,且无bug(首次加载无动画、接口请求两次)。⚠ ️如果只是想实现过渡效果,按照上面介绍的内容即可实现 ⚠ ️如果想了解出现以上两种bug的原因,则可以继续看下面的内容。 踩坑实践 说没踩坑是不可能的,刚开始的代码也不是这样的。下面来解释为何会出现首次加载无动画、接口请求两次这两种bug。 首次加载无动画 之前写过的文章提到过,我在项目中使用了一个叫 react-loadable 的第三方库来进行代码拆分,实现组件按需加载。(相关介绍可具体查看前一篇博客 👉 react + typescript 项目的定制化过程进行了解) 然而,发现当使用 react-loadable 后首次加载时页面切换没有过渡效果,具体看下面的效果:Switch 有一个很重要的属性:location。一般我们不会给该组件设置 location 属性。有无该属性的区别: 不设置location属性: Switch 组件的子组件(一般是 Route 或 Redirect)会根据当前浏览器的 location 作为匹配依据來进行路由匹配。 设置location属性:Switch 组件的子组件会根据定义的 location 作为匹配依据。 关键代码块截图: |
CopyRight 2018-2019 实验室设备网 版权所有 |