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

相关推荐
已读不回143几秒前
设计模式-工厂模式
前端·算法·代码规范
郭少几秒前
🔥 我封装了一个会“思考”的指令!Element-Plus Tooltip 自动检测文本溢出,优雅展示
前端·vue.js·性能优化
谢泽豪1 分钟前
解决 uniapp 修改index.html文件不生效的问题
前端·uni-app
袁煦丞1 分钟前
【黑科技指南】自托管私人导航站Dashy:cpolar内网穿透实验室第476个成功挑战
前端·程序员·远程工作
heartmoonq5 分钟前
关于前端监控用户行为导致的报错
前端
已读不回1435 分钟前
告别痛苦的主题切换!用一个插件解决 Tailwind CSS 多主题开发的所有烦恼
前端·架构
pepedd8646 分钟前
🚀Webpack 从入门到优化,一文全掌握!
前端·webpack·trae
TimelessHaze7 分钟前
【面试考点】从URL输入到页面展示
前端·trae
玲小珑8 分钟前
LangChain.js 完全开发手册(一)AI 应用开发入门
前端·langchain·ai编程
excel9 分钟前
前端必修:从表单基础到富文本编辑,一文吃透 HTML 表单编程与交互
前端