如何仅在桌面端运行React+Framer Motion图片展开动画?
仅桌面端触发Framer Motion图片展开动画的实现方案
核心思路
通过判断当前设备是否为桌面端,控制动画的触发逻辑——仅在桌面端允许点击切换展开/收缩状态,同时让动画仅在桌面端生效。以下是两种高效的实现方式:
方法一:使用Framer Motion内置的useMediaQuery钩子(推荐)
Framer Motion提供的useMediaQuery钩子可以直接匹配CSS媒体查询,无需手动监听窗口尺寸变化,代码更简洁可靠。
修改后的完整代码
import "./projectStyle.css"; import { useState } from "react"; import { motion, useMediaQuery } from "framer-motion"; const variants = { open: { width: "40rem" }, closed: {} }; export default function Project(props) { const [isOpen, setIsOpen] = useState(false); // 匹配桌面端阈值(这里以768px为例,可根据需求调整) const isDesktop = useMediaQuery("(min-width: 768px)"); const handleClick = () => { // 仅在桌面端允许切换状态 if (isDesktop) { setIsOpen(prev => !prev); } }; return ( <motion.div // 仅在桌面端且状态切换时应用动画变体,移动端直接使用默认样式 animate={isDesktop ? (isOpen ? "open" : "closed") : {}} variants={variants} className="projectWrapper mobile" onClick={handleClick} > <div className="overlayContainer"> <img src={props.siteImage} alt={props.altText} /> <div className="overlay"></div> </div> </motion.div> ); }
方法二:手动监听窗口尺寸变化
如果不想依赖Framer Motion的内置钩子,可以用React的useEffect手动监听窗口resize事件,维护桌面端状态:
修改后的完整代码
import "./projectStyle.css"; import { useState, useEffect } from "react"; import { motion } from "framer-motion"; const variants = { open: { width: "40rem" }, closed: {} }; // 定义桌面端宽度阈值 const DESKTOP_THRESHOLD = 768; export default function Project(props) { const [isOpen, setIsOpen] = useState(false); const [isDesktop, setIsDesktop] = useState(window.innerWidth >= DESKTOP_THRESHOLD); // 监听窗口尺寸变化 useEffect(() => { const handleResize = () => { setIsDesktop(window.innerWidth >= DESKTOP_THRESHOLD); // 窗口从桌面端切换到移动端时,重置展开状态 if (window.innerWidth < DESKTOP_THRESHOLD) { setIsOpen(false); } }; window.addEventListener("resize", handleResize); // 组件卸载时移除监听 return () => window.removeEventListener("resize", handleResize); }, []); const handleClick = () => { if (isDesktop) { setIsOpen(prev => !prev); } }; return ( <motion.div animate={isDesktop ? (isOpen ? "open" : "closed") : {}} variants={variants} className="projectWrapper mobile" onClick={handleClick} > <div className="overlayContainer"> <img src={props.siteImage} alt={props.altText} /> <div className="overlay"></div> </div> </motion.div> ); }
额外优化点
- 修正了原代码中
useEffects的拼写错误,改为正确的useEffect - 移动端点击时无任何响应,避免用户误操作困惑
- 窗口从桌面端切换到移动端时自动重置展开状态,保证界面一致性
内容的提问来源于stack exchange,提问作者user16052347
相关产品推荐
相关产品推荐

