天天看點

JS實作放大鏡的效果 —— 仿京東詳情頁中的産品放大效果

案例簡述 

 這次案列是模仿京産品詳情頁中,産品圖放大的效果。

簡單說下效果的具體步驟:

1.滑鼠經過預覽區時,遮蓋層和産品大圖顯示;滑鼠離開則隐藏

2.遮蓋層跟随滑鼠進行移動,并且遮蓋層隻在預覽區域内移動,超出範圍位置則不動

3.大圖中産品位置跟随遮蓋層的位置變化。換句話說就是大圖中産品的細節部分與遮蓋層聚焦的産品細節與之對應。

先看下京東原版的效果

JS實作放大鏡的效果 —— 仿京東詳情頁中的産品放大效果

案例實作的整體思想

第一部分:滑鼠經過和離開預覽區,遮蓋層和大圖檔顯示或隐藏。

這部分主要是給預覽區添加偵聽器:兩個滑鼠事件mouseover、mouseleave,對遮蓋層和大圖檔的display進行控制。

第二部分:遮蓋層跟随滑鼠移動而移動。

第二部分的内容是比較複雜的,是最重要的部分。mousemove事件。首先來分析一下,要想遮蓋層跟随滑鼠移動,其核心思想就是獲得滑鼠在預覽區的坐标,并把滑鼠實時更新的坐标值指派給遮蓋層的left和top值。

第二部分的完成主要分為三個步驟:a. 給預覽區添加滑鼠移動的偵聽器,同時立即獲得滑鼠目前在預覽區的位置,使用e.pageX - 預覽區.offsetLeft 得到滑鼠在預覽區的水準位置,垂直位置同理。b. 再來确定遮蓋層的偏移量,把a中的滑鼠的位置指派給遮蓋層。如果直接指派的話,滑鼠在遮蓋層的左上角,為了讓滑鼠在遮蓋層的中心位置,在設定遮蓋層的位置時,需要減去遮蓋層自身寬\高的一半。c. 最後一步,還要判斷遮蓋層偏移量的範圍,不能超出預覽區。

第三部分:設定大圖檔的偏移量

這部分有個公式也算是個算法:遮擋層移動位置/遮擋層最大移動位置 = 大圖檔移動位置/大圖檔最大移動位置。按比例移動

掌握公式,剩下的就是計算問題了。要注意的是,根據公式算出來的資料指派給大圖檔時要取反,就是取負值。

ok,以上就是本次案例的整個制作思路。有很多細節的地方,要自己去測試才能發現的。更詳細的步驟我在JS代碼部分裡面有注釋。

代碼

重點部分:JS

