欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

ImageZoom 圖片放大鏡效果(多功能擴(kuò)展篇)

 更新時(shí)間:2010年04月14日 09:39:37   作者:  
上一篇ImageZoom已經(jīng)對圖片放大效果做了詳細(xì)的分析,這次在ImageZoom的基礎(chǔ)上進(jìn)行擴(kuò)展,實(shí)現(xiàn)更多的效果。
主要擴(kuò)展了原圖和顯示框的展示模式,有以下幾種模式:
"follow" 跟隨模式:顯示框能跟隨鼠標(biāo)移動的效果;
"handle" 拖柄模式:原圖上有一個(gè)拖柄來標(biāo)記顯示范圍;
"cropper" 切割模式:原圖用不透明的來標(biāo)記顯示范圍,其他部分用半透明顯示;
"handle-cropper" 拖柄切割模式:拖柄模式和切割模式的混合版,同時(shí)用透明度和拖柄來標(biāo)記顯示范圍。
當(dāng)然更多的擴(kuò)展等待你的想象力來發(fā)掘。
兼容:ie6/7/8, firefox 3.6.2, opera 10.51, safari 4.0.4, chrome 4.1

程序說明

【擴(kuò)展模式】

上次ImagesLazyLoad使用了繼承做擴(kuò)展,這次用插件的形式來做擴(kuò)展。

先看看基礎(chǔ)模式,這些模式是保存在ImageZoom._MODE中的,類似這樣的結(jié)構(gòu):

復(fù)制代碼 代碼如下:

ImageZoom._MODE = {
模式名: {
options: {
...
},
methods: {
init: function() {
...
},
...
}
},
...
}

其中模式名就是基礎(chǔ)模式的名字,options是可選參數(shù)擴(kuò)展,methods是程序結(jié)構(gòu)的擴(kuò)展。
基礎(chǔ)模式包含"follow", "handle"和"cropper"模式,后面再詳細(xì)介紹。
methods包含要擴(kuò)展的鉤子程序,是擴(kuò)展的主要部分。
ps:這里說的模式不是“設(shè)計(jì)模式”里面的模式。

擴(kuò)展需要在程序初始化時(shí)進(jìn)行,要放在_initialize程序之前執(zhí)行。
為了不影響原程序的結(jié)構(gòu),這里用織入法在_initialize之前插入一段程序:

復(fù)制代碼 代碼如下:

ImageZoom.prototype._initialize = (function(){
var init = ImageZoom.prototype._initialize,
...;
return function(){
...
init.apply( this, arguments );
}
})();

原理就是先保存原來的函數(shù),插入一段程序組成新函數(shù),然后重新替換原來的函數(shù)。

考慮到組合基礎(chǔ)模式的情況,使用了一個(gè)對象保存真正使用的模式:
復(fù)制代碼 代碼如下:


mode = ImageZoom._MODE,
modes = {
"follow": [ mode.follow ],
"handle": [ mode.handle ],
"cropper": [ mode.cropper ],
"handle-cropper": [ mode.handle, mode.cropper ]
};

可以看到"handle-cropper"模式其實(shí)就是"handle"和"cropper"的組合模式。

插入的程序的主要任務(wù)是根據(jù)設(shè)定好的基礎(chǔ)模式,進(jìn)行擴(kuò)展:
復(fù)制代碼 代碼如下:

var options = arguments[2];
if ( options && options.mode && modes[ options.mode ] ) {
$$A.forEach( modes[ options.mode ], function( mode ){
$$.extend( options, mode.options, false );
$$A.forEach( mode.methods, function( method, name ){
$$CE.addEvent( this, name, method );
}, this );
}, this );
}

首先擴(kuò)展options可選參數(shù)對象,由于可選參數(shù)是第三個(gè)參數(shù),所以用arguments[2]獲取。
extend的第三個(gè)參數(shù)設(shè)為false,說明不重寫相同屬性,即保留自定義的屬性值。
然后把methods里面的方法作為鉤子函數(shù)逐個(gè)添加到程序中。

