由專案需要,原生寫了個詳情頁圖片放大鏡的效果,扔上程式碼供學習分享,也作為日常筆記…
效果如圖(例子中偷偷鏈了張天貓的圖片,希望沒啥事 -。-):
實現過程教簡單,但我們還是從css開始分析,過程如下(圖片已正方形為例):
css:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 |
/* 圖片容器 */ .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:
1 2 3 4 5 6 7 8 9 10 11 12 |
<!-- 圖片容器 --> <div class="J_imgBox imgBox"> <!-- 需要放大的圖片-原始圖 --> <img class="J_mainImg mainImg" src="http://img.alicdn.com/bao/uploaded/i7/TB1Xpe_NXXXXXXRXFXXGTq09XXX_035318.jpg_430x430q90.jpg" /> <!-- 遮罩-既放大的區域 --> <div class="J_glass glass"></div> <!-- 大圖的容器 --> <div class="J_imgMax imgMax"> <!-- 大圖 --> <img class="J_maxImg maxImg" /> </div> </div> |
接下來是主要的js程式碼,一如既往的帶註解:
js:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 |
(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()方法返回元素的大小及其相對於視口的位置
例子:
1 2 3 4 5 6 7 8 9 10 11 |
<body style="width:1400;height:1000"> <div id="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:
1 2 3 4 |
<div id="aDiv"> 123 <div id="bDiv">456</div> </div> |
js:
1 2 3 4 5 6 7 8 9 |
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:
1 2 3 4 |
<div id="aDiv"> 123 <div id="bDiv">456</div> </div> |
js:
1 2 3 4 5 6 7 8 9 10 |
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) |
上面程式碼執行結果為:
1 |
click bDiv |
註釋掉 e.stopImmediatePropagation(); 的結果為:
1 2 3 |
click bDiv click me too click aDIV |
雖然都是些簡單的知識點,在平常開發中也是很實用的,希望能從細節出發,沒事多複習複習 -。-~
後來一時興起將放大鏡寫的更傻瓜式配置的外掛了… 點我看程式碼(github地址)