javascript html js仿LightBox內容顯示效果,div覆蓋層,鎖定頁面

來源:互聯網
上載者:User

javascript html js仿LightBox內容顯示效果,div覆蓋層,鎖定頁面

JS   2009-06-15 12:06   閱讀142   評論0   字型大小: 大   中   小 LightBox的效果(也有的叫Windows關機效果),不過不用那麼複雜,能顯示一個內容框就行了。就是一個覆蓋全屏的層,加一個內容顯示的層。用了position:fixed這個新特性

ps:“定位效果”的意思是螢幕滾動也能固定位置。

程式說明:

要實現一個簡單的LightBox效果,主要有兩個部分:覆蓋層和高亮層。

【跨瀏覽器的固定定位】

首先要先說說這個東西position:fixed,它的作用是跨瀏覽器的固定定位。

摘自詳解定位與定位應用:
“如讓一個元素可能隨著網頁的滾動而不斷改變自己在瀏覽器的位置。而現在我可以通過CSS中的一個定位屬性來實現這樣的一個效果,這個元素屬性就是曾經不被支援的position:fixed; 他的含義就是:固定定位。這個固定與絕對位置很像,唯一不同的是絕對位置是被固定在網頁中的某一個位置,而固定定位則是固定在瀏覽器的視框位置。”

程式中很多地方利用了這個css,ie7、ff都支援這個css,但ie6不支援,程式中只能是在ie6類比這個效果。

【覆蓋層】

覆蓋層的作用是把焦點限制在高亮層上,原理是通過一個絕對位置的層(通常使用div),設定它的寬度和高度以致能覆蓋整個螢幕(包括縮放和滾動瀏覽器的情況下),再給它設定一個比較高的zIndex來層疊在原有內容之上(但要比高亮層小),這樣使用者就只能點到這個層之上的內容了。

如果初始化時沒有提供覆蓋層對象,程式中會自動建立:

this.Lay = $(this.options.Lay) || document.body.insertBefore(document.createElement("div"), document.body.childNodes[0]);

其中由於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來修正滾屏參數:

this.Fixed && window.attachEvent("onscroll", this._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程式是這樣的:

var Contains = function(a, b){    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,我也不清楚。

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"><html xmlns="http://www.w3.org/1999/xhtml"><head><meta http-equiv="Content-Type" content="text/html; charset=gb2312" /><title>JavaScript 仿LightBox內容顯示效果</title></head><body><script>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"; }); }  }};</script><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><div style="margin:0 auto; width:800px; height:500px; border:1px solid #000000;"><input type="button" value="關閉覆蓋層" id="btnOverlay" /><input type="button" value="黑色覆蓋層" id="btnOverColor" /><input type="button" value="全透覆蓋層" id="btnOverOpacity" /><input type="button" value="定位效果" id="btnFixed" /><input type="button" value="置中效果" id="btnCenter" /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><select><option>覆蓋select測試</option></select> <input name="" type="button" value=" 開啟 " id="idBoxOpen" /></div><script>var box = new LightBox("idBox");$("idBoxCancel").onclick = function(){ box.Close(); }$("idBoxOpen").onclick = function(){ box.Show(); }$("btnOverlay").onclick = function(){ box.Close(); if(box.Over){  box.Over = false;  this.value = "開啟覆蓋層"; } else {  box.Over = true;  this.value = "關閉覆蓋層"; }}$("btnOverColor").onclick = function(){ box.Close(); box.Over = true; if(box.OverLay.Color == "#fff"){  box.OverLay.Color = "#000";  this.value = "白色覆蓋層"; } else {  box.OverLay.Color = "#fff"  this.value = "黑色覆蓋層"; }}$("btnOverOpacity").onclick = function(){ box.Close(); box.Over = true; if(box.OverLay.Opacity == 0){  box.OverLay.Opacity = 50;  this.value = "全透覆蓋層"; } else {  box.OverLay.Opacity = 0;  this.value = "半透覆蓋層"; }}$("btnFixed").onclick = function(){ box.Close(); if(box.Fixed){  box.Fixed = false;  this.value = "定位效果"; } else {  box.Fixed = true;  this.value = "取消定位"; }}$("btnCenter").onclick = function(){ box.Close(); if(box.Center){  box.Center = false;  box.Box.style.left = box.Box.style.top = "20%";  box.Box.style.marginTop = box.Box.style.marginLeft = "0";  this.value = "置中效果"; } else {  box.Center = true;  this.value = "重新置放"; }}</script></body></html>
http://blog.163.com/hanguokai1987/blog/static/2702258620095150646411/

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在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.