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