淘宝首页装修宝贝图片时鼠标经过会变大怎做

html-css014

淘宝首页装修宝贝图片时鼠标经过会变大怎做,第1张

这个效果也叫放大镜效果,最早好像在ppg出现的,之后就有了很多仿制品出来了。

一般用于放大查看商品图片,在凡客,京东商城,阿里巴巴等都有类似的效果。

好处是能在原图附近对图片进行局部放大查看,而且可以通过鼠标控制查看的部位。

【基本原理】

首先要有一个img元素作为原图对象,还要有一个容器作为显示框。

显示框里面放另一个img元素作为大图对象,并根据比例设置好尺寸。

当鼠标在原图上移动时,通过对大图进行绝对定位来显示对应的部位,实现类似放大镜的效果。

【图片加载】

程序初始化时会先执行_initLoad程序,主要用来载入图片。

由于img在载入之前获取尺寸是不准确的,所以相关参数的计算都要等到图片加载之后。

有两种放大的方式:使用原图放大、用已经放大的新图片。

原图放大的好处是只需加载一个图片,而使用新图片就可以得到更清晰的效果。

根据不同的方式,会选择对应的原图加载程序:

useOrigin = !this._zoomPic &&this._scale,

loadImage = $$F.bind( useOrigin ? this._loadOriginImage : this._loadImage, this )

当没有设置大图但有放大比例时,会自动使用原图放大加载程序。

先看看使用原图放大加载的过程:

1,加载原图:

if ( originPic &&originPic != image.src ) {

image.onload = loadImage

image.src = originPic

} else if ( image.src ) {

if ( !image.complete ) {

image.onload = loadImage

} else {

loadImage()

}

} else {

return

}

_originPic属性记录原图地址,如果设置了原图并且跟元素当前加载的图片不同,就设置onload并加载原图。

否则,如果元素当前有加载图片的话,先通过complete判断是否加载完成,没完成就设置onload,已经完成的话就直接执行加载程序。

最后,没有原图图片的话就退出程序。

2,执行_loadOriginImage加载程序:

this._image.onload = null

this._zoom.src = this._image.src

this._initLoaded()

由于ie6/7的gif图片载入bug,会先重置onload。

然后执行_initLoaded初始化加载设置程序。

使用新图片就复杂一点:

1,加载原图,同上。

2,预载大图:

var preload = this._preload, zoomPic = this._zoomPic || image.src,

loadPreload = $$F.bind( this._loadPreload, this )

if ( zoomPic != preload.src ) {

preload.onload = loadPreload

preload.src = zoomPic

} else {

if ( !preload.complete ) {

preload.onload = loadPreload

} else {

this._loadPreload()

}

}

_preload是预载对象,使用的是_loadPreload预载加载程序。

预载对象主要用来获取大图的原始尺寸,也是后面原图替换技巧的基础。

如果没有设置大图,说明当前没有设置大图也又没有放大比例,这时就用原图作为大图来用。

加载的方法跟原图类似。

3,当原图加载完成时,执行_loadImage原图加载程序:

复制代码

if ( this._loaded ) {

this._initLoaded()

} else {

this._loaded = true

if ( this._scale ) {

this._substitute = true

this._zoom.src = this._image.src

this._initLoaded()

}

}

复制代码

如果_loaded为true,说明大图已经加载,直接执行_initLoaded程序。

否则设置_loaded为true来标记原图已经加载,如果这时有自定义比例的话,先用原图替换大图。

因为一般大图加载会比较慢,先用原图替换就能立刻操作了,同时设置_substitute属性为true标记使用了替换。

4,当大图预载完成时,执行_loadPreload大图预载程序:

this._zoom.src = this._preload.src

if ( this._loaded ) {

if ( !this._substitute ) { this._initLoaded()}

} else {

this._loaded = true

}

如果_loaded是true,说明原图已经加载完,同时_substitute为false即没有使用原图替换的话,就执行_initLoaded程序。

如果原图没有加载完,那么设置_loaded为true标记大图已经加载。

关于图片加载还要注意一个问题,测试以下代码:

复制代码

<script>

var img=new Image

function test(){

img.onload=function(){alert("load")}

img.src="http://www.google.com.hk/images/nav_logo8.png"

}

test()

setTimeout(test,3000)

</script>

复制代码

在chrome/safari只会弹出一次"load",而其他都是正常的两次,可能是做了优化之类的吧。

当加载完成后,就可以设置相关的对象和参数,这些都在_initLoaded程序中进行。

【加载设置】

