JS 覆盖层 怎么实现的?

LightBox的效果(也有的叫Windows关机效果),不过不用那么复杂,能显示一个内容框就行了。就是一个覆盖全屏的层,加一个内容显示的层。用了position:fixed这个新特性

ps:“定位效果”的意思是屏幕滚动也能固定位置。

程序说明:

要实现一个简单的LightBox效果,主要有两个部分:覆盖层和高亮层。


【跨浏览器的固定定位】

首先要先说说这个东西position:fixed,它的作用是跨浏览器的固定定位。

摘自详解定位与定位应用:
“如让一个元素可能随着网页的滚动而不断改变自己在浏览器的位置。而现在我可以通过CSS中的一个定位属性来实现这样的一个效果,这个元素属性就 是曾经不被支持的position:fixed; 他的含义就是:固定定位。这个固定与绝对定位很像,唯一不同的是绝对定位是被固定在网页中的某一个位置,而固定定位则是固定在浏览器的视框位置。”

程序中很多地方利用了这个css,ie7、ff都支持这个css,但ie6不支持,程序中只能是在ie6模拟这个效果。

【覆盖层】

覆盖层的作用是把焦点限制在高亮层上,原理是通过一个绝对定位的层(通常使用div),设置它的宽度和高度以致能覆盖整个屏幕(包括缩放和滚动浏 览器的情况下),再给它设置一个比较高的zIndex来层叠在原有内容之上(但要比高亮层小),这样用户就只能点到这个层之上的内容了。

如果初始化时没有提供覆盖层对象,程序中会自动创建:

Js代码   收藏代码
  1. this.Lay = $(this.options.Lay) || document.body.insertBefore(document.createElement("div"), document.body.childNodes[0]);  


其中由于document.body.appendChild()导致IE已终止操作bug,所以用了insertBefore。。

【覆盖屏幕】

覆盖层的关键就是如何做到覆盖整个屏幕(锁定整个页面),支持position:fixed的话很简单:

Js代码   收藏代码
  1. 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即可:

Js代码   收藏代码
  1. this.Lay.style.position = "absolute";  
  2. this._resize = Bind(thisfunction(){  
  3.     this.Lay.style.width = Math.max(document.documentElement.scrollWidth, document.documentElement.clientWidth) + "px";  
  4.     this.Lay.style.height = Math.max(document.documentElement.scrollHeight, document.documentElement.clientHeight) + "px";  
  5. });  

要注意的是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(视框高度)。
而恰好两个情况都是取两者中比较大的值,所以就有了以下程序:

Js代码   收藏代码
  1. 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方法重新设置宽度高度:

Js代码   收藏代码
  1. 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了,程序中是这样使用的:

Js代码   收藏代码
  1. 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来修正滚屏参数:

Js代码   收藏代码
  1. this.Fixed && window.attachEvent("onscroll"this._fixed);  
定位函数_fixed是这样的:

Js代码   收藏代码
  1. this._fixed = Bind(thisfunction(){ this.Center ? this.SetCenter() : this.SetFixed(); });  


可以看出在_fixed中,当设置了居中显示时会执行SetCenter程序(后面会说明),否则就执行SetFixed程序。
先说说SetFixed程序的原理,就是把当前scrollTop减去_top值(上一个scrollTop值)再加上当前的offsetTop,就得到要设置的top值了:

Js代码   收藏代码
  1. this.Box.style.top = document.documentElement.scrollTop - this._top + this.Box.offsetTop + "px";  
  2. this.Box.style.left = document.documentElement.scrollLeft - this._left + this.Box.offsetLeft + "px";  
  3.    
  4. 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需要在高亮层显示之后才 能获取,所以定位程序需要放到高亮层显示之后:
Js代码   收藏代码
  1. this.Box.style.top = this.Box.style.left = "50%";  
  2. if(this.Fixed){  
  3.     this.Box.style.marginTop = - this.Box.offsetHeight / 2 + "px";  
  4.     this.Box.style.marginLeft = - this.Box.offsetWidth / 2 + "px";  
  5. }else{  
  6.     this.SetCenter();  
  7. }  


其中如果不是固定定位,需要用SetCenter程序来修正滚屏参数,SetCenter程序是这样的:

Js代码   收藏代码
  1. this.Box.style.marginTop = document.documentElement.scrollTop - this.Box.offsetHeight / 2 + "px";  
  2. this.Box.style.marginLeft = document.documentElement.scrollLeft - this.Box.offsetWidth / 2 + "px";  


【比较文档位置】

在ie6当不显示覆盖层时需要另外隐藏select,这里使用了“覆盖select”的方法1,值得留意的是这里加了个select是否在高亮层的判断:

Js代码   收藏代码
  1. this._select.length = 0;  
  2. Each(document.getElementsByTagName("select"), Bind(thisfunction(o){  
  3.     if(!Contains(this.Box, o)){ o.style.visibility = "hidden"this._select.push(o); }  
  4. }))  


其中Contains程序是这样的:

Js代码   收藏代码
  1. var Contains = function(a, b){  
  2.     return a.contains ? a != b && a.contains(b) : !!(a.compareDocumentPosition(b) & 16);  
  3. }  


作用是返回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,我也不清楚。



Js代码   收藏代码
  1. <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">  
  2. <html xmlns="http://www.w3.org/1999/xhtml">  
  3. <head>  
  4. <meta http-equiv="Content-Type" content="text/html; charset=gb2312" />  
  5. <title>JavaScript 仿LightBox内容显示效果</title>  
  6. </head>  
  7.   
  8. <body>  
  9.   
  10.   
  11.   
  12.   
  13.   
  14. <script>  
  15.   
  16. var isIE = (document.all) ? true : false;  
  17.   
  18. var isIE6 = isIE && ([/MSIE (\d)\.0/i.exec(navigator.userAgent)][0][1] == 6);  
  19.   
  20. var $ = function (id) {  
  21.     return "string" == typeof id ? document.getElementById(id) : id;  
  22. };  
  23.   
  24. var Class = {  
  25.     create: function() {  
  26.         return function() { this.initialize.apply(this, arguments); }  
  27.     }  
  28. }  
  29.   
  30. var Extend = function(destination, source) {  
  31.     for (var property in source) {  
  32.         destination[property] = source[property];  
  33.     }  
  34. }  
  35.   
  36. var Bind = function(object, fun) {  
  37.     return function() {  
  38.         return fun.apply(object, arguments);  
  39.     }  
  40. }  
  41.   
  42. var Each = function(list, fun){  
  43.     for (var i = 0, len = list.length; i < len; i++) { fun(list[i], i); }  
  44. };  
  45.   
  46. var Contains = function(a, b){  
  47.     return a.contains ? a != b && a.contains(b) : !!(a.compareDocumentPosition(b) & 16);  
  48. }  
  49.   
  50.   
  51. var OverLay = Class.create();  
  52. OverLay.prototype = {  
  53.   initialize: function(options) {  
  54.   
  55.     this.SetOptions(options);  
  56.       
  57.     this.Lay = $(this.options.Lay) || document.body.insertBefore(document.createElement("div"), document.body.childNodes[0]);  
  58.       
  59.     this.Color = this.options.Color;  
  60.     this.Opacity = parseInt(this.options.Opacity);  
  61.     this.zIndex = parseInt(this.options.zIndex);  
  62.       
  63.     with(this.Lay.style){ display = "none"; zIndex = this.zIndex; left = top = 0; position = "fixed"; width = height = "100%"; }  
  64.       
  65.     if(isIE6){  
  66.         this.Lay.style.position = "absolute";  
  67.         //ie6设置覆盖层大小程序  
  68.         this._resize = Bind(thisfunction(){  
  69.             this.Lay.style.width = Math.max(document.documentElement.scrollWidth, document.documentElement.clientWidth) + "px";  
  70.             this.Lay.style.height = Math.max(document.documentElement.scrollHeight, document.documentElement.clientHeight) + "px";  
  71.         });  
  72.         //遮盖select  
  73.         this.Lay.innerHTML = '<iframe style="position:absolute;top:0;left:0;width:100%;height:100%;filter:alpha(opacity=0);"></iframe>'  
  74.     }  
  75.   },  
  76.   //设置默认属性  
  77.   SetOptions: function(options) {  
  78.     this.options = {//默认值  
  79.         Lay:        null,//覆盖层对象  
  80.         Color:      "#fff",//背景色  
  81.         Opacity:    50,//透明度(0-100)  
  82.         zIndex:     1000//层叠顺序  
  83.     };  
  84.     Extend(this.options, options || {});  
  85.   },  
  86.   //显示  
  87.   Show: function() {  
  88.     //兼容ie6  
  89.     if(isIE6){ this._resize(); window.attachEvent("onresize"this._resize); }  
  90.     //设置样式  
  91.     with(this.Lay.style){  
  92.         //设置透明度  
  93.         isIE ? filter = "alpha(opacity:" + this.Opacity + ")" : opacity = this.Opacity / 100;  
  94.         backgroundColor = this.Color; display = "block";  
  95.     }  
  96.   },  
  97.   //关闭  
  98.   Close: function() {  
  99.     this.Lay.style.display = "none";  
  100.     if(isIE6){ window.detachEvent("onresize"this._resize); }  
  101.   }  
  102. };  
  103.   
  104.   
  105.   
  106. var LightBox = Class.create();  
  107. LightBox.prototype = {  
  108.   initialize: function(box, options) {  
  109.       
  110.     this.Box = $(box);//显示层  
  111.       
  112.     this.OverLay = new OverLay(options);//覆盖层  
  113.       
  114.     this.SetOptions(options);  
  115.       
  116.     this.Fixed = !!this.options.Fixed;  
  117.     this.Over = !!this.options.Over;  
  118.     this.Center = !!this.options.Center;  
  119.     this.onShow = this.options.onShow;  
  120.       
  121.     this.Box.style.zIndex = this.OverLay.zIndex + 1;  
  122.     this.Box.style.display = "none";  
  123.       
  124.     //兼容ie6用的属性  
  125.     if(isIE6){  
  126.         this._top = this._left = 0; this._select = [];  
  127.         this._fixed = Bind(thisfunction(){ this.Center ? this.SetCenter() : this.SetFixed(); });  
  128.     }  
  129.   },  
  130.   //设置默认属性  
  131.   SetOptions: function(options) {  
  132.     this.options = {//默认值  
  133.         Over:   true,//是否显示覆盖层  
  134.         Fixed:  false,//是否固定定位  
  135.         Center: false,//是否居中  
  136.         onShow: function(){}//显示时执行  
  137.     };  
  138.     Extend(this.options, options || {});  
  139.   },  
  140.   //兼容ie6的固定定位程序  
  141.   SetFixed: function(){  
  142.     this.Box.style.top = document.documentElement.scrollTop - this._top + this.Box.offsetTop + "px";  
  143.     this.Box.style.left = document.documentElement.scrollLeft - this._left + this.Box.offsetLeft + "px";  
  144.       
  145.     this._top = document.documentElement.scrollTop; this._left = document.documentElement.scrollLeft;  
  146.   },  
  147.   //兼容ie6的居中定位程序  
  148.   SetCenter: function(){  
  149.     this.Box.style.marginTop = document.documentElement.scrollTop - this.Box.offsetHeight / 2 + "px";  
  150.     this.Box.style.marginLeft = document.documentElement.scrollLeft - this.Box.offsetWidth / 2 + "px";  
  151.   },  
  152.   //显示  
  153.   Show: function(options) {  
  154.     //固定定位  
  155.     this.Box.style.position = this.Fixed && !isIE6 ? "fixed" : "absolute";  
  156.   
  157.     //覆盖层  
  158.     this.Over && this.OverLay.Show();  
  159.       
  160.     this.Box.style.display = "block";  
  161.       
  162.     //居中  
  163.     if(this.Center){  
  164.         this.Box.style.top = this.Box.style.left = "50%";  
  165.         //设置margin  
  166.         if(this.Fixed){  
  167.             this.Box.style.marginTop = - this.Box.offsetHeight / 2 + "px";  
  168.             this.Box.style.marginLeft = - this.Box.offsetWidth / 2 + "px";  
  169.         }else{  
  170.             this.SetCenter();  
  171.         }  
  172.     }  
  173.       
  174.     //兼容ie6  
  175.     if(isIE6){  
  176.         if(!this.Over){  
  177.             //没有覆盖层ie6需要把不在Box上的select隐藏  
  178.             this._select.length = 0;  
  179.             Each(document.getElementsByTagName("select"), Bind(thisfunction(o){  
  180.                 if(!Contains(this.Box, o)){ o.style.visibility = "hidden"this._select.push(o); }  
  181.             }))  
  182.         }  
  183.         //设置显示位置  
  184.         this.Center ? this.SetCenter() : this.Fixed && this.SetFixed();  
  185.         //设置定位  
  186.         this.Fixed && window.attachEvent("onscroll"this._fixed);  
  187.     }  
  188.       
  189.     this.onShow();  
  190.   },  
  191.   //关闭  
  192.   Close: function() {  
  193.     this.Box.style.display = "none";  
  194.     this.OverLay.Close();  
  195.     if(isIE6){  
  196.         window.detachEvent("onscroll"this._fixed);  
  197.         Each(this._select, function(o){ o.style.visibility = "visible"; });  
  198.     }  
  199.   }  
  200. };  
  201.   
  202. </script>  
  203.   
  204.   
  205. <style>  
  206. .lightbox{width:300px;background:#FFFFFF;border:1px solid #ccc;line-height:25px; top:20%; left:20%;}  
  207. .lightbox dt{background:#f4f4f4; padding:5px;}  
  208. </style>  
  209.   
  210. <dl id="idBox" class="lightbox">  
  211.   <dt id="idBoxHead"><b>LightBox</b> </dt>  
  212.   <dd>  
  213.     内容显示  
  214.     <br /><br />  
  215.     <input name="" type="button" value=" 关闭 " id="idBoxCancel" />  
  216.     <br /><br />  
  217.   </dd>  
  218. </dl>  
  219.   
  220.   
  221. <div style="margin:0 auto; width:800px; height:500px; border:1px solid #000000;">  
  222.   
  223. <input type="button" value="关闭覆盖层" id="btnOverlay" />  
  224. <input type="button" value="黑色覆盖层" id="btnOverColor" />  
  225. <input type="button" value="全透覆盖层" id="btnOverOpacity" />  
  226. <input type="button" value="定位效果" id="btnFixed" />  
  227. <input type="button" value="居中效果" id="btnCenter" />  
  228. <br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br />  
  229. <select>  
  230. <option>覆盖select测试</option>  
  231. </select>   
  232. <input name="" type="button" value=" 打开 " id="idBoxOpen" />  
  233.   
  234. </div>  
  235.   
  236.   
  237.   
  238. <script>  
  239.   
  240. var box = new LightBox("idBox");  
  241.   
  242. $("idBoxCancel").onclick = function(){ box.Close(); }  
  243. $("idBoxOpen").onclick = function(){ box.Show(); }  
  244.   
  245. $("btnOverlay").onclick = function(){  
  246.     box.Close();  
  247.     if(box.Over){  
  248.         box.Over = false;  
  249.         this.value = "打开覆盖层";  
  250.     } else {  
  251.         box.Over = true;  
  252.         this.value = "关闭覆盖层";  
  253.     }  
  254. }  
  255.   
  256. $("btnOverColor").onclick = function(){  
  257.     box.Close();  
  258.     box.Over = true;  
  259.     if(box.OverLay.Color == "#fff"){  
  260.         box.OverLay.Color = "#000";  
  261.         this.value = "白色覆盖层";  
  262.     } else {  
  263.         box.OverLay.Color = "#fff"  
  264.         this.value = "黑色覆盖层";  
  265.     }  
  266. }  
  267.   
  268. $("btnOverOpacity").onclick = function(){  
  269.     box.Close();  
  270.     box.Over = true;  
  271.     if(box.OverLay.Opacity == 0){  
  272.         box.OverLay.Opacity = 50;  
  273.         this.value = "全透覆盖层";  
  274.     } else {  
  275.         box.OverLay.Opacity = 0;  
  276.         this.value = "半透覆盖层";  
  277.     }  
  278. }  
  279.   
  280. $("btnFixed").onclick = function(){  
  281.     box.Close();  
  282.     if(box.Fixed){  
  283.         box.Fixed = false;  
  284.         this.value = "定位效果";  
  285.     } else {  
  286.         box.Fixed = true;  
  287.         this.value = "取消定位";  
  288.     }  
  289. }  
  290.   
  291. $("btnCenter").onclick = function(){  
  292.     box.Close();  
  293.     if(box.Center){  
  294.         box.Center = false;  
  295.         box.Box.style.left = box.Box.style.top = "20%";  
  296.         box.Box.style.marginTop = box.Box.style.marginLeft = "0";  
  297.         this.value = "居中效果";  
  298.     } else {  
  299.         box.Center = true;  
  300.         this.value = "重新定位";  
  301.     }  
  302. }  
  303. </script>  
  304.   
  305. </body>  
  306. </html>  



转自:http://www.cnblogs.com/cloudgamer/archive/2008/09/15/1290954.html

黑色头发:http://heisetoufa.iteye.com/
  • JS 覆盖层 怎么实现的?_第1张图片
  • 大小: 9.7 KB
  • LightBox.rar (2.7 KB)

你可能感兴趣的:(JS 覆盖层 怎么实现的?)