Javascript公共脚本库系列(一): 弹出层脚本


Posted in Javascript onFebruary 24, 2011

一.摘要
本系列文章是为了抽象通用的,跨浏览器的脚本方法.

本篇文章讲解弹出浮动层的javascript函数, 以及函数的原理和使用注意事项.

二.实现效果
用脚本弹出浮动层是我们最常用的脚本方法之一.下面是效果图:

Javascript公共脚本库系列(一): 弹出层脚本 
点击图中的"航空公司"后,会在"航空公司"下面弹出浮动层.

在网上弹出框的脚本相当多, 而且还有各种第三方JS框架可供我们使用.但是其中有的脚本过于简单,仅仅粗略的实现弹出效果而忽略了灵活性,通用性和跨浏览器特性. 使用JS框架又有些杀鸡用牛刀.所以在收集整理了一些资料后, 写出了下文中的ScriptHelper类的弹出层方法.

主要特点有:
支持多浏览器
使用面向对象方法封装
使用简单,通用性强.
将计算位置等函数进行提取, 所有的相关函数都可以单独调用, 可根据具体项目继续二次开发.
三.脚本方法
下面我先将脚本方法贡献出来,然后举例如何使用. 最后讲解脚本的原理.

/* ==================== ScriptHelper 开始 ==================== */ 
/* scriptHelper 脚本帮助对象. 
创建人: ziqiu.zhang 2008.3.5 
添加函数: 
getScroll():得到鼠标滚过的距离-兼容XHTML 
getClient():得到浏览器当前显示区域的大小-兼容XHTML 
showDivCommon():显示图层. 
使用举例: 
<div id="testDiv" style="display:none; position:absolute; border:1px #000000;">我是测试图层我是测试图层</div> 
<div style="width:400px; text-align:center;"><div><a href="#" onclick="ScriptHelper.showDivCommon(this,'testDiv', 20, 70)">事件源</a></div></div> 
*/ 
function scriptHelper() 
{ 
} // 得到鼠标滚过的距离 scrollTop 与 scrollLeft 
/* 用法与测试: 
var myScroll = getScroll(); 
alert("myScroll.scrollTop:" + myScroll.scrollTop); 
alert("myScroll.scrollLeft:" + myScroll.scrollLeft); 
*/ 
scriptHelper.prototype.getScroll = function () 
{ 
var scrollTop = 0, scrollLeft = 0; 
scrollTop = (document.body.scrollTop > document.documentElement.scrollTop)? document.body.scrollTop:document.documentElement.scrollTop; 
if( isNaN(scrollTop) || scrollTop <0 ){ scrollTop = 0 ;} 
scrollLeft = (document.body.scrollLeft > document.documentElement.scrollLeft )? document.body.scrollLeft:document.documentElement.scrollLeft; 
if( isNaN(scrollLeft) || scrollLeft <0 ){ scrollLeft = 0 ;} 
return { scrollTop:scrollTop, scrollLeft: scrollLeft}; 
} 
// 得到浏览器当前显示区域的大小 clientHeight 与 clientWidth 
/* 用法与测试: 
var myScroll = getScroll(); 
alert("myScroll.sTop:" + myScroll.sTop); 
alert("myScroll.sLeft:" + myScroll.sLeft); 
*/ 
scriptHelper.prototype.getClient = function () 
{ 
//判断页面是否符合XHTML标准 
var isXhtml = true; 
if( document.documentElement == null || document.documentElement.clientHeight <= 0) 
{ 
if( document.body.clientHeight>0 ) 
{ 
isXhtml = false; 
} 
} 
this.clientHeight = isXhtml?document.documentElement.clientHeight:document.body.clientHeight; 
this.clientWidth = isXhtml?document.documentElement.clientWidth:document.body.clientWidth; 
return {clientHeight:this.clientHeight,clientWidth:this.clientWidth}; 
} 
// 显示图层,再次调用则隐藏 
/* 参数说明: 
sObj : 要弹出图层的事件源 
divId : 要显示的图层ID 
sObjHeight : 事件源的高度,默认为20.需要手工传入是因为对于由于事件源对象可能是各种HTML元素,有些元素高度的计算无法跨浏览器通用. 
moveLeft : 手工向左移动的距离.不移动则为0(默认). 
divObjHeight: 弹出层的高度.如果传入大于0的此参数, 则当事件源下方空间不足时,在事件源上方弹出层.如果不传此参数则一直在事件源下方弹出. 
用法与测试: 
<div><a href="#" onclick="ScriptHelper.showDivCommon(this,'testDiv', 20, 20)">事件源</a></div> 
*/ 
scriptHelper.prototype.showDivCommon = function (sObj,divId, sObjHeight, moveLeft, divObjHeight) 
{ 
//取消冒泡事件 
if( typeof(window)!='undefined' && window != null && window.event != null ) 
{ 
window.event.cancelBubble = true; 
} 
else if( ScriptHelper.showDivCommon.caller.arguments[0] != null ) 
{ 
ScriptHelper.showDivCommon.caller.arguments[0].cancelBubble = true; 
} 
//参数检测.如果没有传入参数则设置默认值 
if( moveLeft == null ) 
{ 
moveLeft = 0; 
} 
if( sObjHeight == null ) 
{ 
sObjHeight = 20; 
} 
if(divObjHeight == null) 
{ 
divObjHeight = 0; 
} 
var divObj = document.getElementById(divId); //获得图层对象 
var sObjOffsetTop = 0; //事件源的垂直距离 
var sObjOffsetLeft = 0; //事件源的水平距离 
var myClient = this.getClient(); 
var myScroll = this.getScroll(); 
var sWidth = sObj.width; //事件源对象的宽度 
var sHeight = sObjHeight; //事件源对象的高度 
var bottomSpace; //距离底部的距离 
/* 获取事件源控件的高度和宽度.*/ 
if( sWidth == null ) 
{ 
sWidth = 100;//无法获取则为100 
} 
else 
{ 
sWidth = sWidth + 1; //留出1px的距离 
} 
if( divObj.style.display.toLowerCase() != "none" ) 
{ 
//隐藏图层 
divObj.style.display = "none"; 
} 
else 
{ 
if( sObj == null ) 
{ 
alert("事件源对象为null"); 
return false; 
} 
/* 获取事件源对象的偏移量 */ 
var tempObj = sObj; //用于计算事件源坐标的临时对象 
while( tempObj && tempObj.tagName.toUpperCase() != "BODY" ) 
{ 
sObjOffsetTop += tempObj.offsetTop; 
sObjOffsetLeft += tempObj.offsetLeft; 
tempObj = tempObj.offsetParent; 
} 
tempObj = null; 
/* 获取距离底部的距离 */ 
bottomSpace = parseInt(myClient.clientHeight) - ( parseInt(sObjOffsetTop) - parseInt(myScroll.scrollTop)) - parseInt(sHeight); 
/* 设置图层显示位置 */ 
//如果事件源下方空间不足且上方控件足够容纳弹出层,则在上方显示.否则在下方显示 
if( divObjHeight>0 && bottomSpace < divObjHeight && sObjOffsetTop >divObjHeight ) 
{ 
divObj.style.top = ( parseInt( sObjOffsetTop ) - parseInt( divObjHeight ) - 10).toString() + "px"; 
} 
else 
{ 
divObj.style.top = ( parseInt( sObjOffsetTop ) + parseInt( sHeight ) ).toString() + "px"; 
} 
divObj.style.left = ( parseInt( sObjOffsetLeft ) - parseInt( moveLeft ) ).toString() + "px"; 
divObj.style.display="block"; 
} 
} 
// 关闭图层 
/* 参数说明: 
divId : 要隐藏的图层ID 
用法与测试: 
ScriptHelper.closeDivCommon('testDiv'); 
*/ 
scriptHelper.prototype.closeDivCommon = function (divId) 
{ 
// 
var divObj = document.getElementById(divId); //获得图层对象 
if( divObj != null ) 
{ 
divObj.style.display = "none"; 
} 
} 
//建立scriptHelper类的一个实例对象.全局使用. 
var ScriptHelper = new scriptHelper(); 
/* ==================== ScriptHelper 结束 ==================== */

