基于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 这个特性,增加切换动效变得简单得多了。

相关推荐
宁雨桥6 分钟前
前端登录加密实战:从原理到落地,守护用户密码安全
前端·安全·状态模式
椒盐螺丝钉19 分钟前
TypeScript类型兼容性
运维·前端·typescript
_JinHao23 分钟前
Cesium Viewer对象详解——Cesium基础笔记(快速入门)
前端·javascript·笔记·3d·webgl
r0ad1 小时前
从痛点到解决方案:为什么我开发了Chrome元素截图插件
前端·chrome
OEC小胖胖1 小时前
连接世界:网络请求 `wx.request`
前端·微信小程序·小程序·微信开放平台
jingling5551 小时前
解决微信小程序真机调试中访问本地接口 localhost:8080 报错
前端·微信小程序·小程序
en-route1 小时前
使用 Flask 构建 Web 应用:静态页面与动态 API 访问
前端·python·flask
IT_陈寒1 小时前
Vite 5年迭代揭秘:3个核心优化让你的项目构建速度提升200%
前端·人工智能·后端
怎么吃不饱捏2 小时前
vue3+vite,引入阿里巴巴svg图标,自定义大小颜色
前端·javascript·vue.js
无敌最俊朗@2 小时前
MQTT 关键特性详解
java·前端·物联网