在_initLoaded初始化加载设置程序,主要是做触发放大效果前的准备工作。

第一步,执行_initSize程序初始化显示图尺寸。

首先修正放大比例:

if ( !scale ) { scale = this._preload.width / image.width}

this._scale = scale = Math.min( Math.max( this._min, scale ), this._max )

如果没有设置比例,就从预载对象获取的默认尺寸作为大图尺寸。

在图片加载时已经做好“安全措施”,确保这里能获得放大比例。

还可以通过自定义max和min属性来限制比例大小。

然后就可以按比例设置大图尺寸:

zoom.width = Math.ceil( image.width * scale )

zoom.height = Math.ceil( image.height * scale )

第二步,执行_initViewer初始化显示框程序,设置显示框。

先设置好样式:

var styles = { padding: 0, overflow: "hidden" }, p = $$D.getStyle( viewer, "position" )

if ( p != "relative" &&p != "absolute" ){ styles.position = "relative"}

$$D.setStyle( viewer, styles )

zoom.style.position = "absolute"

再把显示图插入显示框:

if ( !$$D.contains( viewer, zoom ) ){ viewer.appendChild( zoom )}

第三步,执行_initData初始化数据程序,主要是设置放大时用到的一些参数。

包括用于位置判断的原图坐标:

this._rect = $$D.rect( image )

用于left/top修正的修正参数:

this._repairLeft = image.clientLeft + parseInt($$D.getStyle( image, "padding-left" ))

this._repairTop = image.clientTop + parseInt($$D.getStyle( image, "padding-top" ))

还有范围参数和显示尺寸。

范围参数就是要显示的范围在原图的尺寸,显示尺寸是显示框的显示尺寸。

如果通过rangeWidth和rangeHeight自定义了范围参数,就可以结合放大比例计算出显示尺寸:

rangeWidth = Math.ceil( rangeWidth )

rangeHeight = Math.ceil( rangeHeight )

this._viewerWidth = Math.ceil( rangeWidth * scale )

this._viewerHeight = Math.ceil( rangeHeight * scale )

$$D.setStyle( viewer, {

width: this._viewerWidth + "px",

height: this._viewerHeight + "px"

})

复制代码

如果没有设置的话,就使用显示框的默认显示尺寸:

复制代码

var styles

if ( !viewer.clientWidth ) {

var style = viewer.style

styles = {

display: style.display,

position: style.position,

visibility: style.visibility

}

$$D.setStyle( viewer, {

display: "block", position: "absolute", visibility: "hidden"

})

}

this._viewerWidth = viewer.clientWidth

this._viewerHeight = viewer.clientHeight

if ( styles ) { $$D.setStyle( viewer, styles )}

rangeWidth = Math.ceil( this._viewerWidth / scale )

rangeHeight = Math.ceil( this._viewerHeight / scale )

复制代码

注意,显示范围是通过clientWidth/clientHeight来获取的。

如果显示框是display为none的隐藏状态,就不能直接获取clientWidth/clientHeight。

这种情况下,程序用以下方法获取:

1,记录display/position/visibility的原始值;

2,分别设为"block"/"absolute"/"hidden",这是既能隐藏也能占位的状态;

3,获取参数;

4,重新设回原始值,恢复原来的状态。

得到显示范围后,再配合比例就能得到范围参数了。

ps:这是通用的获取不占位元素尺寸参数的方法,jquery的css也是用这个方法获取width/height的。

比例计算后可能会得到小数,而尺寸大小只能是整数,程序一律使用Math.ceil来取整。

【放大效果】

所有东西都设置好后,就可以执行start设置触发程序了。

程序会自动执行start方法,里面主要是给原图对象的mouseover/mousemove绑定_start程序:

var image = this._image, START = this._START

$$E.addEvent( image, "mouseover", START )

$$E.addEvent( image, "mousemove", START )

分别对应移入原图对象和在原图对象上移动的情况。

ps:如果使用attachEvent的话还要注意重复绑定同一函数的问题,这里的addEvent就没有这个问题。

绑定的_start程序,主要是进行一些事件的解绑和绑定:

代码

为了在移出窗口时能结束放大效果,给document的mouseout绑定了_OUT程序:

this._OUT = $$F.bindAsEventListener( function(e){

if ( !e.relatedTarget ) this._END()

}, this )

当鼠标移出document会触发mouseout,如果当前relatedTarget是null的话,就延时执行_end结束程序:

var oThis = this, END = function(){ oThis._end()}

this._END = function(){ oThis._timer = setTimeout( END, oThis.delay )}

