umijs / umi

A framework in react community ✨
https://umijs.org
MIT License
15.3k stars 2.65k forks source link

配置路由下如何实现路由动画 #4827

Closed wansuiasdn closed 4 years ago

wansuiasdn commented 4 years ago

无论是ant-motion还是react-transition-group都是需要在页面内重写路由的,配置路由的情况下如何实现,求赐教啊。

CJY0208 commented 4 years ago

@zhengmenghuang 同学的这篇博文的方案似乎可行 https://blog.csdn.net/qq_20059455/article/details/100189819

demo github 在此处 https://github.com/zhengmenghuang/umi-route-animation

anakornk commented 4 years ago

遇到同样的问题,花了点时间去读源码。上面那篇文章是针对于 v2,在v3会有点问题。

layout 组件的 children props 是 Switch 组件。v2 中直接使用 react-router的 switch 组件,该组件使用的location 是通过props 传进来。v3 中的switch 是对 react-router 进行了包装, location 是从router context 获取的。

v2

<Layout>
  <Switch location={}>
    <Route ...>
    <Route ...>
    <Route ...>
  </Switch>
</Layout>

v3

<Layout>
  <Switch> // custom switch
    <Route ...>
    <Route ...>
    <Route ...>
  </Switch>
</Layout>

我暂时的解决方法是读取 switch 的 props, 用react-router 重新建 switch 组件,并把 location 传进去。

  // layout/index.tsx

  const newSwitch = (
    <Switch location={location}>{children.props.children}</Switch>
  );

  // Example using React-Transition-Group

  return (
    <TransitionGroup
      childFactory={(child: any) =>
        React.cloneElement(child, {
          classNames: 'forward',
        })
      }
    >
      <CSSTransition key={location.pathname} timeout={2000}>
        {newSwitch}
      </CSSTransition>
    </TransitionGroup>
  );

完整 demo (通过React Transition Group 和 React-Spring): https://github.com/TongHuaLabs/umi-page-animation

参考文献:

anakornk commented 4 years ago

比较了一下Umi Switch 和 react-router Switch, 两个主要区别是 Umi Switch 允许通过 cloneElement 的方式传递参数给子路由 ( 参考: https://umijs.org/docs/routing#传递参数给子路由 ), 以及location 只能通过 Router Context 获取。

@sorrycc , 能否允许和react-router Switch一样通过传递 location props 来配置 Switch?

// https://github.com/umijs/umi/blob/master/packages/renderer-react/src/renderRoutes/Switch.tsx
// line 9
const location = props.location || context.location;

这样就可以通过 cloneElement 传递 location 实现路由动画,以及传递其他参数给子路由

  const newChildren = React.cloneElement(children, {
    location,
    something: 'helloworld',
  });

参考文献:

wansuiasdn commented 4 years ago

@anakornk 感谢大佬,按您的demo写了一下,但是我这有一个问题,就是A页面和B页面公用了一套封装好的layout,当A跳转到B时,动画效果‘fade’并不是A渐隐B出现,而是B页面渐隐B页面出现,也就是说组件在路由跳转的时候就已经被更新了A页面直接变成了B页面,然后才播放路由动画,您有遇到过这种问题么

anakornk commented 4 years ago

@anakornk 感谢大佬,按您的demo写了一下,但是我这有一个问题,就是A页面和B页面公用了一套封装好的layout,当A跳转到B时,动画效果‘fade’并不是A渐隐B出现,而是B页面渐隐B页面出现,也就是说组件在路由跳转的时候就已经被更新了A页面直接变成了B页面,然后才播放路由动画,您有遇到过这种问题么

layout 里面import的switch是从react-router 引来的吗?还有记得把location props 传进去。

import { Switch } from 'react-router';
wansuiasdn commented 4 years ago

@anakornk 贴下我的代码

import { TransitionGroup, CSSTransition } from 'react-transition-group'; import { withRouter } from 'umi'; import React from 'react' import { Switch } from 'react-router' export default withRouter(({ location, children, history }) => {

const newSwitch = (
    <Switch location={location}>{children.props.children}</Switch>
);

return (
    <TransitionGroup childFactory={child => React.cloneElement(child, { classNames: 'forward' })}>
        <CSSTransition key={location.pathname} timeout={2000}>
            {newSwitch}
        </CSSTransition>
    </TransitionGroup>

);

});

xclw2000 commented 3 years ago

我遇到了和 @wansuiasdn ``同样的问题,不过,我是因为嵌套了两层Layout,才出现的问题。

export default [
  {
    path: '/',
    component: '@/layouts/TransitionLayout',
    routes: [
      {
        path: '/',
        component: '@/layouts/SecurityLayout',
        routes: [
          { path: '/', component: '@/pages/home', exact: true },
          { path: '/hello', component: '@/pages/hello', exact: true },
          { path: '/world', component: '@/pages/world', exact: true },
        ],
      },
    ],
  },
];

第一层Layout就是@anakornk的源码中的layouts/index, 第二层layout是自己的业务逻辑代码

wansuiasdn commented 3 years ago

@xclw2000 大佬这个问题解决了么?