Vue中实现放大镜效果
先来看一下我们需要实现的效果是怎样的:
这里我们没有使用原生的 js 方法去实现, 而是使用的 Vue3 官方推荐的一个工具库 @vueuse/cor 中的 useMouseInElement 方法来实现放大镜的效果
首先来看一下 useMouseInElement 这个方法的返回值有哪些, 会使用到哪些?
我们会使用到 elementX, elementY, isOutside 这三个值, 它们分别的含义是:
- elementX 是鼠标在页面的当前 x 轴坐标位置
- elementY 是鼠标在页面的当前 y 轴坐标位置
- isOutside 是一个布尔值, false 表示鼠标没有在监听元素内; true 表示鼠标在监听的元素内
放大镜效果的元素就是:
- 根据鼠标在中图里的当前坐标位置, 通过判断, 将符合条件的鼠标坐标值赋值给遮罩层和大图的坐标
思路分析:
1. 定义一个变量, 控制遮罩层和大图的显示隐藏效果(show)
2. 定义一个对象, 此对象是直接丢到遮罩层元素的 style 属性中; 所以此对象中的只要符合 css 的规则, 此对象的成员为 top 和 left (遮罩层使用了绝对定位, layerPosition)
3. 定义一个对象, 此对象是直接丢到大图元素的 style 属性中; 主要是控制大图的背景图片位置, 所以成员是 backgroundPositionX 和 backgroundPositionY(largePosition)
4. 定义监听页面元素对象的实例(target)
5. 将 target 传给 useMouseInElement , 获取返回值 elementX, elementY, isOutside (它们都是响应式数据)
6. isOutside 动态的修改掉 show 的值
7. 通过条件判断, 动态的修改到 layerPosition 对象和 largePosition 对象的值
8. 将 show, layerPosition, largePosition 抛给页面使用即可
也就说, elementX = 100 的时候, 遮罩层成的偏移量才可以变化, 这里就是起点
elementX = 300 的时候, 遮罩层的偏移量停止变化, 这里就是终点
所以 elementX = 100 时, layerPosition.left = 0
elementX = 300 时, layerPosition.left = 200
始终要比 elementX 少 100
<template>
<div class="goods-image">
<!-- 大图 -->
<div v-show="show" class="large" :style="[{backgroundImage:`url(${images[currIndex]})`}, largePosition]"></div>
<!-- 中图 -->
<div class="middle" ref="target">
<img :src="images[currIndex]" alt="">
<!-- 遮罩色块 -->
<div v-show="show" class="layer" :style="layerPosition"></div>
</div>
<!-- 小图 -->
<ul class="small">
<li v-for="(item, i) in images" :key="item" :class="{active: currIndex===i}">
<img @mouseenter="currIndex=i" :src="item" alt="">
</li>
</ul>
</div>
</template>
<script>
import { reactive, ref, watch } from 'vue'
import { useMouseInElement } from '@vueuse/core'
export default {
name: 'GoodsImage',
props: {
images: {
type: Array,
default: () => []
}
},
setup (props) {
const currIndex = ref(0)
// 1. 是否显示遮罩和大图
const show = ref(false)
// 2. 遮罩的坐标(样式)
const layerPosition = reactive({
top: 0,
left: 0
})
// 3. 大图的背景坐标(样式)
const largePosition = reactive({
backgroundPositionX: 0,
backgroundPositionY: 0
})
// 4. 获取监听元素的实例对象, 使用useMouseInElement函数进行获取坐标
const target = ref(null)
const { elementX, elementY, isOutside } = useMouseInElement(target)
// 5. 监听元素坐标值的变化
watch([elementX, elementY, isOutside], () => {
show.value = !isOutside.value
const position = { X: 0, Y: 0 }
if (elementX.value < 100) position.X = 0
else if (elementX.value > 300) position.X = 200
else position.X = elementX.value - 100
if (elementY.value < 100) position.Y = 0
else if (elementY.value > 300) position.Y = 200
else position.Y = elementY.value - 100
layerPosition.left = position.X + 'px'
layerPosition.top = position.Y + 'px'
largePosition.backgroundPositionX = -2 * position.X + 'px'
largePosition.backgroundPositionY = -2 * position.Y + 'px'
})
return { currIndex, show, layerPosition, largePosition, target }
}
}
</script>
<style scoped lang="less">
.goods-image {
width: 480px;
height: 400px;
position: relative;
display: flex;
z-index: 500;
.large {
position: absolute;
top: 0;
left: 412px;
width: 400px;
height: 400px;
box-shadow: 0 0 10px rgba(0,0,0,0.1);
background-repeat: no-repeat;
background-size: 800px 800px;
background-color: #f8f8f8;
}
.middle {
width: 400px;
height: 400px;
background: #f5f5f5;
position: relative;
cursor: move;
.layer {
width: 200px;
height: 200px;
background: rgba(0,0,0,.2);
left: 0;
top: 0;
position: absolute;
}
}
.small {
width: 80px;
li {
width: 68px;
height: 68px;
margin-left: 12px;
margin-bottom: 15px;
cursor: pointer;
&:hover,&.active {
border: 2px solid @xtxColor;
}
}
}
}
</style>
更多推荐
所有评论(0)