vue,uniapp 实现卷帘对比效果
需求:两张图重叠放在一起,拖动分割线实现卷帘对比效果,如图
一、vue2代码
<template><div class="main"><div class="img-comparison" @mousedown="startSlide"><img class="before" src="../assets/images/white/1.png" alt="Before" /><imgclass="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><imageclass="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>