基于Solito+Next.js,React Native Web布局过渡实现方案(无Reanimated)
实现Solito+Next.js三端共享中Reanimated布局动画的Web端兼容方案
问题背景
我用Solito+Next.js做三端代码共享,目前Reanimated的Layout Animations API不支持Web(对应Git issue #2993),CSS transition无法实现布局过渡效果,手动逐处适配成本太高。Native端用Reanimated Layout Animations运行正常,但Web端完全没动画效果,现有代码片段如下:
import Animated, { Layout, Easing} from 'react-native-reanimated' ... <AnimatedSolitoImage className="transition-all duration-1000" src={logo} alt="Logo" height={60} width={130} layout={Layout.easing(Easing.ease) .duration(duration * 0.8) .delay(duration * 0.2)} />
可行实现思路
1. 跨平台组件封装(最直接落地方案)
封装统一的布局动画组件,根据平台自动切换底层实现:
- Native端:继续使用Reanimated的
Animated组件+layout属性 - Web端:替换为Framer Motion的
motion组件+layout属性,同时将Reanimated的动画配置(easing、duration、delay)映射为Framer Motion的对应参数
示例代码:
import { Platform } from 'react-native'; import Animated, { Layout, Easing } from 'react-native-reanimated'; import { motion } from 'framer-motion'; import SolitoImage from 'solito/image'; const AnimatedLayoutImage = (props) => { const { layout, className, ...restProps } = props; if (Platform.OS === 'web') { // 将Reanimated的Layout配置转换为Framer Motion的过渡参数 const framerTransition = { type: 'tween', ease: layout?._easing || 'easeInOut', duration: layout?._duration || 300, delay: layout?._delay || 0, }; return ( <motion(SolitoImage) className={className} layout layoutTransition={framerTransition} {...restProps} /> ); } return ( <Animated(SolitoImage) className={className} layout={layout} {...restProps} /> ); }; // 使用时直接替换原组件 <AnimatedLayoutImage className="transition-all duration-1000" src={logo} alt="Logo" height={60} width={130} layout={Layout.easing(Easing.ease) .duration(duration * 0.8) .delay(duration * 0.2)} />
2. Babel插件自动转换(无侵入式适配)
开发自定义Babel插件,在编译阶段自动将Reanimated的layout相关代码转换为Web端的Framer Motion代码:
- 识别代码中
Animated.Xxx组件的layout属性,替换为motion(Xxx)的layout配置 - 解析
Layout.easing(...).duration(...)链式调用,转换为Framer Motion的layoutTransition对象 - 优点:业务代码完全无需修改,编译后自动适配Web端
3. CSS变量+Intersection Observer模拟布局过渡(轻量替代方案)
如果不想引入Framer Motion,可以用原生API模拟简单的布局动画:
- 给目标元素添加ref,用Intersection Observer监听元素位置变化
- 计算元素前后位置的偏移量,通过CSS变量动态设置
transform: translate() - 配合CSS
transition实现平滑过渡,适合简单布局变化场景
示例代码思路:
import { useEffect, useRef, useState } from 'react'; import SolitoImage from 'solito/image'; const LayoutAnimatedImage = (props) => { const ref = useRef(null); const [prevPos, setPrevPos] = useState({ x: 0, y: 0 }); useEffect(() => { const updatePosition = () => { if (!ref.current) return; const { left, top } = ref.current.getBoundingClientRect(); setPrevPos(prev => ({ x: left - prev.x, y: top - prev.y })); }; updatePosition(); window.addEventListener('resize', updatePosition); return () => window.removeEventListener('resize', updatePosition); }, []); return ( <SolitoImage ref={ref} className="transition-transform duration-800 delay-200" style={{ transform: `translate(${prevPos.x}px, ${prevPos.y}px)` }} {...props} /> ); };
4. React Native Web动画适配层(底层透明适配)
扩展React Native Web的Animated组件,为layout属性添加polyfill:
- 在Web端重写
Animated组件的渲染逻辑,内部使用Framer Motion处理布局动画 - 上层业务代码完全复用Reanimated的API,无需修改
- 优点:对业务层完全透明,适配成本极低,但需要深入React Native Web源码逻辑
内容的提问来源于stack exchange,提问作者COC Hindi by sourabh soni
相关产品推荐
相关产品推荐

