滑动对比显示
该组件的实现原理是这样的:
首先将两张图片相对于父元素做绝对定位,然后将上层的图片宽度随着拖拽做动态变换,以此改变下层图片的漏出位置的大小。
核心实现就是通过 js
来控制中间拖拽的那个手柄的位置变化。
代码实现
- JSX
- CSS
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>
)
}
.container {
position: relative;
user-select: none;
.img1Wrap {
overflow: hidden;
width: 100%;
height: 100%;
position: absolute;
top: 0;
left: 0;
pointer-events: none;
img {
height: 100%;
max-width: none;
}
}
.img2Wrap {
overflow: hidden;
height: 100%;
top: 0;
left: 0;
position: absolute;
pointer-events: none;
img {
height: 100%;
max-width: none;
}
}
.touchBar {
height: 100%;
top: 0;
position: absolute;
display: flex;
align-items: center;
justify-content: center;
&::before {
content: "";
width: 3px;
position: absolute;
top: 0;
height: 50%;
border-radius: 0.25rem;
background: rgba(247, 248, 250, 1);
}
&::after {
content: "";
width: 3px;
position: absolute;
bottom: 0;
height: 50%;
border-radius: 0.25rem;
background: rgba(247, 248, 250, 1);
}
.centerHandle {
background: rgba(247, 248, 250, 1);
border-radius: 0.125rem;
cursor: pointer;
display: flex;
width: 30px;
z-index: 9;
padding: .125rem;
.left {
background-color: currentColor;
height: 1.2em;
width: 1.2em;
mask-image: url("data:image/svg+xml;utf8,%3Csvg viewBox='0 0 512 512' mask-image='var(--un-icon)' width='1.2em' height='1.2em' xmlns='http://www.w3.org/2000/svg' %3E%3Cpath d='M327.3 98.9l-2.1 1.8-156.5 136c-5.3 4.6-8.6 11.5-8.6 19.2 0 7.7 3.4 14.6 8.6 19.2L324.9 411l2.6 2.3c2.5 1.7 5.5 2.7 8.7 2.7 8.7 0 15.8-7.4 15.8-16.6V112.6c0-9.2-7.1-16.6-15.8-16.6-3.3 0-6.4 1.1-8.9 2.9z' fill='currentColor'/%3E%3C/svg%3E");
mask-size: 100% 100%;
color: inherit;
}
.right {
background-color: currentColor;
height: 1.2em;
width: 1.2em;
mask-image: url("data:image/svg+xml;utf8,%3Csvg viewBox='0 0 512 512' mask-image='var(--un-icon)' width='1.2em' height='1.2em' xmlns='http://www.w3.org/2000/svg' %3E%3Cpath d='M184.7 413.1l2.1-1.8 156.5-136c5.3-4.6 8.6-11.5 8.6-19.2 0-7.7-3.4-14.6-8.6-19.2L187.1 101l-2.6-2.3C182 97 179 96 175.8 96c-8.7 0-15.8 7.4-15.8 16.6v286.8c0 9.2 7.1 16.6 15.8 16.6 3.3 0 6.4-1.1 8.9-2.9z' fill='currentColor'/%3E%3C/svg%3E");
mask-size: 100% 100%;
color: inherit;
}
}
}
}
本站内容遵守 CC BY-NC-SA 4.0 许可协议,转载请注明出处。
如果内容对你有用,请作者喝杯咖啡 ☕:
如果内容对你有用,请作者喝杯咖啡 ☕: