Vue模仿實現(xiàn)京東商品大圖放大鏡效果
效果如下:

首先,有一個放大鏡的DOM結構
<template>
<div class="spec-preview">
<!-- 展示的原圖 -->
<img :src="imgObj.imgUrl" />
<!-- 綁定觸發(fā) -->
<div class="event"></div>
<!-- 放大圖 -->
<div class="big">
<img :src="imgObj.imgUrl" />
</div>
<!-- 遮罩層 -->
<div class="mask"></div>
</div>
</template>這里img的src是通過父組件傳過來的imgList來展示的,可以換成自己的任意圖
交代一下:遮罩層和展示圖都是正方形的,而且遮罩層的寬高都是展示圖的一半
分別要綁定鼠標移動事件,和獲取兩個元素節(jié)點,分別是遮罩層和放大圖
<template>
<div class="spec-preview">
<img :src="imgObj.imgUrl" />
<div class="event" @mousemove="handler"></div>
<div class="big">
<img :src="imgObj.imgUrl" ref="big" />
</div>
<!-- 遮罩層 -->
<div class="mask" ref="mask"></div>
</div>
</template>vue3中如何獲得ref綁定的節(jié)點元素呢?
首先,要知道在vue2中獲取ref節(jié)點元素是很簡單的,只需要this.$refs.mask即可。但是vue3中是沒有this.$refs的。
<script>
import { computed, getCurrentInstance, onMounted, ref } from "vue";
export default {
name: "ZoomIndex",
props: ["skuImageList"],
setup(props) {
let mask = ref(null);
let big = ref(null);
function handler(event) {
let handlerMask = mask.value;
let handlerBig = big.value;
}
return {
handler,
mask,
big,
};
},
};
</script>為了結構清楚,我把其他不涉及這個案例的代碼都刪掉了。handlerMask和handlerBig就是我們想要獲取的節(jié)點。
獲取到節(jié)點后,就可以寫相應的放大器實現(xiàn)代碼了
首先要獲取event的offserX也就是我們鼠標距離左側邊框的距離 ,然后還需要減去遮罩層本身寬度的一半,高度同理。并且添加約束條件,讓這個遮罩層不能出展示區(qū)域。最后就只需要修改相應元素的left和top屬性即可了(當然,這里肯定是要用到絕對定位的,子絕父相)
function handler(event) {
let handlerMask = mask.value;
let left = event.offsetX - handlerMask.offsetWidth / 2;
let top = event.offsetY - handlerMask.offsetHeight / 2;
// 約束范圍
if (left <= 0) left = 0;
if (left >= handlerMask.offsetWidth) left = handlerMask.offsetWidth;
if (top <= 0) top = 0;
if (top >= handlerMask.offsetHeight) top = handlerMask.offsetHeight;
// 修改元素的left|top屬性值
handlerMask.style.left = left + "px";
handlerMask.style.top = top + "px";
// 修改放大圖
let handlerBig = big.value;
handlerBig.style.left = -2 * left + "px";
handlerBig.style.top = -2 * top + "px";
}這里稍微有疑惑的可能就是放大圖為什么是-2去相乘。 首先根據(jù)前面的介紹,我們的展示圖和放大圖的大小是一致的,都是正方形。而遮罩層的寬高都是其一半。所以要把相應的遮罩層的圖片放大,就是簡單的乘以2即可。那為什么是負數(shù)。這就是涉及到放大圖的移動方向了。我們遮罩層向左移動,起始放大圖是相應的向右移動的。

