JS HTML5事件

来源:互联网 发布:coc淘宝买宝石安全吗 编辑:程序博客网 时间:2024/06/06 08:57

1.contextmenu事件
windows95在PC中引入了上下文菜单的概念,即通过单击鼠标右键可以调出上下文菜单。不久,这个概念也被引入web领域。为了实现上下文菜单,开发人员面临的主要问题是如何确定应该显示上下文菜单,以及如何屏蔽与该操作关联的默认上下文菜单。为解决这个问题,就出现了 contextmenu 这个事件,用以表示何时应该显示上下文菜单,以便开发人员取消默认的上下文菜单而提供自定义的菜单。
由于 contextmenu 事件是冒泡的,因此可以为 document 指定一个事件处理程序,用以处理页面中发生的所有此类事件。这个事件的目标是发生用户操作的元素。在所有浏览器中都可以取消这个事件:在兼容 DOM 的浏览器中,使用event.preventDefalut() ;在 IE 中,将 event.returnValue 的值设置为 false 。因为 contextmenu 事件属于鼠标事件,所以其事件对象中包含与光标位置有关的所有属性。通常使用 contextmenu 事件来显示自定义的上下文菜单,而使用 onclick 事件处理程序来隐藏该菜单。以下面的 HTML 页面为例。

<!DOCTYPE html><html><head><title>ContextMenu Event Example</title></head><body><div id="myDiv">Right click or Ctrl+click me to get a custom context menu.Click anywhere else to get the default context menu.</div><ul id="myMenu" style="position:absolute;visibility:hidden;background-color:silver"><li><a href="http://www.nczonline.net">Nicholas’ site</a></li><li><a href="http://www.wrox.com">Wrox site</a></li><li><a href="http://www.yahoo.com">Yahoo!</a></li></ul></body></html>

这里的 <div> 元素包含一个自定义的上下文菜单。其中, <ul>元素作为自定义上下文菜单,并且在初始时是隐藏的。实现这个例子的 JavaScript 代码如下所示。

EventUtil.addHandler(window, "load", function(event){var div = document.getElementById("myDiv");EventUtil.addHandler(div, "contextmenu", function(event){event = EventUtil.getEvent(event);EventUtil.preventDefault(event);var menu = document.getElementById("myMenu");menu.style.left = event.clientX + "px";menu.style.top = event.clientY + "px";menu.style.visibility = "visible";});EventUtil.addHandler(document, "click", function(event){document.getElementById("myMenu").style.visibility = "hidden";});});

在这个例子中,我们为<div> 元素添加了 oncontextmenu 事件的处理程序。这个事件处理程序首先会取消默认行为,以保证不显示浏览器默认的上下文菜单。然后,再根据 event 对象 clientX 和clientY 属性的值,来确定放置 <ul> 元素的位置。最后一步就是通过将 visibility 属性设置为”visible” 来显示自定义上下文菜单。另外,还为 document 添加了一个 onclick 事件处理程序,以便用户能够通过鼠标单击来隐藏菜单(单击也是隐藏系统上下文菜单的默认操作)。

  1. beforeunload 事件
    之所以有发生在 window 对象上的 beforeunload 事件,是为了让开发人员有可能在页面卸载前阻止这一操作。这个事件会在浏览器卸载页面之前触发,可以通过它来取消卸载并继续使用原有页面。但是,不能彻底取消这个事件,因为那就相当于让用户无法离开当前页面了。为此,这个事件的意图是将控制权交给用户。显示的消息会告知用户页面行将被卸载(正因为如此才会显示这个消息),询问用户是否真的要关闭页面,还是希望继续留下来.
    为了显示这个弹出对话框,必须将 event.returnValue 的值设置为要显示给用户的字符串(对IE 及 Fiefox 而言),同时作为函数的值返回(对 Safari 和 Chrome 而言),如下面的例子所示。
