- 其他连接:
- 以下内容部分都摘自书本:《JavaScript高级程序设计(第3版)》 13.4.7 HTML5 事件
一、动态创建script标签实现跨域
- 原理:
script
标签不受同源策略的限制- 注意: 如果不讲动态创建的
script
元素添加到页面,浏览器是不会开始下载资源的。
- 注意: 如果不讲动态创建的
function loadScript(url, func) {
var script = document.createElement('script');
script.src = url;
//script加载完毕才执行
script.onload = script.onreadystatechange = function(){
if(!this.readyState || this.readyState=='loaded' || this.readyState=='complete'){
func && func();
script.onload = script.onreadystatechange = null;
}
};
document.body.appendChild(script);
}
二、 readystatechange事件
2.1 简介
readystatechange事件
:提供与文档或元素的加载状态有关的信息。- 支持
readystatechange
事件的每个对象都有一个readyState
属性,可能包含下列 5 个值中的一个。即:并非所有对象都会经历readyState
的这几个阶段。【这意味着readystatechange
事件经常会少于4
次,而readyState
属性的值也不总是连续的。】uninitialized
(未初始化):对象存在但尚未初始化。loading
(正在加载):对象正在加载数据。loaded
(加载完毕):对象加载数据完成。interactive
(交互):可以操作对象了,但还没有完全加载。complete
(完成):对象已经加载完毕。
- 支持
readystatechange
事件的浏览器有 IE、Firfox 4+和 Opera。
2.2 document
- 对于
document
而言,值为”interactive
“的readyState
会在与DOMContentLoaded
大致相同的时刻触发readystatechange
事件。 - 此时,
DOM
树已经加载完毕,可以安全地操作它了,因此就会进入交互(interactive
)阶段。 - 但与此同时,图像及其他外部文件不一定可用。下面来看一段处理
readystatechange
事件的代码。
EventUtil.addHandler(document, "readystatechange", function(event){
if (document.readyState == "interactive"){
alert("Content loaded");
}
});
这个事件的 event 对象不会提供任何信息,也没有目标对象。
2.3 与load事件一起使用
-
在与
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
十分相近的效果。
2.4 script标签
readyState
属性无论等于 “loaded
” 还 是”complete
“都可以表示资源已经可用。- 有时候,
readyState
会停在”loaded
“阶段而永远不会“完成”; - 有时候,又会跳过”
loaded
“阶段而直接“完成”。于是,还需要像对待document
一样采取相同的编码方式。
- 有时候,
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);
});