.event {
width: 100%;
height: 100%;
position: absolute;
top: 0;
left: 0;
z-index: 998;
}
.mask {
width: 50%;
height: 50%;
background-color: rgba(0, 255, 0, 0.3);
position: absolute;
left: 0;
top: 0;
display: none;
}
.big {
width: 100%;
height: 100%;
position: absolute;
top: -1px;
left: 100%;
border: 1px solid #aaa;
overflow: hidden;
z-index: 998;
display: none;
background: white;
}
img {
width: 200%;
max-width: 200%;
height: 200%;
position: absolute;
left: 0;
top: 0;
}根據(jù)上面的展示(我把big里面的overflow:hidden去掉后的),可以看到,其實圖片的大小的是展示圖和放大鏡大小的2倍,超出部分是隱藏的。也就是向著相反的方向移動,使得我們遮罩層的區(qū)域放大后正好在放大鏡的展示區(qū)域中。
完整代碼如下:
<template>
<div class="spec-preview">
<img :src="imgObj.imgUrl" />
<div class="event" @mousemove="handler"></div>
<div class="big">
<img :src="imgObj.imgUrl" ref="big" />
</div>
<!-- 遮罩層 -->
<div class="mask" ref="mask"></div>
</div>
</template>
<script>
import { computed, getCurrentInstance, onMounted, ref } from "vue";
export default {
name: "ZoomIndex",
props: ["skuImageList"],
setup(props) {
const internalInstance = getCurrentInstance(); //當前組件實例
const $bus = internalInstance.appContext.config.globalProperties.$bus;
// console.log(props);
let currentIndex = ref(0);
let mask = ref(null);
let big = ref(null);
let imgObj = computed({
get() {
return props.skuImageList[currentIndex.value] || {};
},
});
function handler(event) {
let handlerMask = mask.value;
let left = event.offsetX - handlerMask.offsetWidth / 2;
let top = event.offsetY - handlerMask.offsetHeight / 2;
// 約束范圍
if (left <= 0) left = 0;
if (left >= handlerMask.offsetWidth) left = handlerMask.offsetWidth;
if (top <= 0) top = 0;
if (top >= handlerMask.offsetHeight) top = handlerMask.offsetHeight;
// 修改元素的left|top屬性值
handlerMask.style.left = left + "px";
handlerMask.style.top = top + "px";
// 修改放大圖
let handlerBig = big.value;
handlerBig.style.left = -2 * left + "px";
handlerBig.style.top = -2 * top + "px";
}
onMounted(() => {
// 全局事件總線,獲取兄弟組件傳遞過來的索引值
$bus.on("getIndex", (index) => {
// 修改當前響應式數(shù)據(jù)
currentIndex.value = index.value;
});
});
return {
currentIndex,
imgObj,
handler,
mask,
big,
};
},
};
</script>
<style lang="less">
.spec-preview {
position: relative;
width: 400px;
height: 400px;
border: 1px solid #ccc;
img {
width: 100%;
height: 100%;
}
.event {
width: 100%;
height: 100%;
position: absolute;
top: 0;
left: 0;
z-index: 998;
}
.mask {
width: 50%;
height: 50%;
background-color: rgba(0, 255, 0, 0.3);
position: absolute;
left: 0;
top: 0;
display: none;
}
.big {
width: 100%;
height: 100%;
position: absolute;
top: -1px;
left: 100%;
border: 1px solid #aaa;
// overflow: hidden;
z-index: 998;
display: none;
background: white;
img {
width: 200%;
max-width: 200%;
height: 200%;
position: absolute;
left: 0;
top: 0;
}
}
.event:hover ~ .mask,
.event:hover ~ .big {
display: block;
}
}
</style>到此這篇關于Vue模仿實現(xiàn)京東商品大圖放大鏡效果的文章就介紹到這了,更多相關Vue放大鏡效果內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!
相關文章
Antd-vue Table組件添加Click事件,實現(xiàn)點擊某行數(shù)據(jù)教程
這篇文章主要介紹了Antd-vue Table組件添加Click事件,實現(xiàn)點擊某行數(shù)據(jù)教程,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧2020-11-11
vue3-treeselect數(shù)據(jù)綁定失敗的解決方案
這篇文章主要介紹了vue3-treeselect數(shù)據(jù)綁定失敗的解決方案,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教2024-05-05
vue配置electron使用electron-builder進行打包的操作方法
這篇文章主要介紹了vue配置electron使用electron-builder進行打包的操作方法,本文通過實例代碼給大家介紹的非常詳細,感興趣的朋友跟隨小編一起看看吧2024-08-08
vue.js動態(tài)修改background-image問題
這篇文章主要介紹了vue.js動態(tài)修改background-image問題,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2022-08-08

