主页 > 编程资料 > C# >
发布时间:2015-09-26 作者:网络 阅读:212次

以下是HTML网页特效代码,点击运行按钮可查看效果:

程序说明:

要实现一个简单的LightBox效果,主要有两个部分:覆盖层和高亮层。
而拖放功能跟上面的程序是完全独立的,可自行添加。

【跨浏览器的固定定位】

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

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

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

【覆盖层】

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

【覆盖屏幕】

覆盖层的关键就是如何做到覆盖整个屏幕,支持position:fixed的话很简单:
this.Lay.style.position = "fixed";
this.Lay.style.width = this.Lay.style.height = "100%";

这样能把浏览器的视框覆盖了,其中使用了fixed样式,这里的意思是定位在浏览器的视框,并100%覆盖。
注意不要理解错为这个层覆盖了整个页面,它只是把浏览器可视的部分覆盖了来达到效果。
ie6不支持怎么办?有几个方法:
1,做一个覆盖视框的层,并在onscroll时相应移动,在onresize时重新设大小;
2,做一个覆盖视框的层,在样式上模拟fixed效果;
3,做一个层覆盖了整个页面的层,并在onresize时重新设大小;

方法1的缺点是滚动时很容易露出马脚,而且不好看;方法2的缺点是需要页面结构的改动和body样式的修改,绝对不是好的架构;而我用的是方法3,有更好的方法欢迎提出。

用这个方法只有把position设为absolute,并设置相应的width和height即可:

this.Lay.style.position = "absolute";
this._size = 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";
}.bind(this);

要注意的是scrollWidth和clientWidth的区别,顺带还有offsetWidth,手册上的说明:
scrollWidth:Retrieves the scrolling width of the object.
clientWidth:Retrieves the width of the object including padding, but not including margin, border, or scroll bar.
offsetWidth:Retrieves the width of the object relative to the layout or coordinate parent, as specified by the offsetParent property.

我的理解是:
scrollWidth是内容占的宽度,在有滚动条时相当于整个内容的宽度,在没有滚动条时仅仅只是内容部分宽度不包括补白部分。
clientWidth是可视部分宽度,在有滚动条时仅仅是可视部分的宽度,在没有滚动条时包括整个内容部分宽度加上可视范围内的补白部分。
offsetWidth是clientWidth可视部分宽度加上border和滚动条本身宽度。

这里一般情况下使用scrollWidth和clientWidth中比较大的值(即有滚动条时的scrollWidth和没有滚动条时的clientWidth)作为覆盖层的宽度就可以了,设宽度时是不包括滚动条部分的而documentElement一般也没有border,所以不需要offsetWidth。

上面可以看到我用的是documentElement而不是body,手册上是这样说的:
Retrieves a reference to the root node of the document.
意思是整个文档的根节点,其实就是html节点(body的上一级)。
在XHTML标准中对于整个文档的操作,一般应该使用documentElement而不使用body。

还要注意的是在onresize的时候scrollWidth和clientWidth的值会产生变化,所以需要在事件中重新设置宽度高度:
if(isIE6){ this._size(); window.attachEvent("onresize", this._size); }

【覆盖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的浏览器很简单,只要把position设为fixed就行了,这个样式本来就是这样用的,但可怜的ie6只能模拟了。

ie6模拟的原理是在onscroll事件中,不断根据滚动的距离修正top和left。
首先设置position未absolute,并记录当前scrollTop和scrollLeft的值,给onscroll事件添加定位函数_fixed:

this.Box.style.position = "absolute";
this._top = document.documentElement.scrollTop; this._left = document.documentElement.scrollLeft;
window.attachEvent("onscroll", this._fixed.bind(this));
其中_fixed函数是这样的:

var iTop =  document.documentElement.scrollTop - this._top + this.Box.offsetTop, iLeft = document.documentElement.scrollLeft - this._left + this.Box.offsetLeft;

this.Box.style.top = iTop + "px"; this.Box.style.left = iLeft + "px";

this._top = document.documentElement.scrollTop; this._left = document.documentElement.scrollLeft;
原理也很简单,就是把当前scrollTop减去_top值(上一个scrollTop值)再加上当前的offsetTop,就得到要设置的top值了。

【居中显示】

“居中显示”的意思是高亮层位于视框左右上下居中的位置。
实现这个有两个方法:
1,视框宽度减去高亮层宽度的一半就是居中需要的left值;
2,先设置left值为50%,然后marginLeft设为负的高亮层宽度的一半。

方法1相对方法2需要多一个视框宽度,但方法2设一个负的margin也可能会有很多意想不到的问题,毕竟margin这个样式比较特殊。不过我这里还是选择了方法2,尝试一下嘛。

还有一个问题是在ie6或不是固定定位的情况下(使用absolute定位的时候)需要加上scrollLeft来修正:

this.Box.style.top = this.Box.style.left = "50%";
//显示后才能获取
var iTop = - this.Box.offsetHeight / 2, iLeft = - this.Box.offsetWidth / 2;
//ie6或不是固定定位要修正
if(!this.Fixed || isIE6){ iTop += document.documentElement.scrollTop; iLeft += document.documentElement.scrollLeft; }
this.Box.style.marginTop =  iTop + "px"; this.Box.style.marginLeft = iLeft + "px";
还要注意offsetWidth需要在高亮层显示之后才能获取,所以定位程序需要放到高亮层显示之后。

由于使用了负值的margin,固定定位程序_fixed也需要修正一下:

if(this.Center){ iTop += this.Box.offsetHeight / 2; iLeft += this.Box.offsetWidth / 2; }

这是因为offsetLeft是不包含margin的,在设置left时必须把margin也算进去。

【比较文档位置】

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

Each(document.getElementsByTagName("select"), function(o){
    if(oThis.Box.contains ? !oThis.Box.contains(o) : !(oThis.Box.compareDocumentPosition(o) & 16)){
        o.style.visibility = "hidden"; oThis._select.push(o);
    }
})

JavaScript 自定义多级联动浮动菜单中提过这个东西,但没说明,这里稍微讲解一下。手册里是这样写的:
Checks whether the given element is contained within the object.
意思是检测所给对象是否包含在指定对象里面。注意如果所给对象就是指定对象本身也会返回true,虽然这样不太合理。
但contains只是ie的专有属性,不过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”时返回true,也就是只有NodeA包含NodeB时返回true(&是位“与”运算)。
这样可以写一个通用的contains方法:
a.contains ? a != b && a.contains(b) : !!(a.compareDocumentPosition(arg) & 16);
更详细的说明请看contains() for Mozilla。

关键字词: