reactjs 帧移动拖动转盘不能正常工作

kmbjn2e3  于 2024-01-07  发布在  React
关注(0)|答案(1)|浏览(122)

我尝试建立一个简单的图像carpet的帮助下,帧运动。
我想使用按钮和拖动来控制幻灯片。它工作得很好,但是当我超过最后一张幻灯片上的滑块时,它会动画回到开始,并完全打乱索引逻辑。
下面是我的代码:

"use client";
import { useState } from "react";
import { AnimatePresence, motion, MotionConfig, PanInfo } from "framer-motion";

let images = [
  "/images/carousel/1.jpeg",
  "/images/carousel/2.jpeg",
  "/images/carousel/3.jpeg",
  "/images/carousel/4.jpeg",
  "/images/carousel/5.jpeg",
];

export default function App() {
  let [index, setIndex] = useState(0);

  const dragEndHandler = (dragInfo: PanInfo) => {
    const draggedDistance = dragInfo.offset.x;
    const swipeThreshold = 50;
    if (draggedDistance > swipeThreshold) {
      console.log("swipe detection: ", "prev");
      index > 0 && setIndex(index - 1);
    } else if (draggedDistance < -swipeThreshold) {
      console.log("swipe detection: ", "next");
      index + 1 < images.length && setIndex(index + 1);
    }
  };

  return (
    <MotionConfig transition={{ duration: 0.7, ease: [0.32, 0.72, 0, 1] }}>
      <div className="relative overflow-hidden">
        <motion.div
          animate={{ x: `-${index * 100}%` }}
          className="flex"
          drag="x"
          dragElastic={1}
          dragConstraints={{ left: 0, right: 0 }}
          onDragEnd={(_, dragInfo: PanInfo) => dragEndHandler(dragInfo)}
        >
          {images.map((image) => (
            <div className="aspect-[4/5] w-full min-w-full">
              <img
                key={image}
                src={image}
                className="object-cover min-w-full pointer-events-none"
              />
            </div>
          ))}
        </motion.div>
        <AnimatePresence initial={false}>
          {index > 0 && (
            <motion.button
              initial={{ opacity: 0 }}
              animate={{ opacity: 0.7 }}
              exit={{ opacity: 0, pointerEvents: "none" }}
              whileHover={{ opacity: 1 }}
              className="absolute left-2 top-1/2 -mt-4 flex h-8 w-8 items-center justify-center rounded-full bg-white"
              onClick={() => setIndex(index - 1)}
            >
              <div className="h-6 w-6">Prev</div>
            </motion.button>
          )}
        </AnimatePresence>

        <AnimatePresence initial={false}>
          {index + 1 < images.length && (
            <motion.button
              initial={{ opacity: 0 }}
              animate={{ opacity: 0.7 }}
              exit={{ opacity: 0, pointerEvents: "none" }}
              whileHover={{ opacity: 1 }}
              className="absolute right-2 top-1/2 -mt-4 flex h-8 w-8 items-center justify-center rounded-full bg-white"
              onClick={() => setIndex(index + 1)}
            >
              <div className="h-6 w-6">Next</div>
            </motion.button>
          )}
        </AnimatePresence>
      </div>
    </MotionConfig>
  );
}

字符串
我尝试使用dragSnapToOrigin={false},但这不与弹性等工作.我认为问题发生从弹性的使用和我如何确定拖动方向.但我不能解决这个问题在这里.任何帮助将不胜感激:)

fruv7luv

fruv7luv1#

这个问题来自于你的motion.div的宽度,它是dragConstraints。我给你的motion.div添加了一些边框,注意到它只有一张幻灯片宽。这导致dragConstraints不能像你期望的那样工作。当你到达旋转木马的末尾并向右拖动时,约束启动并将转换样式重置为“无”,所以我们看到carousel缩放回第一张幻灯片,即使索引没有改变。在我使用framer motion的经验中,我最成功地让dragContraints按照我认为他们应该的方式行事,通过使用ref而不是设置topleft等。
这些是需要更新以获得所需结果的内容:
1.更改dragConstraints以使用附加到父容器的引用。
1.确保幻灯片容器的宽度等于所有幻灯片宽度的总和。如果我们希望每张幻灯片都是幻灯片容器宽度的100%,则幻灯片容器的宽度需要为(images.length * 100)%
1.将容器的x偏移量更新为一个图像的宽度(100 / images.length)%乘以索引。
1.从幻灯片中删除min-w-full类。
下面是我创建的this working example的相关代码片段。

const constraintsRef = useRef(null);
    
    ...

    {/* ↓ Parent Container */}
    <div
      // Added ref to Parent Container so we can use
      // it's bounding box as dragConstraints
      // https://www.framer.com/motion/gestures/###dragconstraints
      ref={constraintsRef}
      className="relative overflow-hidden"
    >
      {/* ↓ Draggable Container */}
      <motion.div
        style={{
          // Set the width to be 100% of the Parent Container
          // times the number of slides in the carousel. This
          // helps make sure the dragConstraints work as expected.
          width: `${images.length * 100}%`,
        }}
        animate={{
          // Update the x offset to be one slides width. Since
          // the width of the Draggable Container is
          // images.length * 100, each slide's width is
          // 100 / images.length.
          x: `-${index * (100 / images.length)}%`,
        }}
        drag="x"
        dragElastic={1}
        dragConstraints={
          // Set the drag constraints to the Parent Container's
          // bounding box using a ref.
          // https://www.framer.com/motion/gestures/###dragconstraints
          constraintsRef
        }
        onDragEnd={(_, dragInfo: PanInfo) => dragEndHandler(dragInfo)}
        className="flex"
      >
        {/* ↓ Slides map */}
        {images.map((image, imageIndex) => (
          <div
            key={image + imageIndex}
            // Removed min-w-full. It was causing the slide
            // to be too large. 
            className="aspect-[4/5] w-full"
          >
            <img
              src={image}
              className="object-cover min-w-full pointer-events-none"
            />
          </div>
        ))}
      </motion.div>
      ...
    </div>

字符串

相关问题