圖片放大鏡效果實現過程詳解

ufoe7070 7年前發布 | 15K 次閱讀 CSS 前端技術 JavaScript

效果如圖(例子中偷偷鏈了張天貓的圖片,希望沒啥事 -。-):

實現過程教簡單,但我們還是從css開始分析,過程如下(圖片已正方形為例):

css:

/* 圖片容器 */
    .imgBox{
      width: 200px; /* 各位大老爺們看著辦 */
      height: 200px; /* 各位大老爺們看著辦 */
      position: relative; /* 必需 */
    }
 
    /* 圖片標簽 */
    .mainImg{
      width: 100%; /* 各位大老爺們看著辦,盡量100%好看些[斜眼笑] */
      height: 100%; /* 各位大老爺們看著辦,盡量100%好看些[斜眼笑] */
    }
 
    /* 遮罩層-既放大區域 */
    .glass{
      position: absolute; /* 必需 */
      width: 50px; /* 遮罩層寬度 此處是放大4倍,所以為200/4=50 */
      height: 50px; /* 遮罩層高度 此處是放大4倍,所以為200/4=50  */
      top: -9999px; /* 絕對位置,先放遠些 */
      left: -9999px; /* 絕對位置,先放遠些 */
      cursor: move; /* 鼠標樣式,好看些 */
      background: rgba(0,0,180,0.5); /* 遮罩層樣式,好看些 */
    }
 
    /* 大圖所在的容器 */
    .imgMax{
      position: absolute;  /* 必需 */
      overflow: hidden; /* 必需,蓋掉超出的大圖[斜眼笑] */
      left: 210px; /* 必需,此處為距原圖左邊10像素 */
      top: 0; /* 必需,此處為距上邊0像素 */
      width: 200px; /* 放大圖片容器的寬度 此處此處是放大4倍,為200,保持和原圖容器一般大,若此處為400,則是放大2*4倍,那么相應的放大圖片應該是200*4*2=1600 */
      height: 200px; /* 放大圖片容器的高度 此處此處是放大4倍,為200,保持和原圖容器一般大,若此處為400,則是放大2*4倍,那么相應的放大圖片應該是200*4*2=1600 */
      display: none; /* 先隱藏 */
    }
    .maxImg{
      position: absolute; /* 必需 */
      width: 800px; /* 此處是放大4倍,所以為200*4=800  受放大圖片所在的容器影響,規則如上 */
      height: 800px; /* 此處是放大4倍,所以為200*4=800  受放大圖片所在的容器影響,規則如上 */
    }

上面css中需要注意的就是幾個position和縮放比例,注意調整下即可

寫完樣式,來看看布局:

html:

<!-- 圖片容器 -->
    <divclass="J_imgBox imgBox">
      <!-- 需要放大的圖片-原始圖 -->
      <imgclass="J_mainImg mainImg" src="https://simg.open-open.com/show/02e5aad0cd1342da624fe2287bd3f8b5.jpg"/>
      <!-- 遮罩-既放大的區域 -->
      <divclass="J_glass glass"></div>
      <!-- 大圖的容器 -->
      <divclass="J_imgMax imgMax">
        <!-- 大圖 -->
        <imgclass="J_maxImg maxImg"/>
      </div>
    </div>

接下來是主要的js代碼,一如既往的帶注解:

js:

(function(){
    /* 放大鏡函數
    ** @imgContainer  需要實現放大鏡效果的圖片容器  此處是 class 為 J_imgBox 的 div
    */
    function imgZoom(imgContainer){
 
      // 取大圖url,不知道淘寶圖片規則如何,反正看了詳情頁的大圖和小圖url對比,隨便寫了個替換
      var imgUrl = imgContainer.querySelector('.J_mainImg').src.replace(/.(jpg|jpeg|png|gif)(_)(d+)(x)(d+)(q90)?/g,'');
 
      // 取大圖標簽的節點
      var maxImg = imgContainer.querySelector('.J_maxImg');
 
      // 給該節點的src屬性賦值為大圖的url
      maxImg.src = imgUrl;
 
      // 取大圖所在的容器
      var maxImgContainer = imgContainer.querySelector('.J_imgMax');
 
      // 取遮罩塊
      var glassBlock = imgContainer.querySelector('.J_glass');
 
      // 取消放大鏡效果
      var hideMaxImg = function(){
        glassBlock.style.top = '-9999px';
        glassBlock.style.left = '-9999px';
        maxImgContainer.style.display = 'none';
      }
 
      // 鼠標移出圖片區域,取消放大鏡效果
      imgContainer.onmouseout = function(event){
        event.stopPropagation();
        hideMaxImg();
      };
 
      // 鼠標在圖片區域內移動事件
      imgContainer.onmousemove = function(event) {
        event.stopPropagation();
 
        // 取圖片容器的大小及其相對于視口的位置,需要實時取,所以放在move事件里
        var clientRect = event.currentTarget.getBoundingClientRect();
 
        // 獲取距鼠標距的上和左的坐標
        var leftX = event.clientX - clientRect.left;
        var leftY = event.clientY - clientRect.top;
 
        // 動態設置遮罩塊的left和top位置  這里需要減去遮罩層的一半,因為鼠標位于遮罩塊中心點
        var pointerLeft = leftX - 25;
        var pointerTop = leftY - 25;
 
        // 如果鼠標坐標移動超出原始圖片區域邊緣 則取消放大鏡效果  因為這里存在快速移動鼠標到大圖區域時,鼠標仍處在外層的圖片區域內,并不會觸發mouseout事件(雖然中間隔了小小的間距,但是快速移動仍能產生這個bug,如代碼下面的圖所示)
        if((pointerLeft+25) > clientRect.width || pointerLeft  clientRect.height || pointerTop ){
          hideMaxImg();
          return !1;
        };
 
        // 遮罩塊在最左邊的時候,鼠標仍在圖片區域內,可在遮罩塊左邊緣至中心線區域內移動,且這時遮罩塊為距左0像素
        if(pointerLeft ){
          pointerLeft = 0;
        };
 
        // 同上 右邊限制
        if(pointerLeft > clientRect.width - 50){
          pointerLeft = clientRect.width - 50;
        };
 
        // 同上 頂部限制
        if(pointerTop ){
          pointerTop = 0;
        };
 
        // 同上 底部限制
        if(pointerTop > clientRect.height - 50){
          pointerTop = clientRect.height - 50;
        };
 
        // 設置遮罩塊的位置
        glassBlock.style.left = pointerLeft;
        glassBlock.style.top = pointerTop;
 
        // 取遮罩快距離左邊的位置和圖片區域的寬高比,用于計算大圖偏移距離,展示遮罩塊所對應的圖片區域
        var percentLeft = pointerLeft/clientRect.width;
        var percentHeight = pointerTop/clientRect.height;
 
        // 設置大圖偏移距離 因為其父元素存在 overflow:hidden 所以只會展示對應區塊
        maxImg.style.left = -(percentLeft*maxImg.clientWidth)+'px';
        maxImg.style.top = -(percentHeight*maxImg.clientHeight)+'px';
      };
    }
 
    var elem = document.querySelectorAll('.J_imgBox');
 
    elem.forEach(function(item,idx){
      imgZoom(item)
    })
  })()