EventUtil.addHandler(window, "beforeunload", function(event){event = EventUtil.getEvent(event);var message = "I'm really going to miss you if you go.";event.returnValue = message;return message;});
  1. DOMContentLoaded 事件
    如前所述, window 的 load 事件会在页面中的一切都加载完毕时触发,但这个过程可能会因为要加载的外部资源过多而颇费周折。而 DOMContentLoaded 事件则在形成完整的 DOM树之后就会触发,不理会图像、JavaScript 文件、CSS 文件或其他资源是否已经下载完毕。与 load 事件不同,DOMContentLoaded 支持在页面下载的早期添加事件处理程序,这也就意味着用户能够尽早地与页面进行交互。
    要处理 DOMContentLoaded 事件,可以为 document 或 window 添加相应的事件处理程序(尽管这个事件会冒泡到 window ,但它的目标实际上是 document )。来看下面的例子
EventUtil.addHandler(document, "DOMContentLoaded", function(event){alert("Content loaded");});

IE9+、Firefox、Chrome、Safari 3.1+和 Opera 9+都支持 DOMContentLoaded 事件,通常这个事件既可以添加事件处理程序,也可以执行其他 DOM 操作。这个事件始终都会在 load 事件之前触发。
对于不支持 DOMContentLoaded 的浏览器,我们建议在页面加载期间设置一个时间为 0 毫秒的超时调用,如下面的例子所示。