四.使用举例
接下来我们创建HTML页面演示如何使用此脚本.此实例是一个菜单,当点击时显示子菜单图层.
1.引用脚本文件
将上面的代码保存在ScriptHelper.js文件中.在页面中添加引用:
<script src="http://files.cnblogs.com/zhangziqiu/ScriptHelper.js" type="text/javascript" defer="defer"></script>
2.编写子菜单
先编写两个子菜单图层.
<!-- Sub Menu 1 --> 
<div id="subMenu1" style="position:absolute; display:none; background-color:#D7EFCD; border:solid 1px #000000; margin:0px; padding:5px; height:100px;"> 
<div>1-1</div> 
<div>1-2</div> 
</div> 
<!-- Sub Menu 2 --> 
<div id="subMenu2" style="position:absolute; display:none; background-color:#D7EFCD; border:solid 1px #000000; padding:5px;" > 
<div>2-1</div> 
<div>2-2</div> 
</div>

对于子菜单, 最重要的就是要设置两个样式:position和display.
position:absolute 让此图层能够精确定位显示.从而控制他的显示位置.
display:none 让图层在加载时不显示.
3.编写主菜单
主菜单代码如下:
<!-- Main Menu --> 
<div > 
<a class="cursorHand" onclick="ScriptHelper.showDivCommon(this,'subMenu1', 20, 0, 100)">Menu1</a> 
<a class="cursorHand" onclick="ScriptHelper.showDivCommon(this,'subMenu2', 20, 0)">Menu2</a> 
<a class="cursorHand" href="#">NoSubMenu</a> 
</div>

