1

对于客户,我们正在构建水平拖动的媒体项行。使用 Framer-Motion 水平拖动效果很好,但我无法在单击按钮时为 x 位置设置动画。

这是一般的想法:

在此处输入图像描述

这是我目前拥有的组件(为简洁起见,我删除了样式等):

const HorizontalScroll = ({ children }) => {
  const x = useMotionValue(0);

  function onLeftClick() {
    const xPos = x.get();

    if (Math.round(xPos) === 0) {
      return;
    }

    const newXPosition = xPos + 600;

    x.set(newXPosition > 0 ? 0 : newXPosition);
  }

  function onRightClick() {
    const xPos = x.get();

    const newXPosition = xPos - 600;

    x.set(newXPosition < -2000 ? -2000 : newXPosition);
  }

  return (
    <>
      <button
        type="button"
        onClick={onLeftClick}
      >
        Left
      </button>

      <motion.div
        drag="x"
        dragConstraints={{ left: -2000, right: 0 }}
        initial={false}
        style={{ width: 2000, x }}
      >
        {children}
      </motion.div>

      <button
        type="button"
        onClick={onRightClick}
      >
        Right
      </button>
    </>
  );
};

所以当我x.set()在箭头上单击左或右时我会这样做。做x.set()作品,但它不是动画。

而不是const x = useMotionValue(0)我可以使用useSpringor useTransform,但这会破坏拖动行为。

所以简而言之,我想为 制作动画x.set(),但我不知道该怎么做。有人有想法吗?

4

2 回答 2

1

我终于发布了我的问题,并在不到一个小时的时间内找到了我自己问题的答案......

如果有人有相同的边缘案例问题。我想出的(这绝不是最优雅的解决方案)是使用useAnimation. 我的组件目前看起来像这样:

const translateXForElement = (element) => {
  const transform = element.style.transform;

  if (!transform || transform.indexOf('translateX(') < 0) {
    return 0;
  }

  const extractTranslateX = transform.match(/translateX\((-?\d+)/);

  return extractTranslateX && extractTranslateX.length === 2
    ? parseInt(extractTranslateX[1], 10)
    : 0;
}

const HorizontalScroll = ({ children }) => {
  const dragRef = useRef(null);
  const animation = useAnimation();

  function onLeftClick() {
    const xPos = translateXForElement(dragRef.current);
    const newXPosition = xPos + 600;

    animation.start({
      x: newXPosition > 0 ? 0 : newXPosition,
    });
  }

  function onRightClick() {
    const xPos = translateXForElement(dragRef.current);
    const newXPosition = xPos - 600;

    animation.start({
      x: newXPosition < -2000 ? -2000 : newXPosition,
    });
  }

  return (
    <>
      <button
        type="button"
        onClick={onLeftClick}
      >
        Left
      </button>

      <motion.div
        drag="x"
        dragConstraints={{ left: -2000, right: 0 }}
        initial={false}
        animate={animation}
        style={{ width: 2000, x: 0, opacity: 1 }}
        ref={dragRef}
      >
        {children}
      </motion.div>

      <button
        type="button"
        onClick={onRightClick}
      >
        Right
      </button>
    </>
  );
};

我找不到(好的)解决方案来检索translateX元素的当前值,所以我现在做了一个正则表达式element.style.transform。太糟糕useAnimation()了,不允许检索x(或者我错过了一些东西)。

当然,如果您对我的代码有什么要批准的,我很乐意听到!

于 2020-07-30T12:54:02.540 回答
0

我发现你可以在一个变量中跟踪这个

const HorizontalScroll = ({ children }) => {
  const dragRef = useRef(null);
    const xPos = useRef(0);
  const animation = useAnimation();

  function onLeftClick() {
    const newXPosition = xPos.current + 600;

    animation.start({
      x: newXPosition > 0 ? 0 : newXPosition,
    });
  }

  function onRightClick() {
    const newXPosition = xPos.current - 600;

    animation.start({
      x: newXPosition < -2000 ? -2000 : newXPosition,
    });
  }

    function onUpdate(latest){
        xPos.current = latest.x;
    }

  return (
    <>
      <button
        type="button"
        onClick={onLeftClick}
      >
        Left
      </button>

      <motion.div
        drag="x"
        dragConstraints={{ left: -2000, right: 0 }}
        initial={false}
                onUpdate={onUpdate}
        animate={animation}
        style={{ width: 2000, x: 0, opacity: 1 }}
        ref={dragRef}
      >
        {children}
      </motion.div>

      <button
        type="button"
        onClick={onRightClick}
      >
        Right
      </button>
    </>
  );
};
于 2021-11-23T12:24:31.403 回答