S: 实现一个组件,会跟随鼠标移动,改变左右图片的大小,但是图片并不放缩
思路: 一开始尝试使用background,通过改变两边的宽度来实现,但是实现发现,右边的图片其实是会放缩的,这时候通过查阅资料发现,可以通过clip-path来实现。
clip-path属性是CSS3中的一个属性,用于指定元素的剪辑区域。它可以用来裁剪元素的可见部分,使其呈现出不规则的形状或剪影效果。
clip-path属性的值可以是各种形状,包括基本形状(如矩形、圆形、椭圆等)以及路径形状(通过SVG路径数据描述)。以下是一些常用的clip-path属性值:
-
矩形形状:
clip-path: inset(10px 20px 30px 40px);:指定一个矩形的内边距,裁剪元素的可见区域为指定矩形范围内。
-
圆形形状:
clip-path: circle(50%);:指定一个以元素中心为圆心的圆形,裁剪元素的可见区域为圆形内部。
-
椭圆形状:
clip-path: ellipse(50% 50% at 50% 50%);:指定一个以元素中心为焦点的椭圆形,裁剪元素的可见区域为椭圆形内部。
-
自定义路径形状(通过SVG路径数据):
clip-path: path('M50 0 L100 50 L50 100 L0 50 Z');:通过SVG路径数据描述自定义的路径形状,裁剪元素的可见区域为路径内部。
使用clip-path属性时,可以将其应用于任何具有可见效果的元素,如div、img等。请注意,clip-path属性的兼容性可能会因浏览器而异,特别是一些旧版浏览器对其支持较差。为了获得更好的兼容性,可以考虑使用兼容性较好的CSS前缀或使用其他方法实现类似的效果,如使用mask属性或使用SVG元素作为剪辑路径。
具体实现:
<template>
<div
class="container"
ref="container"
:style="{height: `${height}px`}"
@mouseenter="handleMouseEnter"
@mouseleave="handleMouseLeave"
>
<div
class="left-img img"
ref="left"
:style="{backgroundImage: `url(${originImg})`}"
></div>
<div class="resizer" ref="resizer">
<div class="axisx"></div>
<div class="btn"><div class="blur" /></div>
<div class="axisx"></div>
</div>
<div class="right-img img"
ref="right"
:style="{backgroundImage: `url(${patternImg})`}"
></div>
</div>
</template>
<script>
export default {
name: 'pictureSlider',
props: {
originImg: {
type: String,
default: ''
},
patternImg: {
type: String,
default: ''
},
height: {
type: Number,
default: 400
}
},
data(){
return {
x: 0,
leftWidth: 0
}
},
beforeDestory(){
this.handleMouseLeave()
},
method: {
handleMouseDown(e){
e.preventDefault();
this.x = e.clientX;
this.leftWidth = this.$refs.left.getBoundingClientRect().width;
},
handleMouseEnter(){
document.addEventListen('mousemove', this.handleMouseMove);
},
handleMouseMove(e){
if(!this.$refs.container) return
const rect = this.$refs.container.getBoundingClientRect();
const dx = e.clientX - rect.left;
let newLeftWidth = (dx * 100)/ rect.width;
newLeftWidth = Math.max(newLeftWidth, 0);
newLeftWidth = Math.min(newLeftWidth, 100);
this.$refs.left.style.clipPath = `insert(0 ${rect.width -dx}px 0 0)`;
this.$refs.right.style.clipPath = `insert(0 0 0 ${dx})`;
this.$refs.resizer.style.left = `${newLeftWidth}%`;
},
handleMouseLeave(){
document.removeEventListener('mousemove', this.handleMouseMove);
},
reset(){
this.$refs.left.style.clipPath = `inset(0 50% 0 0 )`;
this.$refs.right.style.clipPath = `inset(0 0 0 50%)`;
this.$refs.resizer.style.left = `${newLeftWidth}%`;
}
}
}
</script>
<style lang="less" scoped>
.container {
position: relative;
overflow: hidden;
.img {
position: absolute;
top: 0;
height: 100%;
width: 100%;
background-size: cover;
background-repeat: no-repeat;
background-position: center;
left: 0;
}
.left-img {
z-index: 1;
clip-path: inset(0 50% 0 0);
}
.right-img {
clip-path: inset(0 0 0 50%);
z-index: 2;
}
.resizer {
position: absolute;
left: 50%;
top: 0;
height: 100%;
cursor: ew-resize;
z-index: 999;
display: flex;
flex-direction: column;
align-items: center;
transform: translate(-50%);
.axisx {
flex: 1;
width: 2px;
background-color: #fff;
}
.btn {
height: 32px;
width: 32px;
border-radius: 50%;
border: 2px solid #fff;
cursor: ew-resize;
z-index: 9999;
background: url('~@/assets/image/pictureSlider.svg') no-repeat;
background-color: rgba(255, 255, 255, 0.1);
background-position: center;
.blur {
width: 100%;
heigth: 100%;
border-radius: 50%;
backdrop-filter: blur(0.5px); // 毛玻璃
}
}
}
}
</style>