react多张图片切换组件,仿优酷图片切换(附图)

前言:之前写过图片切换组件,例如通过改变state,读取图片数组下标来实现切换,感觉效果不是很好,太过生硬,并且因为每次切换时候读取到的下标时候会去重新请求图片的url,重复浪费资源。

 重新整理功能:

1、点击右侧icon时候切换下面4张图片,并附带有平移动画效果

2、点击左侧icon切换前张图片,并附带有平移动画效果

思路整理:

1、使用css的transform,可以将元素旋转,缩放,移动,倾斜

2、使用object-fit:cover需要设置图片填充效果,(每张图片大小不一致)

3、保证每张图片在同一行

4、切换时候设置transform的translateX偏移宽度

按照上面的思路我们贴下代码和初步的实现:

初步less文件----------------

.wrap_scrollImg {
  width: 100%;
  height: 300px;
  background-color: #2C9806;
  overflow: hidden;
  position: relative;

  span {
    z-index: 11;
    position: absolute;
    display: inline-block;
    height: 50px;
    width: 50px;
    background-color: red;
    top: 0;
    bottom: 0;
    margin: auto;
  }

  .left_icon {
    left: 0;
  }

  .right_icon {
    right: 0;
  }

  ul {
    z-index: 10;
    height: 300px;
    white-space: nowrap;
    position: absolute;

    li {
      height: 100%;
      display: inline-block;
      width: 24%;
      margin-left: 1%;

      img {
        width: 100%;
        height: 100%;
        object-fit: cover;
      }
    }
  }
}

初步jsx文件---------------

import React, { Component, useState, memo } from 'react';
import styles from './index.less';

function Index(props) {

  const { imgData } = props;
  const [translateX, setTranslateX] = useState(0); //设置偏移数值

  const clickRightIcon = () => {
    setTranslateX(translateX + 400); //随便写个偏移值测试
  };
  const clickLeftIcon = () => {
    if (translateX === 0) return;
    setTranslateX(translateX - 400);
  };
  console.log('translateX', translateX);
  return (
    <div className={styles.wrap_scrollImg}>
      <span className={styles.left_icon} onClick={clickLeftIcon}></span>
      <span className={styles.right_icon} onClick={clickRightIcon}></span>
      <ul style={{ transform: `translateX(${translateX}px)` }}>
        {imgData.map(item => {
          return <li>
            <img src={item.imgUrl} alt={item.name}/>
          </li>;
        })}

      </ul>
    </div>
  );
}

export default memo(Index);

以上代码初步效果-------------

可以看到点击左右方块图片‘切换了’,分析下有什么不足:每次点击切换时候需要偏移的宽度不准确、左侧边缘有缝隙(margin-left导致的)、切换时候偏移效果生硬、左右切换方向错了、偏移到最后一张图片位置时候需要停止,

经过改造效果:

 最终代码:

less文件-----------------


.wrap_scrollImg {
  width: 100%;
  height: 220px;
  //background-color: #2C9806;
  overflow: hidden;
  position: relative;

  &:hover {
    span {
      display: inline-block;
    }
  }

  span {
    cursor: pointer;
    z-index: 11;
    position: absolute;
    display: none;
    background-color: rgba(0, 0, 0, 0.3);
    top: 0;
    bottom: 0;
    margin: auto;
    height: 35px;
    line-height: 35px;
    width: 24px;
    text-align: center;
    color: white;
    font-size: 20px;
    transition: 0.2s;

    &:hover {
      font-size: 22px;
    }
  }

  .left_icon {
    left: 0;
  }

  .right_icon {
    right: 0;
  }

  ul {
    z-index: 10;
    height: inherit;
    white-space: nowrap;
    position: absolute;
    transition: all 0.5s ease-in 0s;  //偏移的过度效果
    margin-right: -1%; //设置ul偏右-用来抵消li元素右边距1%导致的缺口

    li {
      height: 100%;
      display: inline-block;
      min-width: calc(24%);
      width: calc(24%);
      margin-right: 1%;  //图片右边距
      overflow: hidden;
      border-radius: 6px;
      cursor: pointer;

      img {
        transition: all 0.3s;
        width: 100%;
        height: 100%;
        object-fit: cover;

        &:hover {
          transform: scale(1.1);
        }
      }
    }
  }
}

js文件---------------

import React, { Component, useState, memo, createRef } from 'react';
import styles from './index.less';
import { Icon } from 'antd';

function Index(props) {
  const ref = createRef();
  const { imgData } = props;
  const [translateX, setTranslateX] = useState(0); //每次偏移数值

  /**
   * 点击右侧按钮
   */
  const clickRightIcon = () => {
    if (ref.current.scrollWidth < Math.abs(translateX) + Math.abs(ref.current.offsetWidth)) {//到最后一页时候需要停止点击按钮
      return;
    }
    setTranslateX(translateX - ref.current.offsetWidth); //每次滚动可见区域宽度
  };

  /**
   * 点击左侧按钮
   */
  const clickLeftIcon = () => {
    if (translateX === 0) return;
    setTranslateX(translateX + ref.current.offsetWidth);
  };
  console.log('translateX', translateX);
  console.log('ref', ref);
  return (
    <div className={styles.wrap_scrollImg}>
      <span className={styles.left_icon} onClick={clickLeftIcon}><Icon type="left"/></span>
      <span className={styles.right_icon} onClick={clickRightIcon}><Icon type="right"/></span>
      <ul style={{ transform: `translateX(${translateX}px)` }} ref={ref}>
        {imgData.map(item => {
          return <li>
            <img src={item.imgUrl} alt={item.name}/>
          </li>;
        })}

      </ul>
    </div>
  );
}

export default memo(Index);

以上因为没有其他特定业务需求,所以就只封装成这个样子,有业务需求其实再在基础上增加几个参数就可以,例如每次图片显示多少张、或者切换过度时间为多少。思路对了就很简单。需要比较注意的点我已经再上面给出注释了

不要说我不会,要说我可以学
原文地址:https://www.cnblogs.com/seemoon/p/14482229.html