跳到主要内容

滑动对比显示

code
text

该组件的实现原理是这样的:

首先将两张图片相对于父元素做绝对定位,然后将上层的图片宽度随着拖拽做动态变换,以此改变下层图片的漏出位置的大小。

核心实现就是通过 js 来控制中间拖拽的那个手柄的位置变化。

代码实现

import React from 'react';
import { useRef, useState, useEffect } from 'react';
import styles from './style.module.scss';

export default function ({ img1, img2, height }) {
const container = useRef();
const [width, setWidth] = useState();
const [transform, setTransform] = useState();

useEffect(() => {
const { width: w } = container.current.getBoundingClientRect()
setTransform(w / 2);
setWidth(w);
}, []);

const onMousedown = () => {
document.addEventListener('mousemove', onMousemove)
document.addEventListener('mouseup', onMouseup)
};
function onMousemove(evt) {
const { clientX } = evt
const { left, width } = container.current.getBoundingClientRect()
setTransform(Math.max(0, Math.min(clientX - left, width)))
}
const onTouchstart = () => {
document.addEventListener('touchmove', onTouchmove)
document.addEventListener('touchend', onTouchend)
};
function onTouchmove(evt) {
const { clientX } = evt.touches[0]
const { left, width } = container?.current?.getBoundingClientRect?.()
setTransform(Math.max(0, Math.min(clientX - left, width)))
};
function onTouchend() {
document.removeEventListener('touchmove', onTouchmove)
document.removeEventListener('touchend', onTouchend)
}

function onMouseup() {
document.removeEventListener('mousemove', onMousemove)
document.removeEventListener('mouseup', onMouseup)
}
return (
<div
ref={container}
className={styles.container}
style={{ width: width + 'px', height: height + 'px' }}
>
<div className={styles.img1Wrap}>
<img width={width} src={img1} alt="code" />
</div>
<div style={{ width: transform + 'px' }} className={styles.img2Wrap}>
<img width={width} src={img2} alt="text" />
</div>
<div
className={styles.touchBar}
style={{ transform: `translate3d(${transform - 15}px, 0, 0)` }}
onMouseDown={onMousedown}
onTouchStart={onTouchstart}
>
<div className={styles.centerHandle}>
<div className={styles.left}></div>
<div className={styles.right}></div>
</div>
</div>
</div>
)
}