滑动对比显示


该组件的实现原理是这样的:
首先将两张图片相对于父元素做绝对定位,然后将上层的图片宽度随着拖拽做动态变换,以此改变下层图片的漏出位置的大小。
核心实现就是通过 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 许可协议,转载请注明出处。
如果内容对你有用,请作者喝杯咖啡 ☕:
如果内容对你有用,请作者喝杯咖啡 ☕: