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);

以上因為沒有其他特定業務需求,所以就只封裝成這個樣子,有業務需求其實再在基礎上增加幾個參數就可以,例如每次圖片顯示多少張、或者切換過度時間為多少。思路對了就很簡單。需要比較注意的點我已經再上面給出注釋了

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM