react和transition的一次碰撞

1,503 阅读2分钟

最近在做一个活动,里面需要加入各种动效、动画,使页面看上去活泼生动一些,其中有一个就是关于相册集的淡入淡出循环展示,下面就说一下我的实现思路。

我这个项目是用React写的,所以下面的示例代码都是react的,如果大家的项目是用vue写的,思路其实也是类似的。

React代码


import React, {  useState, useEffect } from "react";
import "./styles.css";
const imgData = [
  {
    pic:
      "https://gt-toolbox.oss-cn-beijing.aliyuncs.com/gt-toolbox/4a51ad2f-4292-4bc6-8f25-b24d3f2272ef.jpg"
  },
  {
    pic:
      "https://gt-toolbox.oss-cn-beijing.aliyuncs.com/gt-toolbox/d61b58d2-175a-44fd-9d11-0037346e9ebf.jpg"
  },
  {
    pic:
      "https://gt-toolbox.oss-cn-beijing.aliyuncs.com/gt-toolbox/a05541c1-6606-4cb8-9e25-28330401394d.jpg"
  },
  {
    pic:
      "https://gt-toolbox.oss-cn-beijing.aliyuncs.com/gt-toolbox/d1ea5213-60ac-4a31-983f-bd215183f130.jpg"
  }
];

export default function Page() {
  const [imgIndex, setImgIndex] = useState(0);
  useEffect(() => {
    const timer = setInterval(() => {
      setImgIndex(c => {
        const max = imgData.length - 1;
        if (c < max) {
          return c + 1;
        } else {
          return 0;
        }
      });
    }, 2500);
    return () => clearInterval(timer);
  }, []);
  return (
    <div className="p5Img">
      {imgData.map((item, index) => (
        <img
          key={item.pic}
          src={item.pic}
          alt="活动照2"
          style={index === imgIndex ? { opacity: 1 } : { opacity: 0 }}
          className="imgOpacity"
        />
      ))}
    </div>
  );
}

CSS代码

.p5Img {
  width: 64.87vw;
  height: 77.67vw;
  margin-top: 3%;
  position: relative;
  z-index: 5;
}
.imgOpacity {
  width: 100%;
  height: 100%;
  position: absolute;
  top: 0;
  opacity: 0;
  left: 0;
  transition: all 2.5s;
}

解释一下

  1. 首先遍历imgData生成img节点,其中img都是绝对定位的,所以它们其实都是堆叠在一起的。
  2. 设置一个定时器(上面代码是用的Reacthooks写法),定时器里面负责每隔几秒种改变一下状态imgIndex的值。
  3. 通过opacity属性控制图片"视觉上"的显示隐藏。当遍历的index和状态imgIndex相等时,设置opacity为1,其余的都是0。
  4. 上面三部其实已经可以让图片轮播展示了,可是最关键的动画呢?emmmm…….当然是通过css代码里的transition: all 2.5s;这句来加上的。看到这里大家是不是觉得很简单?对,没错,就是这么简单,哈哈哈

揭秘

不知道各位有没有看出来上面代码的一点小心机,就是我控制图片显示/隐藏的时候,用的是opacity这个属性,为什么我不用display: none这种呢?原因就是如果用display的话,我css里设置的transition就没用了,淡入淡出的动画也就没了。

还有一点就是我为什么一开始要把所有的图片都遍历出来,而不是根据imgIndexreturn一张图片?因为那样的话淡出的动效就不好做了,react会直接把上一个节点销毁掉,不会给我们加入淡出动效的机会。

其实前端里的很多动效,都可以用很简单的方式实现,就看我们自己有没有想到那个点上了。我上面也只是抛砖引玉,给小伙伴们提供一点小小的思路。

更多

详细的代码,我放到sandbox上了,感兴趣的小伙伴们可以去下面的链接上看看。

Edit kind-wood-feqyc