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

React中使用Framer Motion实现拖拽元素刷新后保持位置

问题

构建支持页面元素拖拽的React应用时,页面刷新后元素会回到初始位置。尝试通过onDragStart和onDragEnd获取拖拽的初始与最终位置并设置为元素初始位置,但无法准确获取位置,也无法保持拖拽后的位置。

相关组件代码:

<motion.div
  drag
  dragMomentum={false}
  dragConstraints={{
    right: 1200,
  }}
  initial={{ x: -1, y: 367 }}
  ref={myRef}
  onDragStart={(event, info) => {
    initailPosition(event, info);
  }}
  onDragEnd={(event, info) => {
    finalPosition(event, info);
  }}
  className={Style.imgCntainer}
>
  <img
    onPointerDown={(e) => {
      dragControls.start(e);
    }}
    className={Style.file}
    src={data[0]?.fileLink}
    alt="img"
  />
</motion.div>

处理函数代码:

const finalPosition = (event, info) => {
  console.log("end", info.offset.y, info.offset.x);
}

const initailPosition = (event, info) => {
  console.log("start", info.offset.y, info.offset.x);
}
解决方案

核心思路

要解决刷新后位置重置的问题,需要持久化存储拖拽后的位置,并在组件初始化时读取该位置;同时修正位置计算逻辑,确保能准确获取拖拽后的最终坐标。

具体实现步骤

  • 用状态管理拖拽位置:不再依赖仅首次渲染生效的initial属性,改用useState存储当前位置,初始化时优先从localStorage读取已保存的位置。
  • 拖拽结束时保存位置:在onDragEnd中计算最终位置,更新状态并将位置存入localStorage,实现持久化。
  • 修正位置计算逻辑:info.offset是拖拽过程中的相对偏移量,需要结合当前状态的位置计算最终绝对坐标,而非直接使用偏移量作为最终位置。

修改后的完整代码

import { motion } from "framer-motion";
import { useState } from "react";

function DraggableImage({ data }) {
  // 初始化时从localStorage读取位置,无存储则用默认值
  const [dragPosition, setDragPosition] = useState(() => {
    const savedPos = localStorage.getItem("draggableImagePosition");
    return savedPos ? JSON.parse(savedPos) : { x: -1, y: 367 };
  });

  const handleDragEnd = (_, info) => {
    // 计算拖拽后的最终位置:当前位置 + 拖拽偏移量
    const newPosition = {
      x: dragPosition.x + info.offset.x,
      y: dragPosition.y + info.offset.y
    };
    setDragPosition(newPosition);
    // 保存到localStorage
    localStorage.setItem("draggableImagePosition", JSON.stringify(newPosition));
  };

  return (
    <motion.div
      drag
      dragMomentum={false}
      dragConstraints={{ right: 1200 }}
      // 用animate绑定状态,实时更新位置
      animate={{ x: dragPosition.x, y: dragPosition.y }}
      className={Style.imgCntainer}
      onDragEnd={handleDragEnd}
    >
      <img
        className={Style.file}
        src={data[0]?.fileLink}
        alt="img"
      />
    </motion.div>
  );
}

关键说明

  • 持久化存储:使用localStorage保存位置,确保页面刷新后数据不丢失;若需要跨页同步,可改用sessionStorage或后端存储。
  • 位置计算:info.offset.x/info.offset.y是拖拽开始到结束的相对移动距离,必须和当前位置相加才能得到最终的绝对坐标。
  • 移除冗余代码:无需手动调用dragControls.start,motion的drag属性已自带完整拖拽功能。
  • 状态驱动渲染:通过animate绑定dragPosition状态,确保拖拽后位置实时更新,而非仅依赖首次渲染的initial属性。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.16 17:55:20