基于react-router-dom, view transition 实现路由切换过渡动效

基于react-router-dom, view transition 实现路由切换过渡动效

可以先看看效果以及代码

view-transition-demo.yangbingrui.info/

背景

在我之前的文章提到,用了 framer-motion 这个包来实现了路由切换时的过渡动效。

关于用 framer-motion来实现路由切换动效的文章

其中一个 hack 写法用于实现前路由离开时的动效,大概是这样的

jsx 复制代码
export const AnimatedOutlet = ({ OutletContext } = {}) => {
    const location = useLocation();
    const element = useOutlet(OutletContext);
    return (
        <AnimatePresence
            mode="wait"
            initial={true}
        >
            {element && React.cloneElement(element, { key: location.pathname })}
        </AnimatePresence>
    );
};

但是这个写法会导致一些副作用,例如,会导致我封装好的 table 组件里面的 hook 执行两次,猜测是在framer-motion库对路由切换时,会克隆一个前路由组件,再对其添加离开动效所导致的。

好的点是:

  • 动效流畅;
  • 兼容性好;

不好的点是:

  • 代码稍显复杂,其他同事难以维护;
  • 当存在a-b-c三级嵌套路由时,想往某个层级里添加过渡动效,都要往该层级嵌套AnimatePresence, motion.div,稍显麻烦。

虽说可以通过一些方式来避免这个副作用,但还是有点麻烦,于是在寻找替代方案。

解决方案

最近发现一个浏览器的特性 view-transition,可以轻松地给组件增加动效,而且基本只需要写 css 就行(并且也要给 react-router-dom 的Link配置viewTransition属性为 true)。于是我用这个特性来替换掉 frame-motion。

一些实现的细节

源码里面有些值得关注的细节:

  1. 注意这个 css 代码,其中的关键就是这几行,::view-transition-old 代表的是切换时,浏览器当前帧的节点离开时的动效声明,::view-transition-new 代表的是浏览器下一帧新的节点进入时的动效声明,b-page-transition是对应节点的 view-transition-name
css 复制代码
::view-transition-old(b-page-transition) {
  animation: var(--b-page-transition-duration) ease-in-out both
    b-page-transition-fade-out;
}

::view-transition-new(b-page-transition) {
  animation: var(--b-page-transition-duration) var(--b-page-transition-duration)
    ease-in-out both b-page-transition-fade-in;
}
  1. 注意这个写法
css 复制代码
.b-page:has(.c-page) {
  view-transition-name: none;
  animation: none;
}

之所以这样写,是因为切换 3 级路由时,不希望再触发 2 级路由的切换动效了,如果不这样写的话,那么切换时,2 、3 级的过渡动效都会被触发。

还有一个点,这里之所以不把 c-page 放到 3 级页面那一层级,之所以这样写,是为了避免首次从 2 级跳到 3 级路由时页面轻微的跳动。跳动的原因,我猜测是切换时 同时触发 2,3 级路由的动效,但又命中上面那条 css 规则所导致的吧。

jsx 复制代码
const BPage = () => {
    //...
      <div className="c-page">
        <Outlet />
      </div>
    //...
};

总结

于是我用了 view-transition 来代替了 framer-motion 来实现路由切换时的动效,效果还可以,还加上了之前不好 实现的 2 级路由切换动效,因为实际通过 framer-motion 来实现动效,要额外增加嵌套的层级深度。而使用了 view transition 这个特性,增加切换动效变得简单得多了。

相关推荐
w***Q3501 小时前
Vue打包
前端·javascript·vue.js
有事没事实验室1 小时前
router-link的custom模式
前端·javascript·vue.js
常乐我净6161 小时前
十、路由和导航
前端
Tonychen1 小时前
TypeScript 里 infer 常见用法
前端·typescript
米诺zuo1 小时前
MUI sx prop 中的响应式适配
前端
周尛先森1 小时前
都React 19了,他到底带来了什么?
前端
洞窝技术2 小时前
一键屏蔽某国IP访问实战
前端·nginx·node.js
fruge2 小时前
前端自动化脚本:用 Node.js 写批量处理工具(图片压缩、文件重命名)
前端·node.js·自动化
Jolyne_2 小时前
antd Image base64缓存 + loading 态优化方案
前端
BINGCHN2 小时前
NSSCTF每日一练 SWPUCTF2021 include--web
android·前端·android studio