1. 程式人生 > >用原生js實現淘寶詳情頁圖片放大鏡效果

用原生js實現淘寶詳情頁圖片放大鏡效果

這個功能是我在模仿淘寶詳情頁的時候做出來的,最初版本對於非1:1比例的圖片沒有做處理,後續對程式進行了完善和邏輯上修改,形成了當前的程式。

廢話不多說,直接進入正題了,先上個效果圖


先放上這段功能的html程式碼

<div id="full-pic">
    <img src="img/full-pic-1.jpg" alt="">
    <span id="pic-span"></span>
    <div id="big-pic">
        <img src="img/big-full-pic-1.jpg" alt="">
    </div>
</div>

然後是這段html對應的css程式碼

#full-pic{
    position: relative;
    width: 400px;
    height: 400px;
    background:#eee;
}
#full-pic>img{
    display: block;
    height: 400px;
    margin:0 auto;
}
#pic-span{
    display: none;
    position: absolute;
    cursor: move;
    width: 200px;
    height: 200px;
    background: url(../img/pic-span.png);
    left: 0px;
    top: 0px;
    z-index: 1;
}
#big-pic{
    width: 400px;
    height: 400px;
    overflow: hidden;
    background: white;
    position: absolute;
    left: 410px;
    top: 0;
    display: block;
}
#big-pic>img{
    display: block;
    position: absolute;
    left: 0;
    top: 0;
}

這裡有一張圖來解釋整個html佈局和css樣式


下面這張圖是頁面的顯示效果


滑動下面的小圖片可以實現上面的樣板圖片的切換以及右邊大圖的切換,實現起來很簡單,就不贅述了

然後就是原生js的程式碼了

