You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何仅在桌面端运行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>
  );
}

额外优化点

  1. 修正了原代码中useEffects的拼写错误,改为正确的useEffect
  2. 移动端点击时无任何响应,避免用户误操作困惑
  3. 窗口从桌面端切换到移动端时自动重置展开状态,保证界面一致性

内容的提问来源于stack exchange,提问作者user16052347

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.12 16:46:12