用 javascript 获取当页面上鼠标(光标)位置

用 javascript 获取当页面上鼠标(光标)位置在许多情况下都会用到,比如拖放,悬停提示(tooltip) 等等。当然,这里我们依然要面对浏览器的兼容问题,在不同的浏览器下,对这些相关的属性处理方式也不同,本文详细介绍了浏览器在处理这些属性时的差异和最终的解决方法。

用 javascript 获取当页面上鼠标(光标)位置 – 示例

 
<script type="text/javascript">
 
// 说明:获取鼠标位置
// 整理:http://www.codebit.cn
// 来源:http://www.webreference.com
 
function mousePosition(ev){
	if(ev.pageX || ev.pageY){
		return {x:ev.pageX, y:ev.pageY};
	}
	return {
		x:ev.clientX + document.body.scrollLeft - document.body.clientLeft,
		y:ev.clientY + document.body.scrollTop  - document.body.clientTop
	};
}
 
</script>

上面的代码我们在 怎么用 javascript 实现拖拽 中已经介绍过了,由于这个需求我们经常用到,所以我们将这段代码独立成一篇文章,供新手查询。

使用方式:

 
 
document.onmousemove = mouseMove;
 
function mouseMove(ev){
	ev = ev || window.event;
	var mousePos = mousePosition(ev);
}

关于代码的详细说明,原文中已经介绍,现转到此处:

我们首先要声明一个 evnet 对象,无论移动、点击、按键等,都会激活一个 evnet ,在 Internet Explorer 里, event 是全局变量,会被存储在 window.event 里. 在 firefox 或者其他浏览器,event 会被相应的函数获取.当我们将mouseMove函数赋值于document.onmousemove,mouseMove 会获取鼠标移动事件。

为了让 ev 在所有浏览器下获取了 event 事件,在Firefox下"||window.event"将不起作用,因为ev已经有了赋值。在 MSIE 中 ev 为空,所以得到 window.event 。

因为在这篇文章中我们需要多次获取鼠标位置,所以我们设计了一个 mousePosition 函数,它包含一个参数 : event 。

因为我们要在 MSIE 和其他浏览器下运行,Firefox 和其他浏览器用 event.pageX 和 event.pageY 来表示鼠标相对于文档的位置,如果你有一个 500*500 的窗口并且你的鼠标在绝对中间,那么 pageX 和 pageY 的值都是 250,如果你向下滚动 500, 那么 pageY 将变成 750。

MSIE 正好相反,它使用 event.clientX 和 event.clientY 表示鼠标相当于窗口的位置,而不是文档。在同样的例子中,如果你向下滚动500,clientY 依然是 250,因此,我们需要添加 scrollLeft 和 scrollTop 这两个相对于文档的属性。最后,MSIE 中文档并不是从 0,0 开始,而是通常有一个小的边框(通常是 2 象素),边框的大小定义在 document.body.clientLeft 和 clientTop 中,我们也把这些加进去。

很幸运,我们现在已经用 mousePosition 函数解决了坐标问题,不需为此费心了。

Javascript 获取浏览器窗口中文档(视口)可用尺寸的方法

由于浏览器的差异,许多信息的获取都要考虑兼容性,窗口中文档可用尺寸是一个经常需要用到的信息,由于浏览器不同甚至版本不同,获取的方法也不一样,本文介绍的函数能够兼容各种浏览器,获取这一信息。同时,文章中对浏览器处理这一信息的差异也做了详细说明。

Javascript 获取浏览器窗口中文档(视口)可用尺寸的方法 – 示例

本文所说的“浏览器窗口中文档(下面简称“视口”)可用尺寸”指浏览器中文档显示区域的尺寸,不包括标题栏、工具栏、滚动条等内容。

在处理这一信息时,不同浏览器和同一浏览器不同版本中有一些差别,说明如下:

(1)在 IE4、IE5 和 没有声明 DOCTYPE 的 IE6 中,视口的这一信息保存在“body”元素中,可以用 document.body.offsetWidth / offsetHeight 获取,

(2)在声明了DOCTYPE 的 IE6 中 ,视口的这一信息保存在 document.documentElement 中,可以用 document.documentElement.clientWidth / clientHeight 获取。

(3)除了 IE 以外的所有浏览器都将此信息保存在 window 对象中,可以用 window.innerWidth / innerHeight 获取。

因此,综合上面的说明,我们可以用下面的方式获取浏览器窗口中文档(视口)可用尺寸:

 
<script type="text/javascript">
// 说明:Javascript 获取浏览器窗口中文档(视口)可用尺寸的方法
// 整理:http://www.CodeBit.cn

function getViewportInfo()
{
	var w = (window.innerWidth) ? window.innerWidth : (document.documentElement && document.documentElement.clientWidth) ? document.documentElement.clientWidth : document.body.offsetWidth;
	var h = (window.innerHeight) ? window.innerHeight : (document.documentElement && document.documentElement.clientHeight) ? document.documentElement.clientHeight : document.body.offsetHeight;
	return {w:w,h:h};
};
</script>

注意!这一信息的获取时临时的,当浏览器窗口本身大小被改变时,此信息也将跟随改变!

Frames : 一个特殊的窗口类型

