JavaScript圖片放大效果詳解

來源:互聯網
上載者:User

效果:

運行代碼框
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"><br /><html xmlns="http://www.w3.org/1999/xhtml"><br /><head><br /><meta http-equiv="Content-Type" content="text/html; charset=utf-8" /><br /><title>Magnifier</title><br /><style type="text/css"><br />#magnifier{<br /> width:342px;<br /> height:420px;<br /> position:absolute;<br /> top:100px;<br /> left:250px;<br /> font-size:0;<br /> border:1px solid #000;<br />}<br />#img{<br /> width:342px;<br /> height:420px;<br />}<br />#Browser{<br /> border:1px solid #000;<br /> z-index:100;<br /> position:absolute;<br /> background:#555;<br />}<br />#mag{<br /> border:1px solid #000;<br /> overflow:hidden;<br /> z-index:100;<br />}<br /></style><br /><script type="text/javascript"><br />function getEventObject(W3CEvent) { //事件標準化函數<br /> return W3CEvent || window.event;<br />}<br />function getPointerPosition(e) { //相容瀏覽器的滑鼠x,y獲得函數<br /> e = e || getEventObject(e);<br /> var x = e.pageX || (e.clientX + (document.documentElement.scrollLeft || document.body.scrollLeft));<br /> var y = e.pageY || (e.clientY + (document.documentElement.scrollTop || document.body.scrollTop));</p><p> return { 'x':x,'y':y };<br />}<br />function setOpacity(elem,level) { //相容瀏覽器設定透明值<br /> if(elem.filters) {<br /> elem.style.filter = 'alpha(opacity=' + level * 100 + ')';<br /> } else {<br /> elem.style.opacity = level;<br /> }<br />}<br />function css(elem,prop) { //css設定函數,可以方便設定css值,並且相容設定透明值<br /> for(var i in prop) {<br /> if(i == 'opacity') {<br /> setOpacity(elem,prop[i]);<br /> } else {<br /> elem.style[i] = prop[i];<br /> }<br /> }<br /> return elem;<br />}<br />var magnifier = {<br /> m : null,</p><p> init:function(magni){<br /> var m = this.m = magni || {<br /> cont : null, //裝載原始映像的div<br /> img : null, //放大的映像<br /> mag : null, //放大框<br /> scale : 15 //比例值,設定的值越大放大越大,但是這裡有個問題就是如果不可以整除時,會產生些很小的白邊,目前不知道如何解決<br /> }</p><p> css(m.img,{<br /> 'position' : 'absolute',<br /> 'width' : (m.cont.clientWidth * m.scale) + 'px', //原始映像的寬*比例值<br /> 'height' : (m.cont.clientHeight * m.scale) + 'px' //原始映像的高*比例值<br /> })</p><p> css(m.mag,{<br /> 'display' : 'none',<br /> 'width' : m.cont.clientWidth + 'px', //m.cont為原始映像,與原始映像等寬<br /> 'height' : m.cont.clientHeight + 'px',<br /> 'position' : 'absolute',<br /> 'left' : m.cont.offsetLeft + m.cont.offsetWidth + 10 + 'px', //放大框的位置為原始映像的右方遠10px<br /> 'top' : m.cont.offsetTop + 'px'<br /> })</p><p> var borderWid = m.cont.getElementsByTagName('div')[0].offsetWidth - m.cont.getElementsByTagName('div')[0].clientWidth; //擷取border的寬</p><p> css(m.cont.getElementsByTagName('div')[0],{ //m.cont.getElementsByTagName('div')[0]為瀏覽框<br /> 'display' : 'none', //開始設定為不可見<br /> 'width' : m.cont.clientWidth / m.scale - borderWid + 'px', //原始圖片的寬/比例值 - border的寬度<br /> 'height' : m.cont.clientHeight / m.scale - borderWid + 'px', //原始圖片的高/比例值 - border的寬度<br /> 'opacity' : 0.5 //設定透明度<br /> })</p><p> m.img.src = m.cont.getElementsByTagName('img')[0].src; //讓原始映像的src值給予放大映像<br /> m.cont.style.cursor = 'crosshair';</p><p> m.cont.onmouseover = magnifier.start;</p><p> },</p><p> start:function(e){</p><p> if(document.all){ //只在IE下執行,主要避免IE6的select無法覆蓋<br /> magnifier.createIframe(magnifier.m.img);<br /> }</p><p> this.onmousemove = magnifier.move; //this指向m.cont<br /> this.onmouseout = magnifier.end;<br /> },</p><p> move:function(e){<br /> var pos = getPointerPosition(e); //事件標準化</p><p> this.getElementsByTagName('div')[0].style.display = '';</p><p> css(this.getElementsByTagName('div')[0],{<br /> 'top' : Math.min(Math.max(pos.y - this.offsetTop - parseInt(this.getElementsByTagName('div')[0].style.height) / 2,0),this.clientHeight - this.getElementsByTagName('div')[0].offsetHeight) + 'px',<br /> 'left' : Math.min(Math.max(pos.x - this.offsetLeft - parseInt(this.getElementsByTagName('div')[0].style.width) / 2,0),this.clientWidth - this.getElementsByTagName('div')[0].offsetWidth) + 'px' //left=滑鼠x - this.offsetLeft - 瀏覽框寬/2,Math.max和Math.min讓瀏覽框不會超出映像<br /> })</p><p> magnifier.m.mag.style.display = '';</p><p> css(magnifier.m.img,{<br /> 'top' : - (parseInt(this.getElementsByTagName('div')[0].style.top) * magnifier.m.scale) + 'px',<br /> 'left' : - (parseInt(this.getElementsByTagName('div')[0].style.left) * magnifier.m.scale) + 'px'<br /> })</p><p> },</p><p> end:function(e){<br /> this.getElementsByTagName('div')[0].style.display = 'none';<br /> magnifier.removeIframe(magnifier.m.img); //銷毀iframe</p><p> magnifier.m.mag.style.display = 'none';<br /> },</p><p> createIframe:function(elem){<br /> var layer = document.createElement('iframe');<br /> layer.tabIndex = '-1';<br /> layer.src = 'javascript:false;';<br /> elem.parentNode.appendChild(layer);</p><p> layer.style.width = elem.offsetWidth + 'px';<br /> layer.style.height = elem.offsetHeight + 'px';<br /> },</p><p> removeIframe:function(elem){<br /> var layers = elem.parentNode.getElementsByTagName('iframe');<br /> while(layers.length >0){<br /> layers[0].parentNode.removeChild(layers[0]);<br /> }<br /> }<br />}<br />window.onload = function(){<br /> magnifier.init({<br /> cont : document.getElementById('magnifier'),<br /> img : document.getElementById('magnifierImg'),<br /> mag : document.getElementById('mag'),<br /> scale : 3<br /> });<br />}<br /></script><br /></head><br /><body><br /><div id="magnifier"><br /><img src="http://www.blueidea.com/articleimg/2009/10/7087/03.jpg" id="img" /><br /><div id="Browser"></div><br /></div><br /><div id="mag"><img id="magnifierImg" /></div><br /><select style="position:absolute;top:200px;left:650px;width:100px;"><br /><option>select測試</option><br /><option>是否能覆蓋</option><br /></select><br /></body><br /></html>
[Ctrl+A 全部選擇 提示:你可先修改部分代碼,再按運行]