window.addEventListener('load', function () {
    // 放大鏡效果
    // 1.滑鼠經過區域 遮擋層和大圖檔顯示和隐藏
    // 2.滑鼠移動 遮擋層跟着移動 主要是獲得滑鼠移動時不斷變化的位置指派給遮擋層
    // 3.遮擋層與大圖檔位置與之對應 按比例移動


    // 1.滑鼠經過preview_img時 遮擋層和大圖檔顯示 和 隐藏
    // 擷取事件源
    var preview_img = this.document.querySelector('.preview_img');
    var mask = this.document.querySelector('.mask');
    var big = this.document.querySelector('.big');
    // 注冊事件
    preview_img.addEventListener('mouseover', function () {
        mask.style.display = 'block';
        big.style.display = 'block';
    })
    preview_img.addEventListener('mouseleave', function () {
        mask.style.display = 'none';
        big.style.display = 'none';
    })
    // 2.滑鼠移動 更新遮擋層的位置
    // 給區域添加偵聽器,隻要滑鼠一移動 就更新遮擋層的位置  切記:隻有開啟定位的盒子 才可以使用left和top值
    preview_img.addEventListener('mousemove', function (e) {

        // (1) 經過時 就要獲得滑鼠在preview_img裡面的坐标
        var mouseX = e.pageX - preview_img.offsetLeft;
        var mouseY = e.pageY - preview_img.offsetTop;
        // console.log(mouseX, mouseY); 
        // (2) 更新遮擋層的位置 
        // a.如果直接指派的話:滑鼠是在遮擋層的左上角,為了美觀滑鼠應該在遮擋層的中心位置 - 盒子高\寬的一半
        var maskX = mouseX - mask.offsetWidth / 2;
        var maskY = mouseY - mask.offsetHeight / 2;
        // b.此時還會出現一個問題:遮擋層在preview_img區域之外也出現了  我們隻需要在區域内顯示 區域外不顯示
        // 是以 我們需要一個判斷條件 left的最大值(previwe_img.width-mask.width)和最小值(0)
        var maskMax = preview_img.offsetWidth - mask.offsetWidth;
        if (maskX <= 0) {
            maskX = 0;
        } else if (maskX >= maskMax) {
            maskX = maskMax;
        }
        if (maskY <= 0) {
            maskY = 0;
        } else if (maskY >= maskMax) {
            maskY = maskMax;
        }
        mask.style.left = maskX + 'px';
        mask.style.top = maskY + 'px';
        // console.log(mask.style.left, mask.style.top);

        // 3.大圖檔跟随遮擋層的移動而移動 
        // 有一個核心算法: 遮擋層移動位置/遮擋層最大移動位置 = 大圖檔移動位置/大圖檔最大移動位置
        // 遮擋層移動位置:maskX maxkY; 遮擋層最大移動位置:maskMax 
        // 大圖檔移動位置: bigX bigY; 大圖檔最大移動位置:bigMax
        // (1)bigMax = 圖檔尺寸-裝圖檔盒子的尺寸  圖檔比盒子大
        var bigImg = document.querySelector('.bigImg');
        var bigMax = bigImg.offsetWidth - big.offsetWidth;
        // (2) bigX = 遮擋層移動位置 * 大圖檔最大移動位置 / 遮擋層最大移動位置
        var bigX = maskX * bigMax / maskMax;
        var bigY = maskY * bigMax / maskMax;
        // (3) 大圖檔的left和top值: big系列的值  的負值
        bigImg.style.left = -bigX + 'px';
        bigImg.style.top = -bigY + 'px';
    })
})
           

 搭建結構:一定要記得引入css檔案和js檔案

<div class="preview_wrap ">
        <div class="preview_img">
            <img src="upload/s3.png" alt="">
            <!-- 遮擋層 -->
            <div class="mask"></div>
            <!-- 放大版的圖檔 -->
            <div class="big">
                <img src="upload/big.jpg" alt="" class="bigImg">
            </div>
        </div>
    </div>
           

樣式:

.preview_wrap {
            width: 400px;
            height: 590px;
        }

        .preview_img {
            position: relative;
            height: 398px;
            border: 1px solid #ccc;
        }

        .mask {
            display: none;
            position: absolute;
            top: 0;
            left: 0;
            width: 300px;
            height: 300px;
            background: #FEDE4F;
            opacity: .5;
            border: 1px solid #ccc;
            cursor: move;
        }

        .big {
            display: none;
            position: absolute;
            left: 410px;
            top: 0;
            width: 500px;
            height: 500px;
            background-color: pink;
            z-index: 999;
            border: 1px solid #ccc;
            overflow: hidden;
        }

        .big img {
            position: absolute;
            top: 0;
            left: 0;
        }
           

最後附上我的效果圖。

JS實作放大鏡的效果 —— 仿京東詳情頁中的産品放大效果

end!

加油加油,每天進步一點點。同時也要每天給自己一點放松的時間,身體和靈魂總要有一個在路上。

好看的皮囊千篇一律,有趣的靈魂萬裡挑一,我想漸漸的、慢慢的變成那個萬裡挑一的人。

繼續閱讀