var pic_div = document.getElementById('full-pic');//拿到整個大的div
var normal_pic = pic_div.getElementsByTagName('img')[0];//拿到div中的圖片
var span_move = document.getElementById('pic-span');//拿到顯示當前圖片位置的span
var big_div = document.getElementById('big-pic');//拿到右邊放置放大圖片的div
var pic_move = big_div.getElementsByTagName('img')[0];//拿到右側放大的圖片本身
//當滑鼠在最外層div中滑動的時候觸發事件,因為要獲取當前的滑鼠位置所以要拿到事件源evt
pic_div.onmousemove = function (evt) {
    // 獲取事件
    var e = evt || window.event;

在這裡解釋一下為什麼事件要加在外圍最大的div上,因為當時做的時候沒有注意到這些樣板圖圖片的寬高比例是不同的

大部分為1:1,也有小部分2:3等等其他比例的,這樣的話就導致限制高度為400px後,不同比例的圖片他們的寬度也就不同

後來進行修正程式的時候覺得麻煩就沒有改了(主要是懶以及嘗試修正發現不會弄哈哈)

    // 獲取大圖和小圖之間的倍數     
    var bigSize = pic_move.offsetHeight;
    var littleSize = normal_pic.offsetHeight;
    var n = bigSize / littleSize;

正如前面所說的,因為圖片的比例是不同的,導致他們顯示出來的寬度不同,當我限制他們的高度為400px時

非1:1比例的圖片他們的寬度就變得很不規律了,這時候只能通過他們的高度變化來獲取他們整體縮放了多少倍

    //獲取pic對於頁面的絕對位置
    var pic_x = normal_pic.getBoundingClientRect().left;
    var pic_y = normal_pic.getBoundingClientRect().top + document.documentElement.scrollTop;

為什麼使用了getBoundingClientRect()這個方法?

getBoundingClientRect()會返回一個數據陣列,包含了當前元素在瀏覽器中的位置,包括left,right,top和bottom等,通過這個方法我們可以拿到居中的樣板圖對於瀏覽器的相對位置。獲取後的資料處理後面有寫到

因為我們要獲取滑鼠在整個最外面div裡面的相對位置來讓span移動(控制顯示範圍)

之前我使用的是clientLeft,但是我發現使用clientLeft時,並不能實現預期的功能,會出現一定的誤差。

    // 獲取滑鼠相對full-pic的位置
    var mouse_x = e.pageX - pic_x;
    var mouse_y = e.pageY - pic_y;

產生這個問題的原因在於,圖片的比例是不盡相同的,除了大部分的1:1,還有2:3這種比例,而這是我們又將圖片的高度限制為400px,同時我們將圖片設為居中,當比例為2:3時,就會在full-pic這個div中居中併產生一個左右的margin值,若直接使用滑鼠在full-pic中移動的資料的話就會產生一個誤差值。

因此最後我選擇了使用pageX-樣板圖的左側在當前頁面中的絕對位置來得到滑鼠對於圖片的相對位置。

獲取滑鼠在圖片中縱向的相對位置時,先拿到了樣板圖的頂部在頁面中的絕對位置,然後和頁面滾動距離相加,就拿到了當前圖片的頂部在文件流中的絕對位置。再使用pageY減去這個位置,即可拿到滑鼠對於樣板圖的相對移動位置。

    //將兩個div的設定為顯示
    big_div.style.display = 'block';
    span_move.style.display = 'block';

設定邊際以及圖片移動的演算法

span_move.style.width = normal_pic.offsetWidth / 2 + 'px';
span_move.style.height = normal_pic.offsetWidth / 2 + 'px';

這兩句程式碼是用來控制span的寬度和高度,因為我發現span的大小不是固定的,而是隨著樣板圖的寬度變化的且永遠是樣板圖寬度的一半,且高度和寬度相同,span為一個正方形

設定完span的寬度,因為我們需要讓span的中心始終跟著滑鼠

所以判斷條件的兩個臨界值分別為span.width/2以及圖片寬度減去span.width/2

normal_pic高度固定為400px,寬度不一定,一般為400px

    //設定邊際以及圖片移動的演算法
    if (mouse_x <= span_move.offsetWidth / 2) {
        //在最左側不發生移動的情況
        pic_move.style.left = '0px';//右邊大圖位置為0px
        span_move.style.left = normal_pic.offsetLeft + 'px';//span始終和圖片左端對齊
    } else
        if (mouse_x > span_move.offsetWidth/ 2 && mouse_x < normal_pic.offsetWidth - span_move.offsetWidth / 2) {

normal_pic.offsetWidth - span_move.offsetWidth / 2 這個是我們限制的滑鼠最右可以移動到的範圍

這是這個邊界的解釋


▲這張圖顯示的是非1:1比例的圖片的限制範圍,如果是1:1比例的話和這個是通用的

用滑鼠的相對位置減去span.width/2可以得到span要移動的距離

var tempX = mouse_x - span_move.offsetWidth/ 2;
pic_move.style.left = -n * (tempX) + 'px';//控制右側大圖的移動
span_move.style.left = tempX + normal_pic.offsetLeft + 'px';//控制span位置的移動

在設定span的移動時候給span加上了normal_pic.offsetLeft這個值,因為tempX是滑鼠相對於樣板圖的位置,而樣板圖相對於外層的div始終可能會有一個偏移量,如果不加上會就會在中間產生一個範圍讓span移動到圖片左側之外。所以我們需要給span加上這個偏移量,限制它的左側範圍。

我們在大圖的div中設定了overflow:hidden屬性,因此可以通過控制大圖的移動來控制顯示範圍

}
        else {
            //當移動到最右端的時候,停止span的移動,大圖也移動到相應的最右端,此時可以通過一個n來控制大圖的移動了
            pic_move.style.left = -n * (normal_pic.offsetWidth - span_move.offsetWidth) + 'px';
            span_move.style.left = normal_pic.offsetLeft + normal_pic.offsetWidth - span_move.offsetWidth + 'px';
        }

n是大圖和小圖的倍數,normal_pic.offsetWidth - span_move.offsetWidth是小圖移動的距離

上下移動的控制

雖然圖片的高度都是400px,上下邊界可以用100和300來限制,但為了普適一些,把100和300轉化成了相應的求值程式碼

if (mouse_y <= span_move.offsetWidth / 2) {
        pic_move.style.top = '0px';
        span_move.style.top = '0px';
    } else if (mouse_y > span_move.offsetHeight / 2 && mouse_y < normal_pic.offsetHeight - span_move.offsetHeight /2) {
        var tempY = mouse_y - span_move.offsetHeight / 2;
        pic_move.style.top = - n * tempY + 'px';
        span_move.style.top = tempY + 'px';
    } else {
        pic_move.style.top = -(n - 1) * normal_pic.offsetHeight + 'px';
        span_move.style.top = normal_pic.offsetHeight - span_move.offsetHeight + 'px';
    }


}


pic_div.onmouseout = function () {
    span_move.style.display = 'none';
    big_div.style.display = 'none';
}

以上就是整個js程式碼以及程式設計的思路