methods可以包含init, load, start, repair, move, end, dispose這幾個(gè)方法,分別對應(yīng)ImageZoom中初始化、加載、開始、修正、移動、結(jié)束和銷毀事件。
在擴(kuò)展時(shí),不同的事件執(zhí)行不同的任務(wù):
init初始化函數(shù):用來設(shè)置擴(kuò)展需要的屬性,注意這些屬性不要跟ImageZoom本身的屬性沖突了,即重名。
load加載函數(shù):圖片加載完成,相關(guān)參數(shù)也設(shè)置完成,主要做執(zhí)行放大效果前的準(zhǔn)備工作。
start開始函數(shù):觸發(fā)放大效果時(shí)執(zhí)行的。
repair修正函數(shù):用于修正大圖定位的坐標(biāo)值。
move移動函數(shù):觸發(fā)放大效果后,鼠標(biāo)移動時(shí)執(zhí)行的。
end結(jié)束函數(shù)就:結(jié)束放大效果時(shí)執(zhí)行的。
dispose銷毀函數(shù):在移除程序時(shí)清理程序的。
ps:具體位置參考ImageZoom中使用$$CE.fireEvent的部分。

可以看到這里用了織入法(weave)和鉤子法(hook)對程序做擴(kuò)展。
織入法是一種aop,可以在不改變原程序的基礎(chǔ)上進(jìn)行擴(kuò)展,但只能在函數(shù)前面或后面加入程序。
而鉤子法必須在原程序中設(shè)置好對應(yīng)鉤子才能配合使用,但位置相對靈活。


【跟隨模式】

在"follow"跟隨模式中,進(jìn)行放大時(shí),顯示框會跟隨鼠標(biāo)移動,就像拿著放大鏡看的效果。

首先顯示框要絕對定位,要實(shí)現(xiàn)顯示框跟隨鼠標(biāo)移動,只要在move中設(shè)置對應(yīng)的left/top就行了:


var style = this._viewer.style;
style.left = e.pageX - this._repairFollowLeft + "px";
style.top = e.pageY - this._repairFollowTop + "px";
其中pageX/pageY是鼠標(biāo)當(dāng)前的坐標(biāo),_repairFollowLeft/_repairFollowTop是坐標(biāo)的修正參數(shù)。

修正參數(shù)是在load中設(shè)置的,如果顯示框隱藏的話,用上一篇獲取顯示范圍的方法獲取參數(shù):
復(fù)制代碼 代碼如下:

if ( !viewer.offsetWidth ) {
styles = { display: style.display, visibility: style.visibility };
$$D.setStyle( viewer, { display: "block", visibility: "hidden" });
}
...
if ( styles ) { $$D.setStyle( viewer, styles ); }

為了跟隨時(shí),讓鼠標(biāo)固定在顯示框中心位置,先根據(jù)顯示框的offsetWidth/offsetHeight修正參數(shù):
復(fù)制代碼 代碼如下:

this._repairFollowLeft = viewer.offsetWidth / 2;
this._repairFollowTop = viewer.offsetHeight / 2;

如果顯示框的offsetParent不是body,還需要根據(jù)offsetParent修正坐標(biāo):
復(fù)制代碼 代碼如下:

if ( !/BODY|HTML/.test( viewer.offsetParent.nodeName ) ) {
var parent = viewer.offsetParent, rect = $$D.rect( parent );
this._repairFollowLeft += rect.left + parent.clientLeft;
this._repairFollowTop += rect.top + parent.clientTop;
}

ps:在Maxthon測試時(shí)發(fā)現(xiàn)body子元素的offsetParent不是body而是html。

為了在移除程序后,能恢復(fù)顯示框的樣式,在load程序中做了樣式的備份:
復(fù)制代碼 代碼如下:

var viewer = this._viewer, style = viewer.style, styles;
this._stylesFollow = {
left: style.left, top: style.top, position: style.position
};

并在dispose中恢復(fù):

$$D.setStyle( this._viewer, this._stylesFollow );

現(xiàn)在已經(jīng)達(dá)到了基本的效果,但由于大圖移動范圍的限制,當(dāng)鼠標(biāo)移動到接近邊界時(shí),大圖就卡住不會動了。
為了實(shí)現(xiàn)在鼠標(biāo)移動時(shí),大圖會持續(xù)變化的效果,在repair中修正了移動坐標(biāo):
復(fù)制代碼 代碼如下:

pos.left = ( viewerWidth / 2 - pos.left ) * ( viewerWidth / zoom.width - 1 );
pos.top = ( viewerHeight / 2 - pos.top ) * ( viewerHeight / zoom.height - 1 );

原理稍有些復(fù)雜,以水平坐標(biāo)為例,先看下圖:

大方框代表大圖對象,小方框代表顯示框。
當(dāng)前位置是根據(jù)鼠標(biāo)坐標(biāo)得到的實(shí)際顯示的位置,目標(biāo)位置想要實(shí)現(xiàn)效果的位置。
有一些物理或幾何知識應(yīng)該明白這個(gè)等式:x / y = m / n
可以推出:y = x * n / m = x * ( zoom.width - viewerWidth ) / zoom.height
x當(dāng)前坐標(biāo)可以通過pos.left來得到:x = viewerWidth / 2 - pos.left
最后得到:left = -y = ( viewerWidth / 2 - pos.left ) * ( viewerWidth / zoom.width - 1 )
垂直坐標(biāo)也差不多。


【拖柄模式】

拖柄是一個(gè)層,在原圖上面,用來表示顯示范圍在原圖的位置和范圍。
顯示范圍可以根據(jù)_rangeWidth/_rangeHeight獲取。
至于位置的指定可以根據(jù)鼠標(biāo)坐標(biāo)或大圖定位坐標(biāo)來設(shè)置。
如果鼠標(biāo)坐標(biāo)的話還必須做其他處理,例如范圍控制,而根據(jù)大圖定位坐標(biāo)相對就方便準(zhǔn)確得多,程序也是用后面一個(gè)方法。

首先在init定義一個(gè)_handle拖柄對象:
復(fù)制代碼 代碼如下:

var handle = $$( this.options.handle );
if ( !handle ) {
var body = document.body;
handle = body.insertBefore(this._viewer.cloneNode(false), body.childNodes[0]);
handle.id = "";
handle["_createbyhandle"] = true;
}
$$D.setStyle( handle, { padding: 0, margin: 0, display: "none" } );

如果沒有自定義拖柄對象,會復(fù)制顯示框作為拖柄對象。
對于自動生成的拖柄對象,會添加"_createbyhandle"屬性作標(biāo)記,方便在dispose中移除。

在load時(shí),設(shè)置拖柄樣式:
復(fù)制代碼 代碼如下:

$$D.setStyle( handle, {
position: "absolute",
width: this._rangeWidth + "px",
height: this._rangeHeight + "px",
display: "block",
visibility: "hidden"
});

絕對定位是必須的,并根據(jù)_rangeWidth/_rangeHeight設(shè)置尺寸。
設(shè)置display和visibility是為了下面獲取參數(shù)。

先根據(jù)原圖坐標(biāo)獲取修正參數(shù):


this._repairHandleLeft = rect.left + this._repairLeft - handle.clientLeft;
this._repairHandleTop = rect.top + this._repairTop - handle.clientTop;

和跟隨模式類似,也要做offsetParent定位的修正:

復(fù)制代碼 代碼如下:

if ( handle.offsetParent.nodeName.toUpperCase() != "BODY" ) {
var parent = handle.offsetParent, rect = $$D.rect( parent );
this._repairHandleLeft -= rect.left + parent.clientLeft;
this._repairHandleTop -= rect.top + parent.clientTop;
}


然后重新隱藏:

$$D.setStyle( handle, { display: "none", visibility: "visible" });

在start時(shí),顯示拖柄對象。

在move時(shí),根據(jù)大圖定位坐標(biāo)設(shè)置拖柄定位:

復(fù)制代碼 代碼如下:

var style = this._handle.style, scale = this._scale;
style.left = Math.ceil( this._repairHandleLeft - x / scale ) + "px";
style.top = Math.ceil( this._repairHandleTop - y / scale ) + "px";

在end時(shí),隱藏拖柄對象。


【切割模式】

“切割”就是選擇的部分全透明,其他部分半透明的效果。
主要通過clip來實(shí)現(xiàn),具體原理可以看圖片切割效果。