以前寫過一個jQuery的圖片放大效果,但是存在著一些小問題,然後最近有時間重寫了一遍,做了很詳盡的改進.改進了大部分bug,而且不採用jQuery.

程式說明

主要為magnifier類,裡面的主要方法有:

  • init:運行方法
  • start:則是滑鼠移入div的事件處理
  • move:則是滑鼠在div中移動的事件處理
  • end:滑鼠移出後的事件處理

程式介紹

主要思維:當滑鼠移入圖片的時候,放大層的DIV出現,然後根據滑鼠移動狀況,改變放大層內映像的top值和left值,使得2個地方保持一致的現實。而2個映像跟據比例進行設定,width和height值,使之產生放大的效果,下面進行詳細的解釋:

在init方法中,主要處理瀏覽框div層的大小,放大框的大小和放大的映像大小。
瀏覽框div的width和height跟據,原始圖片的大小/比例值可以獲得,見代碼:

css(m.cont.getElementsByTagName('div')[0],{        //m.cont.getElementsByTagName('div')[0]為瀏覽框
    'display' : 'none',                //開始設定為不可見
    'width' : m.cont.clientWidth / m.scale - borderWid + 'px',    //原始圖片的寬/比例值 - border的寬度
    'height' : m.cont.clientHeight / m.scale - borderWid + 'px',    ////原始圖片的高/比例值 - border的寬度
    'opacity' : 0.5                    //設定透明度
})

放大框的大小則設定為於原始映像相同大小,代碼如下:

css(m.mag,{
    'display' : 'none',
    'width' : m.cont.clientWidth + 'px',        //m.cont為原始映像
    'height' : m.cont.clientHeight + 'px',
    'position' : 'absolute',
    'left' : m.cont.offsetLeft + m.cont.offsetWidth + 10 + 'px',    //放大框的位置為原始映像的右方遠10px
    'top' : m.cont.offsetTop + 'px'
})

放大的映像大小為,原始映像大小*比例值,代碼如下:

css(m.img,{
    'position' : 'absolute',
    'width' : (m.cont.clientWidth * m.scale) + 'px',    //原始映像的寬*比例值
    'height' : (m.cont.clientHeight * m.scale) + 'px'    //原始映像的高*比例值
})

由於放大是根據比例進行放大,所以在瀏覽框上和放大映像上需要仔細計算,這也就是該程式的主要思維之一。

 

 