setTimeout(function(){//在此添加事件处理程序}, 0);

这段代码的实际意思就是:“在当前 JavaScript 处理完成后立即运行这个函数。”在页面下载和构建期间,只有一个 JavaScript 处理过程,因此超时调用会在该过程结束时立即触发。至于这个时间与DOMContentLoaded 被触发的时间能否同步,主要还是取决于用户使用的浏览器和页面中的其他代码。为了确保这个方法有效,必须将其作为页面中的第一个超时调用;即便如此,也还是无法保证在所有环
境中该超时调用一定会早于 load 事件被触发。
4. readystatechange 事件
IE 为 DOM 文档中的某些部分提供了 readystatechange 事件。这个事件的目的是提供与文档或元素的加载状态有关的信息,但这个事件的行为有时候也很难预料。支持 readystatechange 事件的每个对象都有一个 readyState 属性,可能包含下列 5 个值中的一个。

uninitialized (未初始化):对象存在但尚未初始化。
loading (正在加载):对象正在加载数据。
loaded (加载完毕):对象加载数据完成
interactive (交互):可以操作对象了,但还没有完全加载。
complete (完成):对象已经加载完毕。

这些状态看起来很直观,但并非所有对象都会经历 readyState 的这几个阶段。换句话说,如果某个阶段不适用某个对象,则该对象完全可能跳过该阶段;并没有规定哪个阶段适用于哪个对象。显然,这意味着 readystatechange 事件经常会少于 4 次,而 readyState 属性的值也不总是连续的。

对于 document 而言,值为 “interactive” 的 readyState 会在与 DOMContentLoaded 大致相同的时刻触发 readystatechange 事件。此时,DOM树已经加载完毕,可以安全地操作它了,因此就会进入交互(interactive)阶段。但与此同时,图像及其他外部文件不一定可用。下面来看一段处理readystatechange 事件的代码。

EventUtil.addHandler(document, "readystatechange", function(event){if (document.readyState == "interactive"){alert("Content loaded");}});

这个事件的 event 对象不会提供任何信息,也没有目标对象。
在与 load 事件一起使用时,无法预测两个事件触发的先后顺序。在包含较多或较大的外部资源的页面中,会在 load 事件触发之前先进入交互阶段;而在包含较少或较小的外部资源的页面中,则很难说 readystatechange 事件会发生在 load 事件前面。
让问题变得更复杂的是,交互阶段可能会早于也可能会晚于完成阶段出现,无法确保顺序。在包含较多外部资源的页面中,交互阶段更有可能早于完成阶段出现;而在页面中包含较少外部资源的情况下,完成阶段先于交互阶段出现的可能性更大。因此,为了尽可能抢到先机,有必要同时检测交互和完成阶段,如下面的例子所示。

EventUtil.addHandler(document, "readystatechange", function(event){if (document.readyState == "interactive" || document.readyState == "complete"){EventUtil.removeHandler(document, "readystatechange", arguments.callee);alert("Content loaded");}});

对于上面的代码来说,当 readystatechange 事件触发时,会检测 document.readyState 的值,看当前是否已经进入交互阶段或完成阶段。如果是,则移除相应的事件处理程序以免在其他阶段再执行。注意,由于事件处理程序使用的是匿名函数,因此这里使用了 arguments.callee 来引用该函数。然后,会显示一个警告框,说明内容已经加载完毕。这样编写代码可以达到与使用DOMContentLoaded十分相近的效果。
另外,<script>(在 IE 和 Opera 中)和 (仅 IE 中)元素也会触发 readystatechange事件,可以用来确定外部的 JavaScript 和 CSS 文件是否已经加载完成。与在其他浏览器中一样,除非把动 态 创 建 的 元 素 添 加 到 页 面 中 , 否 则 浏 览 器 不 会 开 始 下 载 外 部 资 源 。 基 于 元 素 触 发 的readystatechange 事件也存在同样的问题,即 readyState 属性无论等于 “loaded” 还是”complete” 都可以表示资源已经可用。有时候, readyState 会停在 “loaded” 阶段而永远不会“完成”;有时候,又会跳过 “loaded” 阶段而直接“完成”。于是,还需要像对待 document 一样采取相同的编码方式。例如,下面展示了一段加载外部 JavaScript 文件的代码。

EventUtil.addHandler(window, "load", function(){var script = document.createElement("script");EventUtil.addHandler(script, "readystatechange", function(event){event = EventUtil.getEvent(event);var target = EventUtil.getTarget(event);if (target.readyState == "loaded" || target.readyState == "complete"){EventUtil.removeHandler(target, "readystatechange", arguments. callee);alert("Script Loaded");}});script.src = "example.js";document.body.appendChild(script);});

这个例子为新创建的 <script> 节点指定了一个事件处理程序。事件的目标是该节点本身,因此当触发 readystatechange 事件时,要检测目标的 readyState 属性是不是等于 “loaded” 或”complete” 。如果进入了其中任何一个阶段,则移除事件处理程序(以防止被执行两次),并显示一个警告框。与此同时,就可以执行已经加载完毕的外部文件中的函数了。
同样的编码方式也适用于通过 元素加载 CSS 文件的情况,如下面的例子所示。

EventUtil.addHandler(window, "load", function(){var link = document.createElement("link");link.type = "text/css";link.rel= "stylesheet";EventUtil.addHandler(script, "readystatechange", function(event){event = EventUtil.getEvent(event);var target = EventUtil.getTarget(event);if (target.readyState == "loaded" || target.readyState == "complete"){EventUtil.removeHandler(target, "readystatechange", arguments. callee);alert("CSS Loaded");}});link.href = "example.css";document.getElementsByTagName("head")[0].appendChild(link);});

同样,最重要的是要一并检测 readyState 的两个状态,并在调用了一次事件处理程序后就将其移除。
5. pageshow 和 pagehide 事件

Firefox 和 Opera 有一个特性,名叫“往返缓存”(back-forward cache,或 bfcache),可以在用户使用浏览器的“后退”和“前进”按钮时加快页面的转换速度。这个缓存中不仅保存着页面数据,还保存了 DOM 和 JavaScript 的状态;实际上是将整个页面都保存在了内存里。如果页面位于 bfcache 中,那么再次打开该页面时就不会触发 load 事件。尽管由于内存中保存了整个页面的状态,不触发 load 事件也不应该会导致什么问题,但为了更形象地说明 bfcache 的行为,Firefox 还是提供了一些新事件。
第一个事件就是 pageshow ,这个事件在页面显示时触发,无论该页面是否来自 bfcache。在重新加载的页面中, pageshow 会在 load 事件触发后触发;而对于 bfcache 中的页面, pageshow 会在页面状态完全恢复的那一刻触发。另外要注意的是,虽然这个事件的目标是 document ,但必须将其事件处理程序添加到 window 。来看下面的例子。

(function(){var showCount = 0;EventUtil.addHandler(window, "load", function(){alert("Load fired");});EventUtil.addHandler(window, "pageshow", function(){showCount++;alert("Show has been fired " + showCount + " times.");});})();

这个例子使用了私有作用域,以防止变量 showCount 进入全局作用域。当页面首次加载完成时,showCount 的值为 0 。此后,每当触发 pageshow 事件, showCount 的值就会递增并通过警告框显示出来。如果你在离开包含以上代码的页面之后,又单击“后退”按钮返回该页面,就会看到 showCount每次递增的值。这是因为该变量的状态,乃至整个页面的状态,都被保存在了内存中,当你返回这个页面时,它们的状态得到了恢复。如果你单击了浏览器的“刷新”按钮,那么 showCount 的值就会被重置为 0 ,因为页面已经完全重新加载了。
除了通常的属性之外, pageshow 事件的 event 对象还包含一个名为 persisted 的布尔值属性。如果页面被保存在了 bfcache 中,则这个属性的值为 true ;否则,这个属性的值为 false 。可以像下面这样在事件处理程序中检测这个属性。

(function(){var showCount = 0;EventUtil.addHandler(window, "load", function(){alert("Load fired");});EventUtil.addHandler(window, "pageshow", function(){showCount++;alert("Show has been fired " + showCount +" times. Persisted? " + event.persisted);});})();

与 pageshow 事件对应的是 pagehide 事件,该事件会在浏览器卸载页面的时候触发,而且是在unload 事件之前触发。与 pageshow 事件一样, pagehide 在 document 上面触发,但其事件处理程序必须要添加到 window 对象。这个事件的 event 对象也包含 persisted 属性,不过其用途稍有不同。来看下面的例子。

EventUtil.addHandler(window, "pagehide", function(event){alert("Hiding. Persisted? " + event.persisted);});

有时候,可能需要在 pagehide 事件触发时根据 persisted 的值采取不同的操作。对于 pageshow事件,如果页面是从 bfcache 中加载的,那么 persisted 的值就是 true ;对于 pagehide 事件,如果页面在卸载之后会被保存在 bfcache 中,那么 persisted 的值也会被设置为 true 。因此,当第一次触发 pageshow 时,persisted 的值一定是 false ,而在第一次触发 pagehide 时, persisted 就会变成 true (除非页面不会被保存在 bfcache 中)。
6. hashchange 事件
HTML5 新增了 hashchange 事件,以便在 URL 的参数列表(及 URL 中“#”号后面的所有字符串)发生变化时通知开发人员。之所以新增这个事件,是因为在 Ajax 应用中,开发人员经常要利用 URL 参数列表来保存状态或导航信息。
必须要把 hashchange 事件处理程序添加给 window 对象,然后 URL 参数列表只要变化就会调用它。此时的 event 对象应该额外包含两个属性: oldURL 和 newURL 。这两个属性分别保存着参数列表变化前后的完整 URL。例如:

EventUtil.addHandler(window, "hashchange", function(event){alert("Old URL: " + event.oldURL + "\nNew URL: " + event.newURL);});

支持 hashchange 事件的浏览器有 IE8+、Firefox 3.6+、Safari 5+、Chrome 和 Opera 10.6+。在这些浏览器中,只有 Firefox 6+、Chrome 和 Opera 支持 oldURL 和 newURL 属性。为此,最好是使用 location对象来确定当前的参数列表。

EventUtil.addHandler(window, "hashchange", function(event){alert("Current hash: " + location.hash);});
0 0