首页 > 解决方案 > 在 React 中让元素随着延迟顺序变化

问题描述

我试图让一排点以很小的延迟(在每个点变化之间)按顺序变化,但遇到了麻烦。这是我到目前为止所拥有的:

const Dots = () => {
  const [currentDot, setCurrentSegment] = useState(1);

  return (
    <Wrapper>
      <StyledLargeDot
        onClick={() => setCurrentSegment(1)}
        isActive={currentDot >= 1}
      />
      <StyledLargeDot
        onClick={() => setCurrentSegment(2)}
        isActive={currentDot >= 2}
      />
      <StyledLargeDot
        onClick={() => setCurrentSegment(3)}
        isActive={currentDot >= 3}
      />
      <StyledLargeDot
        onClick={() => setCurrentSegment(4)}
        isActive={currentDot >= 4}
      />
      <StyledLargeDot
        onClick={() => setCurrentSegment(5)}
        isActive={currentDot >= 5}
      />
      <StyledLargeDot
        onClick={() => setCurrentSegment(6)}
        isActive={currentDot >= 6}
      />
    </Wrapper>
  );
};

export default Dots;

const Wrapper = styled.div`
  background: green;
  display: flex;
  height: 100vh;
  align-items: center;
  justify-content: space-evenly;
  width: 100vw;
`;

const StyledLargeDot = styled.div`
  background: #ffffff;
  border: 2px solid #fff;
  border-radius: 50%;
  cursor: pointer;
  position: relative;
  height: 5px;
  opacity: ${(props) => (props.isActive ? "1" : "0.3")};
  transform: ${(props) => (props.isActive ? "scale(2)" : "")};
  transition: all 0.5s 1s linear;
  width: 5px;

  &:hover {
    transform: ${(props) => (props.isActive ? "" : "scale(2)")};
    opacity: ${(props) => (props.isActive ? "" : "1")};
  }
`;


一个“工作”的例子在这里:https ://codesandbox.io/s/optimistic-smoke-qlv2i?file=/src/components/Dots.js

我想要发生的是:

第一个点(从左到右)始终处于活动状态。在职的

当单击另一个点时,它之间的点会按顺序激活,并会稍有延迟,直到单击的点最后亮起。不工作 - 单击的点首先激活,中间的点不按顺序激活。

如果它点击了前一个点,那么它之后的点会依次停用(从右到左),直到它们到达它但它仍然保持活动状态。不工作 - 单击的那个仍然处于活动状态,但介于两者之间的那些似乎没有按顺序一起停用。

理想情况下,任何未激活的点都会在悬停时缩放到激活的大小而不激活。不工作,但我知道为什么,并且可能会在修复其他所有内容后弄清楚。

正如你所看到的,我所做的有些工作,但不是真的。我想我可以弄清楚悬停,但真正的问题是我被难住的顺序和时间:/

我什至不确定这是否是最好的方法,真的很感激一些帮助吗?

先感谢您

标签: javascriptreactjs

解决方案


https://codesandbox.io/s/gifted-ramanujan-h41iu多田!

首先我用一个对象创建了一个数组来保存每个点的属性

const initialDots = [
  { isActive: true, delay: 0},
  { isActive: false, delay: 0},
  { isActive: false, delay: 0 },
  { isActive: false, delay: 0 },
  { isActive: false, delay: 0},
  { isActive: false, delay: 0 }
];

我将每个元素映射到一个<StyledLargeDot {...dot} onClick={() => handleChange(index)} />.句柄更改函数将改变数组以获得正确的效果。

  return (
    <Wrapper>
      {dots.map((dot, index) => {
        return (
          <StyledLargeDot {...dot} onClick={() => handleChange(index)}/>
        );
      })}
    </Wrapper>
  );

后来我将其更改为下面添加悬停功能的内容,因为过渡延迟<StyledLargeDot/>使得很难在没有延迟的情况下添加任何悬停效果。

  return (
    <Wrapper>
      {dots.map((dot, index) => {
        return (
          <div
            onClick={() => handleChange(index)}
            style={{ position: "relative" }}
          >
            <StyledLargeDot {...dot} />
            <HoverEffect {...dot} />
          </div>
        );
      })}
    </Wrapper>
  );

我必须对您的组件进行以下更改才能获取新delay属性。

const StyledLargeDot = styled.div`
  background: #ffffff;
  border: 2px solid #fff;
  border-radius: 50%;
  cursor: pointer;
  position: relative;
  height: 5px;
  opacity: ${(props) => (props.isActive ? "1" : "0.3")};
  transform: ${(props) => (props.isActive ? "scale(2)" : "")};
  transition: all 0.5s ${(props) => props.delay}s linear;
  width: 5px;
`;

重要的部分是handleChange()使效果成为可能的功能。它通过计算每个点的适当转换延迟并正确更新isActive属性来在单击一个点后工作。该delayFix变量不是必需的,但您可以将其设置为 0 以查看差异。

  const [dots, setDots] = useState(initialDots);
  const handleChange = (currentIndex) => {
    let delayFix = currentIndex > currentDot ? -1 : 0;
    setDots(
      dots.map((dot, index) => {
        return {
          isActive: index <= currentIndex,
          delay: Math.abs(index - currentDot) + delayFix
        };
      })
    );
    setCurrentSegment(currentIndex);
  };

为了得到<HoverEffect/>工作,我在下面创建了这个组件。

const HoverEffect = styled.div`
  background: #ffffff;
  border: 2px solid #fff;
  border-radius: 50%;
  cursor: pointer;
  position: absolute;
  height: 5px;
  width: 5px;
  top: 0;
  left: 0;
  z-index: 100;
  opacity: 0.3;
  transition: all 0.5s linear;
  :hover {
    opacity: ${(props) => (props.isActive ? "0.3" : "1")};
    transform: ${(props) => (props.isActive ? "" : "scale(2)")};
  }
`;

推荐阅读