我们创建了三个菜单.其中Menu1和Menu2拥有子菜单, NoSubMenu没有子菜单.
我们使用了a元素创建菜单对象, 但是因为没有为其添加href属性,所以默认情况下鼠标放上去不会变成hand图形.需要为其添加样式cursorHand,次样式的代码如下:
<style type="text/css">
.cursorHand { cursor:pointer;}
</style>
最关键的是为菜单添加的onclick事件, 此事件调用ScriptHelper.showDivCommon方法用于显示图层.
方法第一个参数值为this表示将事件源对象传入, 在函数中会根据事件源计算显示位置.
方法第二个参数表示弹出图的Id
方法第三个参数是可选参数, 用于设置向下的偏移量.因为我们计算的位置是"<a>Menu1</a>"这个元素的左上角坐标.需要设置一个向下的偏移量.一般设置为事件源的高度,默认为20px.
方法第四个参数是可选参数,用于设置向左的偏移量.原因同上.默认为0px;
方法第五个参数是可选参数,需要传入弹出层的高度.如果使用了此属性则弹出层可能弹出在事件源上方.不传递此属性则始终在事件源下方弹出图层.
4.效果与完整代码

Javascript公共脚本库系列(一): 弹出层脚本 
完整实例代码如下:

<!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> 
<title>ScriptHelper 类测试页面</title> 
<script src="http://files.cnblogs.com/zhangziqiu/ScriptHelper.js" type="text/javascript" defer="defer"></script> 
<style type="text/css"> 
.cursorHand { cursor:pointer;} 
</style> 
</head> 
<body style="position:relative;"> 
<div style="height:200px;"></div> 
<!-- Main Menu --> 
<div > 
<a class="cursorHand" onclick="ScriptHelper.showDivCommon(this,'subMenu1', 20, 0, 100)">Menu1</a> 
<a class="cursorHand" onclick="ScriptHelper.showDivCommon(this,'subMenu2', 20, 0)">Menu2</a> 
<a class="cursorHand" href="#">NoSubMenu</a> 
</div> 
<!-- Sub Menu 1 --> 
<div id="subMenu1" style="position:absolute; display:none; background-color:#D7EFCD; border:solid 1px #000000; margin:0px; padding:5px; height:100px;"> 
<div>1-1</div> 
<div>1-2</div> 
</div> 
<!-- Sub Menu 2 --> 
<div id="subMenu2" style="position:absolute; display:none; background-color:#D7EFCD; border:solid 1px #000000; padding:5px;" > 
<div>2-1</div> 
<div>2-2</div> 
</div> 
</body> 
</html>

