當前位置: 華文世界 > 手機

功能問題:如何實作圖片放大鏡功能?

2024-01-17手機

大家好,我是大澈!

本文 約 2900+ 字 ,整篇閱讀大約需要 4 分鐘。

感謝關註微信公眾號:「程式設計師大澈」,免費領取" 面試禮包 "一份,然後免費加入 問答群 ,從此讓解決問題的你不再孤單!

1. 需求分析

平常我們一般都是在手機淘寶上購物,不知道大家有沒有體驗過PC端淘寶,裏面有很多好玩的設計。

比如我們今天要實作的功能:圖片放大鏡,這是一個在電商網站套用非常廣的設計。

滑鼠移入 左側縮圖 時, 小盒子 和 右邊大圖 顯示,並且小盒子跟隨滑鼠移動,右側大圖出現放大效果。

再梳理一下,圖片放大鏡功能設計有如下幾個 優點 :

  • 提供更好的使用者體驗 :透過放大鏡功能,使用者可以在不離開當前頁面或進一步導航的情況下,更詳細地檢視影像的細節。
  • 提供互動性 :放大鏡功能增加了使用者與影像的互動性。透過滑鼠懸停或輕觸式熒幕幕,使用者可以控制放大鏡的位置,並即時檢視所選區域的放大效果。
  • 增強響應式設計 :無論使用者使用大螢幕器材還是小螢幕器材,他們都能夠在需要時放大影像,輕松檢視細節。
  • 圖片放大鏡功能的實際套用場景有很多,如電子商務、藝術設計展示、圖片庫等。

    要實作圖片放大鏡功能,一般有兩種方式:一種是 利用原生JS動態設定偏移量,一種是 利用原生JS的Canvas動態截取。

    當然,實作方式一定不僅僅只有這幾種,還有很多可以嘗試的其它辦法,這裏期待朋友們補充指教吧!

    下面我們一起來看看,上述兩種原生JS的具體實作。

    2. 功能實作

    先簡單聊聊這兩種原生JS方式的實作原理,再附上可直接使用的源碼,最後置身於真實專案中,對圖片放大鏡功能的實作做一下小結。

    2.1 方式一 動態設定偏移量

    此方式中,左側縮圖和右側大圖插入的是同一個圖片,不過原圖視窗的圖片要適當縮小,放大視窗圖片保持原大小,超出部份設定隱藏。

    先實作小盒子跟著滑鼠移動的功能,且小盒子不能移出邊界。

    再實作右側大圖隨著小盒子的移動實作自身移動,且兩者移動方向總是相反的。

    <!DOCTYPE html><html lang="en"><head><meta charset="UTF-8"><title>放大鏡</title>< style>*{margin: 0;padding: 0;}.container{width: 400px;height: 250px;position: relative;left: 250px;top: 150px;}.bigBox{width: 500px;height: 500px;border-radius: 50%;position: absolute;left: 430px;border: 1px solid #ccc;overflow: hidden;display: none;}.smallBox{position: absolute;border: 1px solid #ccc;font-size: 0;}.mask{width: 100px;height: 100px;cursor: move;position: absolute;top: 0;left: 0;background-color: rgba(255,255,0,0.4);display: none;}#bigPic{position: absolute;}</ style></head><body><div class="container" id="box"><!-- 左側縮圖 --><div class="smallBox"><img src="./01.png" alt="" width="400px"><!-- 小盒子 --><div class="mask"></div></div><!-- 右側大圖 --><div class="bigBox"><img src="./01.png" alt="" id="bigPic"></div></div></body><script>window.onload = function(){var smallBox = document.getElementsBy className('smallBox')[0];var bigBox = document.getElementsBy className('bigBox')[0];var mask = document.getElementsBy className('mask')[0];var box = document.getElementById('box');var bigPic = document.getElementById('bigPic');smallBox.onmouseover = function(){bigBox. style.display = "block";mask. style.display = "block";}smallBox.onmouseout = function(){bigBox. style.display = "none";mask. style.display = "none";}smallBox.onmousemove = function(event){//pageX,pageY//處理相容性和捲軸var event = event || window.event;var scrollLeft = document.body.scrollLeft || document.documentElement.scrollLeft;var scrollTop = document.body.scrollTop || document.documentElement.scrollTop;var pageX = event.pageX || event.clientX + scollLeft;var pageY = event.pageY || event.clientY + scollTop;var targetX = pageX - box.offsetLeft - mask.offsetWidth/2;var targetY = pageY - box.offsetTop - mask.offsetHeight/2;//左邊界if(targetX<0){targetX = 0;}//上邊界if(targetY<0){targetY = 0;}//右邊界if(targetX>smallBox.offsetWidth - mask.offsetWidth){targetX = smallBox.offsetWidth - mask.offsetWidth}//下邊界if(targetY>smallBox.offsetHeight - mask.offsetHeight){targetY = smallBox.offsetHeight - mask.offsetHeight}//設定小盒子的左偏移和上偏移mask. style.left = targetX + 'px';mask. style.top = targetY + 'px';var smallMoveX = smallBox.offsetWidth - mask.offsetWidth;var bigMoveX = bigPic.offsetWidth - bigBox.offsetWidth;var smallMoveY = smallBox.offsetHeight - mask.offsetHeight;var bigMoveY = bigPic.offsetHeight - bigBox.offsetHeight;//設定右邊放大部份跟隨滑鼠移動var rateX = bigMoveX/smallMoveX; var rateY = bigMoveY/smallMoveY;bigPic. style.left = -rateX*targetX+'px';bigPic. style.top = -rateY*targetY+'px'; }}</script></html>

    2.2 方式二 Canvas動態截取

    此方式中,頁面上總共放三塊畫布。一塊放左側縮圖,一塊放小盒子,一塊放右側大圖。

    先實作小盒子跟隨滑鼠在左側縮圖上移動。

    再把小盒子內的圖片截取出來,按比例放到右側大圖的畫布上,從而實作放大效果。

    <!DOCTYPE html><html lang="en"><head><meta charset="UTF-8"><title>放大鏡</title>< style>*{margin: 0;padding: 0;}.container{width: 300px;height: 300px;border: 1px solid #ccc;position: relative;}canvas{border: 1px solid #ccc;}#big-canvas{position: absolute;left: 320px;top: 100px;display: none;}#small-canvas{position: absolute;opacity: 0.5;left: 0;top: 0;display: none;}</ style></head><body><div class="container"><!-- 左側縮圖 --><canvas id="canvas" width="300px" height="300px"></canvas><!-- 右側大圖 --><canvas id="big-canvas" width="500px" height="500px"></canvas><!-- 小盒子 --><canvas id="small-canvas" width="80px" height="80px"></canvas></div></body><script>window.onload = function(){var container = document.getElementsBy className('container')[0];var canvas = document.getElementById('canvas');var context = canvas.getContext('2d');var bigCanvas = document.getElementById('big-canvas');var bigContext = bigCanvas.getContext('2d');var smallCanvas = document.getElementById('small-canvas');var smallContext = smallCanvas.getContext('2d');//左側縮圖var img = new Image();img.src = './01.png';img.onload = function(){context.drawImage(img,0,0,300,300);}//小盒子var imgbd = new Image();imgbd.src = '';imgbd.onload = function(){smallContext.drawImage(imgbd,0,0,80,80);}container.onmousemove = function(event){//滑鼠移進小盒子和右側大圖都顯示bigCanvas. style.display = 'block';smallCanvas. style.display = 'block';// x是開始裁剪圖片的位置的橫座標 y是開始裁剪圖片的位置的縱座標var x = event.pageX - container.offsetLeft - smallCanvas.offsetWidth/2;var y = event.pageY - container.offsetTop - smallCanvas.offsetHeight/2;//判斷邊界if (x<0) {x = 0;}if (x> canvas.offsetWidth - smallCanvas.offsetWidth) {x = canvas.offsetWidth - smallCanvas.offsetWidth;}if (y<0) {y = 0;}if (y> canvas.offsetHeight - smallCanvas.offsetHeight) {y = canvas.offsetHeight - smallCanvas.offsetHeight;}// 設定小盒子的位置smallCanvas. style.left = x + 'px';smallCanvas. style.top = y + 'px';// 參數:影像物件,開始剪下的 x 座標位置,開始剪下的 y座標位置,被剪下影像的寬度,被剪下影像的高度,繪制位置的起始x座標,起始y座標,繪制影像的寬,高bigContext.drawImage(canvas,x,y,80,80,0,0,500,500);}//滑鼠移出小盒子和右側大圖都隱藏container.onmouseleave = function(){bigCanvas. style.display = 'none';smallCanvas. style.display = 'none';}}</script></html>

    2.3 小結

    對於圖片放大鏡功能的實作,上述兩種原生JS方式其實都不算復雜。

    我們只需要在使用時,細細梳理一遍程式碼,再修改一些必要參數即可,不需要鉆牛角尖過分糾結。

    在真實專案中,我們更應該有如下考慮:

    對於Vue2專案,可直接使用 vue2.0-zoom 庫。

    對於Vue3專案,可直接使用 zoomer-vue3 庫。

    如需高度自訂時,可使用上述兩種 原生JS方式 擇其一來手寫。

    結語

    建立這個平台的初衷:

  • 打造一個專註於 前端功能問題的 問答平台,讓大家高效搜尋處理同樣問題。
  • 遇到有共鳴的問題,與眾多同行朋友們一起討論,一起沈澱成長。
  • 平台現 擁有功能問題、技術資訊、實用幹貨3個專欄內容。
  • 感謝關註微信公眾號:「程式設計師大澈」,免費領取" 面試禮包 "一份,然後免費加入 問答群 ,從此讓解決問題的你不再孤單!