在第一次寫的程式裡,直接省去了onmouseover,因為直接使用onmousemove就可以滿足功能。而這次使用onmouseover是為了避免在使用過程中遇到select,在IE6下,select無法設定z-Index值,使得放大框的突然出現卻無法覆蓋select。詳細下面在討論,

在move方法中,最重要的就是如果做到滑鼠移動過程中,瀏覽框隨著滑鼠移動的同時,放大映像也跟著運動,,使得放大映像所顯示的範圍與瀏覽框所在原始映像位置一致。

先說說瀏覽框跟隨滑鼠移動,主要代碼如下:

top:pos.y - this.offsetTop - parseInt(this.getElementsByTagName('div')[0].style.height) / 2
left:pos.x - this.offsetLeft - parseInt(this.getElementsByTagName('div')[0].style.width) / 2

由於是,對m.cont綁定事件,所以這個時候this指向m.cont。

由映像可以得知left=滑鼠x - this.offsetLeft - 瀏覽框寬/2,所以跟據該幾何思想可以得出而代碼,而top的值也是根據一樣的道理所得,這裡就不做詳細解釋了。接下來就是在滑鼠運動的同時,放大映像也要跟著改變top和left值,代碼如下:

css(magnifier.m.img,{
    'top' : - (parseInt(this.getElementsByTagName('div')[0].style.top) * magnifier.m.scale) + 'px',
    'left' : - (parseInt(this.getElementsByTagName('div')[0].style.left) * magnifier.m.scale) + 'px'
})

代碼很清晰的可以得出,只需要在瀏覽框的top和left值上*比例就可以了。而加上負號的原因是預設座標為(0,0),而在移動過程中,始座標只會向負方向移動。
在該方法中有2個需要注意的地方:

1.

this.getElementsByTagName('div')[0].style.display = '';

應該放在設定this.getElementsByTagName('div')[0]的top與left之前,原因是如果display為none的話,無法擷取其寬和高。如果把display = ''放在設定top與left之後,會出現一個奇怪的現象,大家可以試下,該問題一直困擾了我很久,在多次嘗試中才發現問題再這上面。奇怪現象如下:

2.

'top' : Math.min(Math.max(pos.y - this.offsetTop - parseInt(this.getElementsByTagName('div')[0].style.height) / 2,0),this.clientHeight - this.getElementsByTagName('div')[0].offsetHeight) + 'px';

這麼長的代碼可能讓人很困惑,我只是用Math.max()和Math.min()去避免了採用if語句,自己偷了點懶,就是為了實現瀏覽框不會超出原始映像而已,仔細看看就清楚啦。

end方法很清晰,就是瀏覽框和放大框進行隱藏。

 

 

 

 

[覆蓋select]

在為了在IE6下可以覆蓋select,我加入了2個放法createIframe和removeIframe。分別是在onmouseover事件裡建立一個iframe和在onmouseout裡銷毀iframe。

createIframe:function(elem){
    var layer = document.createElement('iframe');
    layer.tabIndex = '-1';
    layer.src = 'javascript:false;';
    elem.parentNode.appendChild(layer);
       
    layer.style.width = elem.offsetWidth + 'px';
    layer.style.height = elem.offsetHeight + 'px';
}

首先需要使用負的tabIndex值把iframe排除在tab序列之外,否則使用者可能會使用鍵盤導航到它,這就亂了套了,所以需要將tabIndex值設定為負的。另外,還要設定src,設定該值是為了避免在SSL頁面上出現問題.在IE中,沒有設定src的iframe將會自動裝載about:blank。IE將此視為不安全頁面,而且會產生一個警告對話方塊,內容是“該頁麵包含安全和非安全的內容”。為了避免這個問題,可以將src設定為“javascript:false;”。(該段摘自<<JavaScript精髓>>)
而避免iframe在頁面所造成的混亂,所以在onmouseout中將iframe銷毀,而不對其進行隱藏。

使用說明

由於時間上的問題,所以沒有封裝的太好,主要是在CSS上,最好根據我所設定的那樣設定,感覺有些亂。希望大家能夠理解,而修改也不會太難.因為我內建一個css()函數,只要稍加設定就可以了。使用例子:

magnifier.init({
    cont : document.getElementById('magnifier'),
    img : document.getElementById('magnifierImg'),
    mag : document.getElementById('mag'),
    scale : 3
});

cont為container縮寫,指的是裝載原始映像的div;
img則是放大的映像;
mag則為magnifier縮寫,是指放大框;
scale為比例值,設定的值越大放大越大,但是這裡有個問題就是如果不可以整除時,會產生些很小的白邊,目前不知道如何解決;
至於瀏覽框和原始映像為m.cont.getElementsByTagName('img')[0]和m.cont.getElementsByTagName('div')[0],所以建議在裝載映像的div中最好只放一個div和img。

PS:剛剛給源碼也加了注釋了,有些沒有的,大概在下面的代碼說明會有.this指標搞的好混亂~希望大家能看的明白什麼回事..越用this越覺得不太好用啊..誒.>~搞了1個下午,累,休息下先哈。

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.