在_end程序中,会先执行stop方法,在里面移除所有可能绑定的事件,再执行start方法继续等待触发。

而mousemove绑定的_move移动程序,主要用来实现鼠标移动到哪里就放大哪里的功能。

为适应更多的情况(例如扩展篇的其他模式),把它绑定到document上,但也因此不能用mouseout事件来触发移出程序。

程序通过鼠标和原图的坐标比较,来判断鼠标是否移出原图对象范围:

var x = e.pageX, y = e.pageY, rect = this._rect

if ( x <rect.left || x >rect.right || y <rect.top || y >rect.bottom ) {

this._END()

} else {

...

}

如果鼠标移出原图对象的话,就执行_END结束放大效果。

如果鼠标在原图对象上移动,就计算坐标进行定位。

先修正坐标,把鼠标坐标转化成大图的定位坐标:

pos.left = viewerWidth / 2 - ( x - rect.left - this._repairLeft ) * scale

pos.top = viewerHeight / 2 - ( y - rect.top - this._repairTop ) * scale

再设置范围限制:

x = Math.ceil(Math.min(Math.max( pos.left, viewerWidth - zoom.width ), 0))

y = Math.ceil(Math.min(Math.max( pos.top, viewerHeight - zoom.height ), 0))

最后设置定位,使显示框显示要放大的部位。

ps:我尝试过用scrollLeft/scrollTop来做定位,但发现这样在ie中会像锯齿那样移动,放得越大越明显,所以放弃。

【鼠标滚动缩放】

如果设置mouse属性为true,就会开启鼠标滚动缩放功能。

在执行放大效果期间,可以通过滚动鼠标滚轮对大图进行缩放处理。

其实就是根据滚轮动参数的变化来修改放大比例。

关于鼠标滚动事件,在slider中也提过,不过那时只分析了ie和ff的区别,这里再分析一下。

首先ie是用mousewheel绑定事件的,使用event的wheelDelta来获取滚动参数。

其他浏览器用以下代码测试:

代码

向下滚动一下,可以得到以下结果:

ff:DOMMouseScroll:3_undefined

opera:mousewheel:3_-120

chrome/safari:mousewheel:0_-120

可以看到事件的绑定,ff只支持DOMMouseScroll,其他就只支持mousewheel。

而滚动参数的获取,ff只支持detail,opera两种都支持,chrome/safari就支持wheelDelta。

ps:不明白chrome/safari的detail为什么是0,有其他用途?

而DOMMouseScroll跟mousewheel还有一个不同是前者不能直接绑定元素,后者可以。

即可以elem.onmousewheel,但不能elem.onDOMMouseScroll。

根据以上分析,在_start程序里是这样把_mouse程序绑定到document的滚动事件中:

this.mouse &&$$E.addEvent( document, $$B.firefox ? "DOMMouseScroll" : "mousewheel", this._MOUSE )

在_mouse程序里面根据滚动参数和自定义的rate缩放比率得到新的放大比例:

this._scale += ( e.wheelDelta ? e.wheelDelta / (-120) : (e.detail || 0) / 3 ) * this.rate

修改比例时,程序参数也需要重新计算。

由于_rangeWidth/_rangeHeight会影响计算的过程,要重新恢复成自定义的默认值:

var opt = this.options

this._rangeWidth = opt.rangeWidth

this._rangeHeight = opt.rangeHeight

然后执行_initSize和_initData重新设置尺寸和参数,再执行_move重新定位。

最后记得用preventDefault防止触发页面滚动。

我用代码做了一个,步骤如下。

1 打开Flash8,新建Flash文档,ctrl+F8,新建影片剪辑元件,导入图片。

2 回到主场景中,把影片剪辑元件拖到舞台,在属性面板中,命名该影片剪辑的实例名称为pic_mc

3 选中第一帧,F9,打开动作面板,写上写下代码:

pic_mc.onRollOver = function() {

pic_mc._xscale = pic_mc._xscale+50;

pic_mc._yscale = pic_mc._yscale+50;

};

pic_mc.onRollOut = function() {

pic_mc._xscale = pic_mc._xscale-50;

pic_mc._yscale = pic_mc._yscale-50;

};

4 测试影片即可。

说明,代码中的“50”是放大的像素数,你可以根据实际情况修改,值越大效果越明显。还有,这是Action Script 2.0代码,直接在Flash 8运行是没问题的,如果在Flash CS3或者CS4版本,注意在新建Flash文档时,选择“Flash文件(2.0)”。

如果还有问题,可以加我。