為了實(shí)現(xiàn)切割效果,需要在init中新建一個(gè)_cropper切割層:

復(fù)制代碼 代碼如下:

var body = document.body,
cropper = body.insertBefore(document.createElement("img"), body.childNodes[0]);
cropper.style.display = "none";

并在load中設(shè)置這個(gè)切割層:

復(fù)制代碼 代碼如下:

cropper.src = image.src;
cropper.width = image.width;
cropper.height = image.height;
$$D.setStyle( cropper, {
position: "absolute",
left: rect.left + this._repairLeft + "px",
top: rect.top + this._repairTop + "px"
});

差不多是復(fù)制一個(gè)原圖對象,并且絕對定位到原圖對象上面。

在start時(shí),顯示切割層,并根據(jù)透明度設(shè)置原圖為半透明狀態(tài)。

在move時(shí),根據(jù)大圖移動的坐標(biāo)設(shè)置切割層要clip的范圍:
復(fù)制代碼 代碼如下:

var w = this._rangeWidth, h = this._rangeHeight, scale = this._scale;
x = Math.ceil( -x / scale ); y = Math.ceil( -y / scale );
this._cropper.style.clip = "rect(" + y + "px " + (x + w) + "px " + (y + h) + "px " + x + "px)";

在end時(shí),隱藏切割層,并重新設(shè)置原圖為不透明,來恢復(fù)原來的狀態(tài)。

還要記得在dispose中移除切割層。


使用技巧

需要擴(kuò)展的效果時(shí)才需要添加這個(gè)擴(kuò)展程序。

可自行對ImageZoom._MODE進(jìn)行擴(kuò)展,擴(kuò)展后記得在modes添加對應(yīng)模式。

可以組合多個(gè)基礎(chǔ)模式同時(shí)使用,具體參考"handle-cropper"模式。


使用說明

使用方法跟ImageZoom差不多,只是多了一個(gè)可選參考mode設(shè)置顯示模式。
使用"handle"模式時(shí),可選參數(shù)的"handle"屬性可以設(shè)置拖柄對象。
使用"cropper"模式時(shí),可選參數(shù)的"opacity"屬性可以設(shè)置透明度。
使用"handle-cropper"模式時(shí),以上兩個(gè)參數(shù)都可以使用。
程序源碼
復(fù)制代碼 代碼如下:

ImageZoom._MODE = {
//跟隨
"follow": {
methods: {
init: function() {
this._stylesFollow = null;//備份樣式
this._repairFollowLeft = 0;//修正坐標(biāo)left
this._repairFollowTop = 0;//修正坐標(biāo)top
},
load: function() {
var viewer = this._viewer, style = viewer.style, styles;
this._stylesFollow = {
left: style.left, top: style.top, position: style.position
};
viewer.style.position = "absolute";
//獲取修正參數(shù)
if ( !viewer.offsetWidth ) {//隱藏
styles = { display: style.display, visibility: style.visibility };
$$D.setStyle( viewer, { display: "block", visibility: "hidden" });
}
//修正中心位置
this._repairFollowLeft = viewer.offsetWidth / 2;
this._repairFollowTop = viewer.offsetHeight / 2;
//修正offsetParent位置
if ( !/BODY|HTML/.test( viewer.offsetParent.nodeName ) ) {
var parent = viewer.offsetParent, rect = $$D.rect( parent );
this._repairFollowLeft += rect.left + parent.clientLeft;
this._repairFollowTop += rect.top + parent.clientTop;
}
if ( styles ) { $$D.setStyle( viewer, styles ); }
},
repair: function(e, pos) {
var zoom = this._zoom,
viewerWidth = this._viewerWidth,
viewerHeight = this._viewerHeight;
pos.left = ( viewerWidth / 2 - pos.left ) * ( viewerWidth / zoom.width - 1 );
pos.top = ( viewerHeight / 2 - pos.top ) * ( viewerHeight / zoom.height - 1 );
},
move: function(e) {
var style = this._viewer.style;
style.left = e.pageX - this._repairFollowLeft + "px";
style.top = e.pageY - this._repairFollowTop + "px";
},
dispose: function() {
$$D.setStyle( this._viewer, this._stylesFollow );
}
}
},
//拖柄
"handle": {
options: {//默認(rèn)值
handle: ""http://拖柄對象
},
methods: {
init: function() {
var handle = $$( this.options.handle );
if ( !handle ) {//沒有定義的話用復(fù)制顯示框代替
var body = document.body;
handle = body.insertBefore(this._viewer.cloneNode(false), body.childNodes[0]);
handle.id = "";
handle["_createbyhandle"] = true;//生成標(biāo)識用于移除
}
$$D.setStyle( handle, { padding: 0, margin: 0, display: "none" } );

this._handle = handle;
this._repairHandleLeft = 0;//修正坐標(biāo)left
this._repairHandleTop = 0;//修正坐標(biāo)top
},
load: function() {
var handle = this._handle, rect = this._rect;
$$D.setStyle( handle, {
position: "absolute",
width: this._rangeWidth + "px",
height: this._rangeHeight + "px",
display: "block",
visibility: "hidden"
});
//獲取修正參數(shù)
this._repairHandleLeft = rect.left + this._repairLeft - handle.clientLeft;
this._repairHandleTop = rect.top + this._repairTop - handle.clientTop;
//修正offsetParent位置
if ( !/BODY|HTML/.test( handle.offsetParent.nodeName ) ) {
var parent = handle.offsetParent, rect = $$D.rect( parent );
this._repairHandleLeft -= rect.left + parent.clientLeft;
this._repairHandleTop -= rect.top + parent.clientTop;
}
//隱藏
$$D.setStyle( handle, { display: "none", visibility: "visible" });
},
start: function() {
this._handle.style.display = "block";
},
move: function(e, x, y) {
var style = this._handle.style, scale = this._scale;
style.left = Math.ceil( this._repairHandleLeft - x / scale ) + "px";
style.top = Math.ceil( this._repairHandleTop - y / scale ) + "px";
},
end: function() {
this._handle.style.display = "none";
},
dispose: function() {
if( "_createbyhandle" in this._handle ){ document.body.removeChild( this._handle ); }
this._handle = null;
}
}
},
//切割
"cropper": {
options: {//默認(rèn)值
opacity: .5//透明度
},
methods: {
init: function() {
var body = document.body,
cropper = body.insertBefore(document.createElement("img"), body.childNodes[0]);
cropper.style.display = "none";

this._cropper = cropper;
this.opacity = this.options.opacity;
},
load: function() {
var cropper = this._cropper, image = this._image, rect = this._rect;
cropper.src = image.src;
cropper.width = image.width;
cropper.height = image.height;
$$D.setStyle( cropper, {
position: "absolute",
left: rect.left + this._repairLeft + "px",
top: rect.top + this._repairTop + "px"
});
},
start: function() {
this._cropper.style.display = "block";
$$D.setStyle( this._image, "opacity", this.opacity );
},
move: function(e, x, y) {
var w = this._rangeWidth, h = this._rangeHeight, scale = this._scale;
x = Math.ceil( -x / scale ); y = Math.ceil( -y / scale );
this._cropper.style.clip = "rect(" + y + "px " + (x + w) + "px " + (y + h) + "px " + x + "px)";
},
end: function() {
$$D.setStyle( this._image, "opacity", 1 );
this._cropper.style.display = "none";
},
dispose: function() {
document.body.removeChild( this._cropper );
this._cropper = null;
}
}
}
}

ImageZoom.prototype._initialize = (function(){
var init = ImageZoom.prototype._initialize,
mode = ImageZoom._MODE,
modes = {
"follow": [ mode.follow ],
"handle": [ mode.handle ],
"cropper": [ mode.cropper ],
"handle-cropper": [ mode.handle, mode.cropper ]
};
return function(){
var options = arguments[2];
if ( options && options.mode && modes[ options.mode ] ) {
$$A.forEach( modes[ options.mode ], function( mode ){
//擴(kuò)展options
$$.extend( options, mode.options, false );
//擴(kuò)展鉤子
$$A.forEach( mode.methods, function( method, name ){
$$CE.addEvent( this, name, method );
}, this );
}, this );
}
init.apply( this, arguments );
}
})();