许多初学者在处理 frame 时往往会出现这样或那样的错误,其实,frame 是一个特殊的窗口类型,只要明白了他们之间的关系,可以很容易控制,本文摘译自 JavaScript 2.0-The Complete Reference 一书的英文第二版(仅摘录了对理解 frame 有直接关系的章节),文章详细介绍了 frame ,相信对新手理解 frame 会有很大帮助。

对 window 和 frame 关系的错误理解是web开发者中普遍存在的问题,从 (x) html 和 Javascript 来看,每个窗口中显示的 frame 都能很容易的控制,事实上,当一个 window 有多个 frame , 可以通过 window.frames[] 来实现对每个独立的窗口目标的引用,一些简单却很有用的属性在下表中列举出来:

Window 属性 说明
frames[] 存放当前窗口中所有frame对象的数组。
length 窗口 frame 的数目,和 window.frames.length 等同。
name 当前窗口的名字,自 JavaScript 1.1 起,这个值是可读写的。
parent 对父窗口的引用。
self 对窗口自身的引用。
top 对最高级别窗口的引用,这个值通常和parent一致,除非 frame 中有更多的 frame。
window 另外一个对当前窗口的引用。

想用 Javascript 控制 frame 最主要的是要把各自的名字和他们之间的关系弄清楚,如果你有一个叫 frames.html 的页面,页面代码如下:

 
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Frameset//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-frameset.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>FrameSet Test</title>
<meta http-equiv="content-type" content="text/html; charset=ISO-8859-1" />
</head>
<frameset rows="33%,*,33%">
      <frame src="framerelationship.html" name="frame1" id="frame1" />
      <frame src="moreframes.html" name="frame2" id="frame2" />
      <frame src="framerelationship.html" name="frame5" id="frame5" />
</frameset>
</html>

在这种情况下,当前文档主体可以看作是三个 frame (frame1,frame2, and frame5) 的 parent ,你可以使用下面的方式取得 frame 数目:

 
window.frames.length

你如果在三个子 frame 中运行代码,可以用下面的方法 :

 
window.parent.frames.length

或者

 
parent.frames.length

parent 表示一个窗体的父窗体,也可以用 top 来表示最高级别的窗体,这样可以写成 top.frames.length ,但是需要注意的是:除非你有嵌套 frame ,否则 parent 和 top 通常表示的是一个对象。

访问一个 frame ,可以用 name 或者下标的方式查询 frames 数组,parent.frames[0].name 将会输出第一个 frame 的名字,在我们的例子中就是 frame1,同样,我们也可以用 parent.frame1 或者 parent.frames["frame1"] 来实现相同的操作,记住,一个 frame 就是一个 window,知道这个,就可以使用所有Window 和 Document 的方法。

当理解了 frame 之间的关系,可以很容易的通过 parent.frames[] 操作任何 frame ,假如你有一个简单的框架页面:

 
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Frameset//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-frameset.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>Two Frames</title>
<meta http-equiv="content-type" content="text/html; charset=ISO-8859-1" />
</head>
<frameset cols="300,*">
      <frame src="navigation.html" name="frame1" id="frame1" />
      <frame src="content.html" name="frame2" id="frame2" />
</frameset>
</html>

在 navigation 窗体里面,你可以通过下面的方式设置一个对 content 窗体引用的变量:

 
var contentFrame = parent.frames[1]; // 或者使用名称

iframe 是一个需要注意的 frame 变种,用iframe可以让你不使用框架,但是却可以嵌入页面,问题是,我们如何控制这些 iframe ?事实上,我们也可以用 frames[] 的方法,此外,如果你的 iframe 有命名,可以通过 getElementById 来操控,示例如下:

 
<iframe src="http://www.google.com" name="iframe1" id="iframe1" height="200" width="200"></iframe>
<form action="#" method="get">
<input type="button" value="Load by Frames Array"
 onclick="frames['iframe1'].location='http://www.javascriptref.com';" />
<input type="button" value="Load by DOM"
 onclick="document.getElementById('iframe1').src='http://www.pint.com';" />
</form>

可以通过在链接标签里面加上 target 来将操作指向目标 frame :

 
<a href="http://www.google.com" target="framename">Google</a>

防止包含在框架里面的页面被直接访问

相信大多数人设置框架页面必然有自己的目的,同时也不期望别人直接访问到被嵌套的页面,比如一个典型的两列框架布局,左侧操作导航,右侧页面主体,没有人期望自己的左侧导航页面被直接访问到,本文介绍的方法就是为了防止这个情况发生。

 
<script type="text/javascript">
<!--
if (parent.location.href == self.location.href)
  window.location.href = 'frameset.html';
//-->
</script>

代码先判断了父窗体的链接是否等同于自身链接(当父窗体为空时,parent 等于自身),如果相同,说明当前窗体被直接访问到了,此时,就将当前窗体的链接定向到设置框架的页面,即期望中的父窗体。

防止页面被包含在 frame 里面

很多情况下,我们并不希望自己的页面被其他人恶意嵌套在框架中,其实,在理解了框架之间的关系后,我们很容易实现这一目的。

 
<script type="text/javascript">
<!--
function frameBuster()
{
      if (window != top)
          top.location.href = location.href;
}
window.onload = frameBuster;
// -->
</script>

该段代码判断最高级别的窗体是否等同于窗体,如果不相等,说明当前窗体被包含在框架里面了,就将最高级别的窗体链接定向到当前期望的窗体链接。