補bug圖:

看完后是不是覺得簡直不要太簡單,接下來就來理一理以上代碼中能夠抽取出來在平常開發中比較實用的知識點:

Element.getBoundingClientRect()

Element.getBoundingClientRect()方法返回元素的大小及其相對于視口的位置

例子:

<bodystyle="width:1400;height:1000">
      <divid="testDiv" style="width:10px;height:20px;background:#f00"></div>
      <script>
        (function(){
          var elem = document.getElementById('testDiv');
          document.body.addEventListener('click',function(){
              console.log(elem.getBoundingClientRect())
          },false)
        })()
      </script>
    </body>

效果如圖:

從效果圖上不難看出,當我移動視圖后再點擊body,打印的對象都能夠正確返回元素的大小及其相對于視口的位置

這個方法也可以用于實現當某元素滾動到底/頂部時觸發對應事件,相當方便。

Event

1.event.target 和 event.currentTarget

target:指向觸發事件的元素

currentTarget:指向被綁定事件句柄的元素

只有當綁定的事件處理程序與觸發該事件處理程序都為同一個對象的時候,兩者相同

例子代碼:

html:

  <divid="aDiv">
      123
      <divid="bDiv">456</div>
    </div>

js:

  document.getElementById('aDiv').addEventListener('click',function(e){
    if(e.target === e.currentTarget) {
      console.log('target === currentTarget')
    }else{
      console.log('target !== currentTarget')
    }
    console.log('target',e.target)
    console.log('currentTarget',e.currentTarget)
  },false)

效果圖:

從效果圖中,我們可以看到,當點擊456時,target指向的是456所在的bDiv,currentTarget則指向aDiv,因為事件是綁定在aDiv上,但觸發是在bDiv上,而且bDiv又在aDiv內,當點擊123時,則target與currentTarget一致,綁定和觸發都在aDiv上。

2.event.preventDefault() & event.stopPropagation()

preventDefault:如果事件可取消,則取消該事件,而不停止事件的進一步傳播

stopPropagation:阻止捕獲和冒泡階段中當前事件的進一步傳播

3.event.stopPropagation() & event.stopImmediatePropagation()

stopPropagation:阻止捕獲和冒泡階段中當前事件的進一步傳播

stopImmediatePropagation:阻止元素上調用相同事件的其他事件監聽并阻止冒泡

兩者區別的例子:

html:

  <divid="aDiv">
      123
      <divid="bDiv">456</div>
    </div>

js:

  document.getElementById('aDiv').addEventListener('click',function(){
    console.log('click aDiv')
  },false)
  document.getElementById('bDiv').addEventListener('click',function(e){
    e.stopImmediatePropagation();
    console.log('click bDiv')
  },false)
  document.getElementById('bDiv').addEventListener('click',function(){
    console.log('click me too')
  },false)

上面代碼執行結果為:

clickbDiv

注釋掉 e.stopImmediatePropagation(); 的結果為:

clickbDiv
clickmetoo
clickaDIV

雖然都是些簡單的知識點,在平常開發中也是很實用的,希望能從細節出發,沒事多復習復習 -。-~

 

 

來自:http://web.jobbole.com/90929/

 

 本文由用戶 ufoe7070 自行上傳分享,僅供網友學習交流。所有權歸原作者,若您的權利被侵害,請聯系管理員。
 轉載本站原創文章,請注明出處,并保留原始鏈接、圖片水印。
 本站是一個以用戶分享為主的開源技術平臺,歡迎各類分享!