在線演示地址http://demo.jb51.net/js/ImageZoom_ext/ImageZoom_ext.htm
打包下載地址http://www.dbjr.com.cn/jiaoben/25809.html
出處:http://www.cnblogs.com/cloudgamer/

相關(guān)文章

  • js 火狐下取本地路徑實(shí)現(xiàn)思路

    js 火狐下取本地路徑實(shí)現(xiàn)思路

    火狐下取本地全路徑使用js代碼實(shí)現(xiàn),感興趣的朋友可以參考下哈,希望可以幫助到你
    2013-04-04
  • JS模板編譯的實(shí)現(xiàn)詳情

    JS模板編譯的實(shí)現(xiàn)詳情

    這篇文章主要介紹了JS模板編譯的實(shí)現(xiàn)詳情,編譯是一種格式變成另一種格式的過程。編譯會導(dǎo)致好的結(jié)果,比如書寫簡單的代碼,編譯出來復(fù)雜的代碼;或者提高代碼的使用性能
    2022-07-07
  • javascript ES6 Template String模板字符串使用方法

    javascript ES6 Template String模板字符串使用方法

    這篇文章主要介紹了javascript ES6 模板字符串(Template String)是增強(qiáng)版的字符串,用反引號(`)標(biāo)識,它可以當(dāng)作普通字符串使用,也可以用來定義多行字符串,或者在字符串中嵌入變量,需要的朋友可以參考下
    2023-06-06
  • javascript的動態(tài)加載、緩存、更新以及復(fù)用(一)

    javascript的動態(tài)加載、緩存、更新以及復(fù)用(一)

    在做OA、MIS、ERP等信息管理類的項(xiàng)目,經(jīng)常會遇到引用很多js文件,這就需要用到動態(tài)加載、緩存、更新以及復(fù)用等技術(shù),下面我們來討論下
    2014-06-06
  • JavaScript中實(shí)現(xiàn)異步編程模式的4種方法

    JavaScript中實(shí)現(xiàn)異步編程模式的4種方法

    這篇文章主要介紹了JavaScript中實(shí)現(xiàn)異步編程模式的4種方法,本文講解了回調(diào)函數(shù)、事件監(jiān)聽、發(fā)布/訂閱、Promises對象4種方法,需要的朋友可以參考下
    2014-09-09
  • JS基于正則表達(dá)式的替換操作(replace)用法示例

    JS基于正則表達(dá)式的替換操作(replace)用法示例

    這篇文章主要介紹了JS基于正則表達(dá)式的替換操作(replace)用法,結(jié)合具體實(shí)例形式詳細(xì)分析了replace函數(shù)的語法、參數(shù)及具體使用技巧,需要的朋友可以參考下
    2017-04-04
  • js獲取地址欄中傳遞的參數(shù)(兩種方法)

    js獲取地址欄中傳遞的參數(shù)(兩種方法)

    本文主要介紹了如何獲取地址欄中的參數(shù)的兩種方法。具有很好的參考價(jià)值,下面跟著小編一起來看下吧
    2017-02-02
  • webpack4.0 入門實(shí)踐教程

    webpack4.0 入門實(shí)踐教程

    webpack4.0發(fā)布了一段時(shí)間了,這篇文章主要介紹了webpack4.0 入門實(shí)踐教程,小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧
    2018-10-10
  • JS實(shí)現(xiàn)導(dǎo)出Excel和CSV文件操作

    JS實(shí)現(xiàn)導(dǎo)出Excel和CSV文件操作

    這篇文章介紹了JS實(shí)現(xiàn)導(dǎo)出Excel和CSV文件的方法,文中通過示例代碼介紹的非常詳細(xì)。對大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2022-05-05
  • 利用JavaScript將Excel轉(zhuǎn)換為JSON示例代碼

    利用JavaScript將Excel轉(zhuǎn)換為JSON示例代碼

    這篇文章主要給大家介紹了關(guān)于利用JavaScript將Excel轉(zhuǎn)換為JSON的相關(guān)資料,文中通過示例代碼介紹的非常詳細(xì),對大家學(xué)習(xí)或者使用JavaScript具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面來一起學(xué)習(xí)學(xué)習(xí)吧
    2019-06-06

最新評論