javascript
JavaScript 仿LightBox内容显示效果
近來要做一個LightBox的效果(也有的叫Windows關機效果),不過不用那么復雜,能顯示一個內容框就行了。
這個效果很久以前就做過,無非就是一個覆蓋全屏的層,加一個內容顯示的層。不過showbo教了我position:fixed這個新特性,決定重寫一遍。
ps:“定位效果”的意思是屏幕滾動也能固定位置。
程序說明:
要實現一個簡單的LightBox效果,主要有兩個部分:覆蓋層和高亮層。
【跨瀏覽器的固定定位】
首先要先說說這個東西position:fixed,它的作用是跨瀏覽器的固定定位。
摘自詳解定位與定位應用:
“如讓一個元素可能隨著網頁的滾動而不斷改變自己在瀏覽器的位置。而現在我可以通過CSS中的一個定位屬性來實現這樣的一個效果,這個元素屬性就是曾經不被支持的position:fixed; 他的含義就是:固定定位。這個固定與絕對定位很像,唯一不同的是絕對定位是被固定在網頁中的某一個位置,而固定定位則是固定在瀏覽器的視框位置。”
程序中很多地方利用了這個css,ie7、ff都支持這個css,但ie6不支持,程序中只能是在ie6模擬這個效果。?
【覆蓋層】
覆蓋層的作用是把焦點限制在高亮層上,原理是通過一個絕對定位的層(通常使用div),設置它的寬度和高度以致能覆蓋整個屏幕(包括縮放和滾動瀏覽器的情況下),再給它設置一個比較高的zIndex來層疊在原有內容之上(但要比高亮層小),這樣用戶就只能點到這個層之上的內容了。
如果初始化時沒有提供覆蓋層對象,程序中會自動創建:
其中由于document.body.appendChild()導致IE已終止操作bug,所以用了insertBefore。。
【覆蓋屏幕】
覆蓋層的關鍵就是如何做到覆蓋整個屏幕(鎖定整個頁面),支持position:fixed的話很簡單:
with(this.Lay.style){?display?=?"none";?zIndex?=?this.zIndex;?left?=?top?=?0;?position?=?"fixed";?width?=?height?=?"100%";?}
這樣能把瀏覽器的視框覆蓋了,其中使用了fixed樣式,這里的意思是定位在瀏覽器的視框,并100%覆蓋。
注意不要理解錯為這個層覆蓋了整個頁面,它只是把瀏覽器可視的部分覆蓋了來達到效果。
ie6不支持怎么辦?有幾個方法:
1,做一個覆蓋視框的層,并在onscroll時相應移動,在onresize時重新設大小;
2,做一個覆蓋視框的層,在樣式上模擬fixed效果;
3,做一個層覆蓋了整個頁面的層,并在onresize時重新設大小;
方法1的缺點是滾動時很容易露出馬腳,而且不好看;方法2的缺點是需要頁面結構的改動和body樣式的修改,絕對不是好的架構;而我用的是方法3,有更好的方法歡迎提出。
用這個方法只要把position設為absolute,并使用一個_resize方法來設置width和height即可:
this.Lay.style.position?=?"absolute";
this._resize?=?Bind(this,?function(){
????this.Lay.style.width?=?Math.max(document.documentElement.scrollWidth,?document.documentElement.clientWidth)?+?"px";
????this.Lay.style.height?=?Math.max(document.documentElement.scrollHeight,?document.documentElement.clientHeight)?+?"px";
});
要注意的是scrollHeight和clientHeight的區別(用Height容易測試),順帶還有offsetHeight,手冊上的說明:
scrollHeight:Retrieves the scrolling height of the?object.
clientHeight:Retrieves the height of the?object?including padding, but not including margin, border, or scroll bar.
offsetHeight:Retrieves the height of the?object?relative to the layout or coordinate parent, as specified by the offsetParent?property.
我的理解是:
scrollHeight是對象的內容的高度;
clientHeight是對象的可視部分高度;
offsetHeight是clientHeight加上border和滾動條本身高度。
舉個例子吧,先說說clientHeight和offsetHeight的區別(在ie7中測試):
?
測的是外面的div,offsetHeight和clientHeight相差17(分別是83和100),這個相差的就是那個滾動條本身的高度。
再看看clientHeight和scrollHeight的區別(下面是模擬在ie中的情況):
| ? | ? |
可以看到clientHeight不受內容影響,都是83,即內容有沒有超過對象高度都不受影響,但scrollHeight會受內容高度影響,而且從測試可以意識到:
當有滾動條時,覆蓋層的高度應該取scrollHeight(內容高度);當沒有滾動條時,覆蓋層的高度應該取clientHeight(視框高度)。
而恰好兩個情況都是取兩者中比較大的值,所以就有了以下程序:Math.max(document.documentElement.scrollHeight,?document.documentElement.clientHeight)?+?"px";
設寬度時是不包括滾動條部分的而documentElement一般也沒有border,所以不需要offsetWidth。
上面可以看到我用的是documentElement而不是body,手冊上是這樣說的:
Retrieves a reference to the root node of the document.
意思是整個文檔的根節點,其實就是html節點(body的上一級),注意這是在XHTML的標準下。上面可以看到我們取值的對象是整個文檔而不只是body,所以這里用documentElement。
要注意的是在window的onresize事件中scrollWidth和clientWidth的值會產生變化,程序中在onresize中使用_resize方法重新設置寬度高度:
if(isIE6){?this._resize();?window.attachEvent("onresize",?this._resize);?}
【覆蓋select】
自定義的層給select遮擋住是一個老問題了,不過可喜的是ie7和ff都已經支持select的zIndex,只要給層設定高的zIndex就能覆蓋select了,可惜對于ie6這個問題還是需要解決。
覆蓋select據我所知有兩個比較好的方法:
1,顯示層時,先隱藏select,關閉層時再重新顯示;
2,用一個iframe作為層的底,來遮住select。
方法1應該都明白,方法2就是利用iframe可以覆蓋select的特性,只要把一個iframe作為層的底部就可以覆蓋下面的select了,程序中是這樣使用的:
this.Lay.innerHTML?=?'<iframe?style="position:absolute;top:0;left:0;width:100%;height:100%;filter:alpha(opacity=0);"></iframe>'
可以看出這個透明的iframe也以同樣覆蓋整個頁面,如果是有內容顯示的頁面最好設置z-index:-1;確保iframe在層的底部。
個人覺得使用方法2比較好,但始終是改變了頁面結構,有時會比較難控制,至于方法1就比較容易方便。
【高亮層】
高亮層就是用來顯示內容的層,沒什么看頭,所以特意加了些效果在上面,吸引一下眼球。
有興趣的話可以結合拖放效果和漸變效果,做出更好的效果。
【固定定位】
這里“固定定位”的意思是當滾動滾動條時,高亮層依然保持在瀏覽器對應的位置上,把Fixed設為true就會開啟這個效果。
同樣對于支持fixed的瀏覽器很簡單,只要把position設為fixed就行了,這個樣式本來就是這樣使用的,但可憐的ie6只能模擬了。
ie6模擬的原理是在onscroll事件中,不斷根據滾動的距離修正top和left。
首先設置position為absolute,要注意的是position要在覆蓋層顯示之前顯示,否則計算覆蓋層寬高時會計算偏差(例如把頁面撐大)。
再給onscroll事件添加定位函數_fixed來修正滾屏參數:
定位函數_fixed是這樣的:
this._fixed?=?Bind(this,?function(){?this.Center???this.SetCenter()?:?this.SetFixed();?});
可以看出在_fixed中,當設置了居中顯示時會執行SetCenter程序(后面會說明),否則就執行SetFixed程序。
先說說SetFixed程序的原理,就是把當前scrollTop減去_top值(上一個scrollTop值)再加上當前的offsetTop,就得到要設置的top值了:
this.Box.style.top?=?document.documentElement.scrollTop?-?this._top?+?this.Box.offsetTop?+?"px";
this.Box.style.left?=?document.documentElement.scrollLeft?-?this._left?+?this.Box.offsetLeft?+?"px";
?
this._top?=?document.documentElement.scrollTop;?this._left?=?document.documentElement.scrollLeft;
【居中顯示】
“居中顯示”的意思是高亮層位于視框左右上下居中的位置。
實現這個有兩個方法:
1,視框寬度減去高亮層寬度的一半就是居中需要的left值;
2,先設置left值為50%,然后marginLeft設為負的高亮層寬度的一半。
方法1相對方法2需要多一個視框寬度,而且方法2在縮放瀏覽器時也能保持居中,明顯方法2是更好,不過用margin會影響到left和top的計算,必須注意(例如SetFix修正的地方)。這里我選擇了方法2,還要注意offsetWidth和offsetHeight需要在高亮層顯示之后才能獲取,所以定位程序需要放到高亮層顯示之后:
this.Box.style.top?=?this.Box.style.left?=?"50%";
if(this.Fixed){
????this.Box.style.marginTop?=?-?this.Box.offsetHeight?/?2?+?"px";
????this.Box.style.marginLeft?=?-?this.Box.offsetWidth?/?2?+?"px";
}else{
????this.SetCenter();
}
其中如果不是固定定位,需要用SetCenter程序來修正滾屏參數,SetCenter程序是這樣的:
this.Box.style.marginTop?=?document.documentElement.scrollTop?-?this.Box.offsetHeight?/?2?+?"px";
this.Box.style.marginLeft?=?document.documentElement.scrollLeft?-?this.Box.offsetWidth?/?2?+?"px";
【比較文檔位置】
在ie6當不顯示覆蓋層時需要另外隱藏select,這里使用了“覆蓋select”的方法1,值得留意的是這里加了個select是否在高亮層的判斷:
this._select.length?=?0;
Each(document.getElementsByTagName("select"),?Bind(this,?function(o){
????if(!Contains(this.Box,?o)){?o.style.visibility?=?"hidden";?this._select.push(o);?}
}))
其中Contains程序是這樣的:
????return?a.contains???a?!=?b?&&?a.contains(b)?:?!!(a.compareDocumentPosition(b)?&?16);
}
作用是返回a里面是否包含b,里面用到了兩個函數,分別是ie的contains和ff(dom)的compareDocumentPosition。
其中contains手冊里是這樣寫的:
Checks whether the given element is contained within the object.?
意思是檢測所給對象是否包含在指定對象里面。注意如果所給對象就是指定對象本身也會返回true,雖然這樣不太合理。
而ff的compareDocumentPosition功能更強大。
參考Comparing Document Position看下表:
從NodeA.compareDocumentPosition(NodeB)返回的結果:
| Bits | Number | Meaning |
| 000000 | 0 | Elements are identical. |
| 000001 | 1 | The nodes are in different documents (or one is outside of a document). |
| 000010 | 2 | Node B precedes Node A. |
| 000100 | 4 | Node A precedes Node B. |
| 001000 | 8 | Node B contains Node A. |
| 010000 | 16 | Node A contains Node B. |
| 100000 | 32 | For private use by the browser. |
從這里可以看出NodeA.compareDocumentPosition(NodeB) & 16的意思是當第5位數是“1”時才返回16,也就是只有NodeA包含NodeB時返回16(&是位與運算)。
ps:為什么不直接a.compareDocumentPosition(b)?==?16,我也不清楚。
程序代碼:
var?isIE?=?(document.all)???true?:?false;
var?isIE6?=?isIE?&&?([/MSIE?(\d)\.0/i.exec(navigator.userAgent)][0][1]?==?6);
var?$?=?function?(id)?{
????return?"string"?==?typeof?id???document.getElementById(id)?:?id;
};
var?Class?=?{
????create:?function()?{
????????return?function()?{?this.initialize.apply(this,?arguments);?}
????}
}
var?Extend?=?function(destination,?source)?{
????for?(var?property?in?source)?{
????????destination[property]?=?source[property];
????}
}
var?Bind?=?function(object,?fun)?{
????return?function()?{
????????return?fun.apply(object,?arguments);
????}
}
var?Each?=?function(list,?fun){
????for?(var?i?=?0,?len?=?list.length;?i?<?len;?i++)?{?fun(list[i],?i);?}
};
var?Contains?=?function(a,?b){
????return?a.contains???a?!=?b?&&?a.contains(b)?:?!!(a.compareDocumentPosition(b)?&?16);
}
var?OverLay?=?Class.create();
OverLay.prototype?=?{
??initialize:?function(options)?{
????this.SetOptions(options);
????
????this.Lay?=?$(this.options.Lay)?||?document.body.insertBefore(document.createElement("div"),?document.body.childNodes[0]);
????
????this.Color?=?this.options.Color;
????this.Opacity?=?parseInt(this.options.Opacity);
????this.zIndex?=?parseInt(this.options.zIndex);
????
????with(this.Lay.style){?display?=?"none";?zIndex?=?this.zIndex;?left?=?top?=?0;?position?=?"fixed";?width?=?height?=?"100%";?}
????
????if(isIE6){
????????this.Lay.style.position?=?"absolute";
????????//ie6設置覆蓋層大小程序
????????this._resize?=?Bind(this,?function(){
????????????this.Lay.style.width?=?Math.max(document.documentElement.scrollWidth,?document.documentElement.clientWidth)?+?"px";
????????????this.Lay.style.height?=?Math.max(document.documentElement.scrollHeight,?document.documentElement.clientHeight)?+?"px";
????????});
????????//遮蓋select
????????this.Lay.innerHTML?=?'<iframe?style="position:absolute;top:0;left:0;width:100%;height:100%;filter:alpha(opacity=0);"></iframe>'
????}
??},
??//設置默認屬性
??SetOptions:?function(options)?{
????this.options?=?{//默認值
????????Lay:????????null,//覆蓋層對象
????????Color:????????"#fff",//背景色
????????Opacity:????50,//透明度(0-100)
????????zIndex:????????1000//層疊順序
????};
????Extend(this.options,?options?||?{});
??},
??//顯示
??Show:?function()?{
????//兼容ie6
????if(isIE6){?this._resize();?window.attachEvent("onresize",?this._resize);?}
????//設置樣式
????with(this.Lay.style){
????????//設置透明度
????????isIE???filter?=?"alpha(opacity:"?+?this.Opacity?+?")"?:?opacity?=?this.Opacity?/?100;
????????backgroundColor?=?this.Color;?display?=?"block";
????}
??},
??//關閉
??Close:?function()?{
????this.Lay.style.display?=?"none";
????if(isIE6){?window.detachEvent("onresize",?this._resize);?}
??}
};
var?LightBox?=?Class.create();
LightBox.prototype?=?{
??initialize:?function(box,?options)?{
????
????this.Box?=?$(box);//顯示層
????
????this.OverLay?=?new?OverLay(options);//覆蓋層
????
????this.SetOptions(options);
????
????this.Fixed?=?!!this.options.Fixed;
????this.Over?=?!!this.options.Over;
????this.Center?=?!!this.options.Center;
????this.onShow?=?this.options.onShow;
????
????this.Box.style.zIndex?=?this.OverLay.zIndex?+?1;
????this.Box.style.display?=?"none";
????
????//兼容ie6用的屬性
????if(isIE6){
????????this._top?=?this._left?=?0;?this._select?=?[];
????????this._fixed?=?Bind(this,?function(){?this.Center???this.SetCenter()?:?this.SetFixed();?});
????}
??},
??//設置默認屬性
??SetOptions:?function(options)?{
????this.options?=?{//默認值
????????Over:????true,//是否顯示覆蓋層
????????Fixed:????false,//是否固定定位
????????Center:????false,//是否居中
????????onShow:????function(){}//顯示時執行
????};
????Extend(this.options,?options?||?{});
??},
??//兼容ie6的固定定位程序
??SetFixed:?function(){
????this.Box.style.top?=?document.documentElement.scrollTop?-?this._top?+?this.Box.offsetTop?+?"px";
????this.Box.style.left?=?document.documentElement.scrollLeft?-?this._left?+?this.Box.offsetLeft?+?"px";
????
????this._top?=?document.documentElement.scrollTop;?this._left?=?document.documentElement.scrollLeft;
??},
??//兼容ie6的居中定位程序
??SetCenter:?function(){
????this.Box.style.marginTop?=?document.documentElement.scrollTop?-?this.Box.offsetHeight?/?2?+?"px";
????this.Box.style.marginLeft?=?document.documentElement.scrollLeft?-?this.Box.offsetWidth?/?2?+?"px";
??},
??//顯示
??Show:?function(options)?{
????//固定定位
????this.Box.style.position?=?this.Fixed?&&?!isIE6???"fixed"?:?"absolute";
????//覆蓋層
????this.Over?&&?this.OverLay.Show();
????
????this.Box.style.display?=?"block";
????
????//居中
????if(this.Center){
????????this.Box.style.top?=?this.Box.style.left?=?"50%";
????????//設置margin
????????if(this.Fixed){
????????????this.Box.style.marginTop?=?-?this.Box.offsetHeight?/?2?+?"px";
????????????this.Box.style.marginLeft?=?-?this.Box.offsetWidth?/?2?+?"px";
????????}else{
????????????this.SetCenter();
????????}
????}
????
????//兼容ie6
????if(isIE6){
????????if(!this.Over){
????????????//沒有覆蓋層ie6需要把不在Box上的select隱藏
????????????this._select.length?=?0;
????????????Each(document.getElementsByTagName("select"),?Bind(this,?function(o){
????????????????if(!Contains(this.Box,?o)){?o.style.visibility?=?"hidden";?this._select.push(o);?}
????????????}))
????????}
????????//設置顯示位置
????????this.Center???this.SetCenter()?:?this.Fixed?&&?this.SetFixed();
????????//設置定位
????????this.Fixed?&&?window.attachEvent("onscroll",?this._fixed);
????}
????
????this.onShow();
??},
??//關閉
??Close:?function()?{
????this.Box.style.display?=?"none";
????this.OverLay.Close();
????if(isIE6){
????????window.detachEvent("onscroll",?this._fixed);
????????Each(this._select,?function(o){?o.style.visibility?=?"visible";?});
????}
??}
};
使用說明:?
首先要有一個高亮層:
<style>
.lightbox{width:300px;background:#FFFFFF;border:1px?solid?#ccc;line-height:25px;?top:20%;?left:20%;}
.lightbox?dt{background:#f4f4f4;?padding:5px;}
</style>
<dl?id="idBox"?class="lightbox">
??<dt?id="idBoxHead"><b>LightBox</b>?</dt>
??<dd>
????內容顯示
????<br?/><br?/>
????<input?name=""?type="button"?value="?關閉?"?id="idBoxCancel"?/>
????<br?/><br?/>
??</dd>
</dl>
至于覆蓋層一般不需要另外設了,接著就可以實例化一個LightBox:
var?box?=?new?LightBox("idBox");
打開和關閉LightBox分別是Show()和Close()方法,
其中LightBox有下面幾個屬性:
屬性:默認值//說明
Over:true,//是否顯示覆蓋層
Fixed:false,//是否固定定位
Center:false,//是否居中
onShow:function(){}//顯示時執行
還有OverLay屬性是覆蓋層對象,它也有幾個屬性:
屬性:默認值//說明
Lay:null,//覆蓋層對象
Color:"#fff",//背景色
Opacity:50,//透明度(0-100)
zIndex:1000//層疊順序
完整實例下載
轉載于:https://www.cnblogs.com/top5/archive/2010/10/12/1848511.html
總結
以上是生活随笔為你收集整理的JavaScript 仿LightBox内容显示效果的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: DataGridView 添加Combo
- 下一篇: jQuery使用总结 - Core jQ