五.注意事项:
1.要给Body元素加上position:relative样式:
<body style="position:relative;">
不增加的话在IE6下有时会出现无法精确定位事件源的情况.比如在menu的<div>上添加几个<br/>,则弹出层的位置就发生错误了.
如果在Body元素上增加此样式仍然弹出位置错误,则请在事件源对象的容器元素中也添加此样式
2.不传递最后一个参数则弹出层只在事件源下面弹出.否则将会计算事件源底部的举例, 如果底部控件不足并且上部控件充足,则弹出层显示在事件源上方.
3.在页面上要添加DOCTYPE元素.不添加的话很可能在某些浏览器中出现错误.有关DOCTYPE的作用,请查看下面的文章:
DOCTYPE元素解析
六.总结
兼容多浏览器真的是一件让人头疼的事情.我估计此函数还是会有问题.本来想写脚本分析的, 但是在写作的时候又发现了一些Bug并且进行了修正.兼容来兼容去最后把自己兼容晕了.其实如果一个项目能使用脚本库将会是一个很好的选择.本系列文章只是希望构建一个轻量级的脚本类库.大家使用中有任何问题希望多多交流, 一起打造简单易用的脚本库!
Javascript 相关文章推荐
jquery select(列表)的操作(取值/赋值)
Aug 06 Javascript
通过身份证号得到出生日期和性别的js代码
Nov 23 Javascript
学习JavaScript的最佳方法分享
Oct 21 Javascript
JSON取值前判断
Dec 23 Javascript
详解Angular开发中的登陆与身份验证
Jul 27 Javascript
用瀑布流的方式在网页上插入图片的简单实现方法
Sep 23 Javascript
JavaScript自定义浏览器滚动条兼容IE、 火狐和chrome
Jan 05 Javascript
JS使用JSON.parse(),JSON.stringify()实现对对象的深拷贝功能分析
Mar 06 Javascript
详解Vue后台管理系统开发日常总结(组件PageHeader)
Nov 01 Javascript
angularjs模态框的使用代码实例
Dec 20 Javascript
Vue 组件注册全解析
Dec 17 Vue.js
如何利用React实现图片识别App
Feb 18 Javascript
从零开始学习jQuery (十一) 实战表单验证与自动完成提示插件
Feb 23 #Javascript
从零开始学习jQuery (十) jQueryUI常用功能实战
Feb 23 #Javascript
从零开始学习jQuery (八) 插播:jQuery实施方案
Feb 23 #Javascript
从零开始学习jQuery (六) jquery中的AJAX使用
Feb 23 #Javascript
从零开始学习jQuery (四) jQuery中操作元素的属性与样式
Feb 23 #Javascript
从零开始学习jQuery (三) 管理jQuery包装集
Feb 23 #Javascript
jQuery的学习步骤
Feb 23 #Javascript
You might like
锁定年轻人的双倍活力 星巴克推出星倍醇即饮浓咖啡
2021/03/03 咖啡文化
PHP使用CURL获取302跳转后的地址实例
2014/05/04 PHP
Yii中CGridView关联表搜索排序方法实例详解
2014/12/03 PHP
PHP 返回数组后处理方法(开户成功后弹窗提示)
2017/07/03 PHP
javascript中的prototype属性实例分析说明
2010/08/09 Javascript
你必须知道的Javascript知识点之&quot;this指针&quot;的应用
2013/04/23 Javascript
JavaScript中的异常捕捉介绍
2014/12/31 Javascript
使用命令对象代替switch语句的写法示例
2015/02/28 Javascript
JavaScript中的this关键字使用方法总结
2015/03/13 Javascript
jQuery插件Elastislide实现响应式的焦点图无缝滚动切换特效
2015/04/12 Javascript
自己动手写的jquery分页控件(非常简单实用)
2015/10/28 Javascript
react native带索引的城市列表组件的实例代码
2017/08/08 Javascript
js实现扫雷小程序的示例代码
2017/09/27 Javascript
微信小程序实战篇之购物车的实现代码示例
2017/11/30 Javascript
Angular搜索场景中使用rxjs的操作符处理思路
2018/05/30 Javascript
vue移动端下拉刷新和上拉加载的实现代码
2018/09/08 Javascript
[02:31]《DAC最前线》之选手酒店现场花絮
2015/01/30 DOTA
python删除指定类型(或非指定)的文件实例详解
2015/07/06 Python
详解Python读取配置文件模块ConfigParser
2017/05/11 Python
浅谈pyhton学习中出现的各种问题(新手必看)
2017/05/17 Python
python3结合openpyxl库实现excel操作的实例代码
2018/09/11 Python
Python爬虫基础之XPath语法与lxml库的用法详解
2018/09/13 Python
Pytorch实现的手写数字mnist识别功能完整示例
2019/12/13 Python
python3.8.1+selenium实现登录滑块验证功能
2020/05/22 Python
HTML5 实战PHP之Web页面表单设计
2011/10/09 HTML / CSS
SkinCeuticals官网:美国药妆品牌
2018/04/19 全球购物
Electric官网:美国高级眼镜和配件品牌
2020/06/04 全球购物
写clone()方法时,通常都有一行代码,是什么?
2012/10/31 面试题
电子技术专业中专生的自我评价
2013/12/17 职场文书
建筑班组长岗位职责
2014/01/02 职场文书
汽车技术服务英文求职信范文
2014/01/02 职场文书
甜美蛋糕店创业计划书
2014/01/30 职场文书
打架检讨书2000字
2014/02/22 职场文书
入党介绍人评语
2014/05/06 职场文书
希特勒经典演讲稿
2014/05/19 职场文书
药剂专业求职信
2014/06/20 职场文书