vue,uniapp 实现卷帘对比效果

发布于:2025-09-13 ⋅ 阅读:(21) ⋅ 点赞:(0)

需求:两张图重叠放在一起,拖动分割线实现卷帘对比效果,如图

在这里插入图片描述
在这里插入图片描述

一、vue2代码

<template>
  <div class="main">
    <div class="img-comparison" @mousedown="startSlide">
      <img class="before" src="../assets/images/white/1.png" alt="Before" />
      <img
        class="after"
        src="../assets/images/white/2.png"
        alt="After"
        :style="{
          clipPath:
            'polygon(0 0, ' +
            sliderPosition +
            '% 0, ' +
            sliderPosition +
            '% 100%, 0 100%)',
        }"
      />
      <div class="slider" :style="{ left: sliderPosition + '%' }"></div>
    </div>
  </div>
</template>

<script>
export default {
  data() {
    return {
      sliderPosition: 0, // 初始位置设为 0 (左侧)
      isSliding: false,
    };
  },
  methods: {
    startSlide(e) {
      this.isSliding = true;
      document.addEventListener("mousemove", this.moveSlider);
      document.addEventListener("mouseup", this.endSlide);
      this.moveSlider(e);
      // 禁止文本和图片选中
      document.body.style.userSelect = "none";
    },
    moveSlider(e) {
      if (!this.isSliding) return;
      const comparisonRect = e.target
        .closest(".img-comparison")
        .getBoundingClientRect();
      const newPosition = e.clientX - comparisonRect.left;
      this.sliderPosition =
        (Math.max(0, Math.min(comparisonRect.width, newPosition)) /
          comparisonRect.width) *
        100;
    },
    endSlide() {
      this.isSliding = false;
      document.removeEventListener("mousemove", this.moveSlider);
      document.removeEventListener("mouseup", this.endSlide);
      // 恢复文本和图片的可选中行为
      document.body.style.userSelect = "";
    },
  },
};
</script>

<style lang="scss" scoped>
.main {
  display: flex;
  align-items: center;
  justify-content: center;
  height: 100vh;
  background-color: black;

  .img-comparison {
    position: relative;
    width: 100%;
    max-width: 600px;
    user-select: none; // 禁用选择

    img {
      width: 100%;
      height: 600px;
      pointer-events: none; // 禁止图片的鼠标事件,以避免选中
    }

    .after {
      position: absolute;
      top: 0;
      left: 0;
      transition: clip-path 0.3s ease; // 加快动画速度
    }

    .slider {
      position: absolute;
      top: 0;
      bottom: 0;
      width: 2px;
      background-color: rgba(255, 255, 255, 0.5);
      cursor: ew-resize;
      transition: left 0.3s ease; // 加快动画速度
    }
  }
  .img-comparison:hover {
    cursor: pointer;
  }
}
</style>    

二、uniapp代码

<template>
    <view class="main">
        <view class="img-comparison" @touchstart="startSlide" @touchmove="moveSlider" @touchend="endSlide">
            <image class="before" :src="require('../../static/888.png')" mode="aspectFill" alt="Before"></image>
            <image
                class="after"
                :src="require('../../static/999.png')"
                mode="aspectFill"
                :style="{
                    clipPath:
                        'polygon(0 0, ' +
                        sliderPosition +
                        '% 0, ' +
                        sliderPosition +
                        '% 100%, 0 100%)',
                }"
                alt="After"
            ></image>
            <view class="slider" :style="{ left: sliderPosition + '%' }"></view>
        </view>
    </view>
</template>

<script>
export default {
    data() {
        return {
            sliderPosition: 0, // 初始位置设为 0 (左侧)
            isSliding: false,
        };
    },
    methods: {
        startSlide(e) {
            this.isSliding = true;
            this.moveSlider(e);
        },
        moveSlider(e) {
            if (!this.isSliding) return;
            const query = uni.createSelectorQuery().in(this);
            query.select('.img-comparison').boundingClientRect((res) => {
                const newPosition = e.changedTouches[0].clientX - res.left;
                this.sliderPosition =
                    (Math.max(0, Math.min(res.width, newPosition)) / res.width) * 100;
            }).exec();
        },
        endSlide() {
            this.isSliding = false;
        },
    },
};
</script>

<style lang="scss" scoped>
.main {
    display: flex;
    align-items: center;
    justify-content: center;
    height: 100vh;
    background-color: black;

    .img-comparison {
        position: relative;
        width: 100%;
        max-width: 600px;
        user-select: none; // 禁用选择

        image {
            width: 100%;
            height: 600px;
            pointer-events: none; // 禁止图片的鼠标事件,以避免选中
        }

        .after {
            position: absolute;
            top: 0;
            left: 0;
            transition: clip-path 0.3s ease; // 加快动画速度
        }

        .slider {
            position: absolute;
            top: 0;
            bottom: 0;
            width: 2px;
            background-color: rgba(255, 255, 255, 0.5);
            cursor: ew-resize;
            transition: left 0.3s ease; // 加快动画速度
        }
    }
    .img-comparison:hover {
        cursor: pointer;
    }
}
</style>    

网站公告

今日签到

点亮在社区的每一天
去签到