js圖片放大鏡效果實(shí)現(xiàn)方法詳解
由項(xiàng)目需要,原生寫(xiě)了個(gè)詳情頁(yè)圖片放大鏡的效果,扔上代碼供學(xué)習(xí)分享,也作為日常筆記...
效果如圖(例子中偷偷鏈了張?zhí)熵埖膱D片,希望沒(méi)啥事 -。-):
實(shí)現(xiàn)過(guò)程教簡(jiǎn)單,但我們還是從css開(kāi)始分析,過(guò)程如下(圖片已正方形為例):
上面css中需要注意的就是幾個(gè)position和縮放比例,注意調(diào)整下即可
寫(xiě)完樣式,來(lái)看看布局:
html:
<!-- 圖片容器 --> <div class="J_imgBox imgBox"> <!-- 需要放大的圖片-原始圖 --> <img class="J_mainImg mainImg" src="http://img.alicdn.com/bao/uploaded/i7/TB1Xpe_NXXXXXXRXFXXGTq09XXX_035318.jpg_430x430q90.jpg" /> <!-- 遮罩-既放大的區(qū)域 --> <div class="J_glass glass"></div> <!-- 大圖的容器 --> <div class="J_imgMax imgMax"> <!-- 大圖 --> <img class="J_maxImg maxImg" /> </div> </div>
接下來(lái)是主要的js代碼,一如既往的帶注解:
js:
(function(){ /* 放大鏡函數(shù) ** @imgContainer 需要實(shí)現(xiàn)放大鏡效果的圖片容器 此處是 class 為 J_imgBox 的 div */ function imgZoom(imgContainer){ // 取大圖url,不知道淘寶圖片規(guī)則如何,反正看了詳情頁(yè)的大圖和小圖url對(duì)比,隨便寫(xiě)了個(gè)替換 var imgUrl = imgContainer.querySelector('.J_mainImg').src.replace(/\.(jpg|jpeg|png|gif)(_)(\d+)(x)(\d+)(q90)?/g,''); // 取大圖標(biāo)簽的節(jié)點(diǎn) var maxImg = imgContainer.querySelector('.J_maxImg'); // 給該節(jié)點(diǎn)的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'; } // 鼠標(biāo)移出圖片區(qū)域,取消放大鏡效果 imgContainer.onmouseout = function(event){ event.stopPropagation(); hideMaxImg(); }; // 鼠標(biāo)在圖片區(qū)域內(nèi)移動(dòng)事件 imgContainer.onmousemove = function(event) { event.stopPropagation(); // 取圖片容器的大小及其相對(duì)于視口的位置,需要實(shí)時(shí)取,所以放在move事件里 var clientRect = event.currentTarget.getBoundingClientRect(); // 獲取距鼠標(biāo)距的上和左的坐標(biāo) var leftX = event.clientX - clientRect.left; var leftY = event.clientY - clientRect.top; // 動(dòng)態(tài)設(shè)置遮罩塊的left和top位置 這里需要減去遮罩層的一半,因?yàn)槭髽?biāo)位于遮罩塊中心點(diǎn) var pointerLeft = leftX - 25; var pointerTop = leftY - 25; // 如果鼠標(biāo)坐標(biāo)移動(dòng)超出原始圖片區(qū)域邊緣 則取消放大鏡效果 因?yàn)檫@里存在快速移動(dòng)鼠標(biāo)到大圖區(qū)域時(shí),鼠標(biāo)仍處在外層的圖片區(qū)域內(nèi),并不會(huì)觸發(fā)mouseout事件(雖然中間隔了小小的間距,但是快速移動(dòng)仍能產(chǎn)生這個(gè)bug,如代碼下面的圖所示) if((pointerLeft+25) > clientRect.width || pointerLeft < 0 - 25 || (pointerTop+25) > clientRect.height || pointerTop < 0 - 25){ hideMaxImg(); return !1; }; // 遮罩塊在最左邊的時(shí)候,鼠標(biāo)仍在圖片區(qū)域內(nèi),可在遮罩塊左邊緣至中心線區(qū)域內(nèi)移動(dòng),且這時(shí)遮罩塊為距左0像素 if(pointerLeft < 0){ pointerLeft = 0; }; // 同上 右邊限制 if(pointerLeft > clientRect.width - 50){ pointerLeft = clientRect.width - 50; }; // 同上 頂部限制 if(pointerTop < 0){ pointerTop = 0; }; // 同上 底部限制 if(pointerTop > clientRect.height - 50){ pointerTop = clientRect.height - 50; }; // 設(shè)置遮罩塊的位置 glassBlock.style.left = pointerLeft; glassBlock.style.top = pointerTop; // 取遮罩快距離左邊的位置和圖片區(qū)域的寬高比,用于計(jì)算大圖偏移距離,展示遮罩塊所對(duì)應(yīng)的圖片區(qū)域 var percentLeft = pointerLeft/clientRect.width; var percentHeight = pointerTop/clientRect.height; // 設(shè)置大圖偏移距離 因?yàn)槠涓冈卮嬖?overflow:hidden 所以只會(huì)展示對(duì)應(yīng)區(qū)塊 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) }) })()
補(bǔ)bug圖:
看完后是不是覺(jué)得簡(jiǎn)直不要太簡(jiǎn)單,接下來(lái)就來(lái)理一理以上代碼中能夠抽取出來(lái)在平常開(kāi)發(fā)中比較實(shí)用的知識(shí)點(diǎn):
Element.getBoundingClientRect()
Element.getBoundingClientRect()方法返回元素的大小及其相對(duì)于視口的位置
例子:
<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>
效果如圖:
從效果圖上不難看出,當(dāng)我移動(dòng)視圖后再點(diǎn)擊body,打印的對(duì)象都能夠正確返回元素的大小及其相對(duì)于視口的位置
這個(gè)方法也可以用于實(shí)現(xiàn)當(dāng)某元素滾動(dòng)到底/頂部時(shí)觸發(fā)對(duì)應(yīng)事件,相當(dāng)方便。
Event
1.event.target 和 event.currentTarget
target:指向觸發(fā)事件的元素
currentTarget:指向被綁定事件句柄的元素
只有當(dāng)綁定的事件處理程序與觸發(fā)該事件處理程序都為同一個(gè)對(duì)象的時(shí)候,兩者相同
例子代碼:
html:
<div id="aDiv"> 123 <div id="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)
效果圖:
從效果圖中,我們可以看到,當(dāng)點(diǎn)擊456時(shí),target指向的是456所在的bDiv,currentTarget則指向aDiv,因?yàn)槭录墙壎ㄔ赼Div上,但觸發(fā)是在bDiv上,而且bDiv又在aDiv內(nèi),當(dāng)點(diǎn)擊123時(shí),則target與currentTarget一致,綁定和觸發(fā)都在aDiv上。
2.event.preventDefault() & event.stopPropagation()
preventDefault:如果事件可取消,則取消該事件,而不停止事件的進(jìn)一步傳播
stopPropagation:阻止捕獲和冒泡階段中當(dāng)前事件的進(jìn)一步傳播
3.event.stopPropagation() & event.stopImmediatePropagation()
stopPropagation:阻止捕獲和冒泡階段中當(dāng)前事件的進(jìn)一步傳播
stopImmediatePropagation:阻止元素上調(diào)用相同事件的其他事件并阻止冒泡
兩者區(qū)別的例子:
html:
<div id="aDiv"> 123 <div id="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)
上面代碼執(zhí)行結(jié)果為:
click bDiv
注釋掉 e.stopImmediatePropagation(); 的結(jié)果為:
click bDiv
click me too
click aDIV
雖然都是些簡(jiǎn)單的知識(shí)點(diǎn),在平常開(kāi)發(fā)中也是很實(shí)用的,希望能從細(xì)節(jié)出發(fā),沒(méi)事多復(fù)習(xí)復(fù)習(xí) -。-~
后來(lái)一時(shí)興起將放大鏡寫(xiě)的更傻瓜式配置的插件了... 點(diǎn)我看代碼(github地址)
以上就是本文的全部?jī)?nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
相關(guān)文章
JavaScript 用cloneNode方法克隆節(jié)點(diǎn)的代碼
很多時(shí)候我們需要通過(guò)HTML DOM 的方式,用JavaScript 動(dòng)態(tài)生成很多相同的節(jié)點(diǎn),包括其子節(jié)點(diǎn)2012-10-10無(wú)限循環(huán)輪播圖之運(yùn)動(dòng)框架(原生JS實(shí)現(xiàn))
下面小編就為大家?guī)?lái)一篇無(wú)限循環(huán)輪播圖之運(yùn)動(dòng)框架(原生JS實(shí)現(xiàn))。小編覺(jué)得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2017-10-10詳解JavaScript調(diào)用棧、尾遞歸和手動(dòng)優(yōu)化
本篇文章主要介紹了詳解JavaScript調(diào)用棧、尾遞歸和手動(dòng)優(yōu)化,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2017-06-06VScode中配置JavaScript編譯環(huán)境的方法
這篇文章主要介紹了VSCODE中配置JavaScript編譯環(huán)境的方法,方式一 使用Node.js做為解釋器運(yùn)行JS代碼 Node.js的安裝和配置,方式二使用VSCODE插件Code Runner運(yùn)行JS代碼,本文給大家介紹的非常詳細(xì),需要的朋友可以參考下2022-08-08微信小程序wxss如何引用外部CSS文件以及iconfont
這篇文章主要給大家介紹了關(guān)于微信小程序wxss如何引用外部CSS文件以及iconfont的相關(guān)資料,文中通過(guò)圖文介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2021-03-03js中int和string數(shù)據(jù)類(lèi)型互相轉(zhuǎn)化實(shí)例
在本篇文章里小編給大家分享了關(guān)于js中int和string數(shù)據(jù)類(lèi)型互相轉(zhuǎn)化實(shí)例和代碼,需要的朋友們學(xué)習(xí)下。2019-01-01Javascript獲取HTML靜態(tài)頁(yè)面參數(shù)傳遞值示例
獲取HTML靜態(tài)頁(yè)面參數(shù)傳遞值可以利用split函數(shù)來(lái)按參數(shù)切成數(shù)組、利用正則表達(dá)式來(lái)獲取,具體實(shí)現(xiàn)如下,感興趣的朋友可以參考下2013-08-08js原生跨域_用script標(biāo)簽的簡(jiǎn)單實(shí)現(xiàn)
下面小編就為大家?guī)?lái)一篇js原生跨域_用script標(biāo)簽的簡(jiǎn)單實(shí)現(xiàn)。小編覺(jué)得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2016-09-09