首页 > 编程笔记 > JavaScript笔记 > JS事件 阅读:1,704

JS页面事件(非常详细)

所有页面事件都明确的处理整个页面的函数和状态。主要包括页面的加载和卸载,即用户访问页面和离开关闭页面的事件类型。

页面初始化

load 事件类型在页面完全加载完毕的时候触发。该事件包含所有的图形图像、外部文件(如 CSS、JS 文件等)的加载,也就是说,在页面所有内容全部加载之前,任何 DOM 操作都不会发生。为 window 对象绑定 load 事件类型的方法有两种。

1) 直接为 window 对象注册页面初始化事件处理函数。
window.onload = f;
function f() {
    alert("页面加载完毕");
}

2) 在页面 <body> 标签中定义 onload 事件处理属性。
<body onload="f()">
<script>
    function f() {
        alert("页面加载完毕");
    }
</script>

示例1

如果同时使用上面两种方法定义页面初始化事件类型,它们并不会发生冲突,也不会发生两次触发事件。
<body onload="f()">
<script>
    window.onload = f;
    function f() {
        alert("页面加载完毕");
    }
</script>
</body>
原来 JavaScript 解释器在编译时,如果发现同时使用两种方法定义 load 事件类型,会使用 window 对象注册的事件处理函数覆盖掉 body 元素定义的页面初始化事件属性。

示例2

在下面示例中,函数 f2() 被调用,而函数 f1() 就被覆盖掉。
<body onload="f1()">
<script>
    window.onload = f2;
    function f1 () {
        alert('<body onload="f1()">');
    }
    function f2 () {
        alert('window.onload = f2;');
    }
</script>
</body>
在实际开发中,load 事件类型经常需要调用附带参数的函数,但是 load 事件类型不能够直接调用函数,要解决这个问题,有以下两种方法。

1) 在 body 元素中通过事件属性的形式回调函数。
<body onload="f('Hi')">
<script>
    function f (a) {
        alert(a);
    }
</script>
</body>

2) 通过函数嵌套或闭包函数来实现。
window.onload = function () {  //事件处理函数
    f("Hi");  //调用函数
}
functioin f(a) {  //被处理函数
    alert(a);
}
也可以采用闭包函数形式,这样在注册事件时,虽然调用的是函数,但是其返回值依然是一个函数,不会引发语法错误。
window.onload = f("Hi");
function f(a) {
    return function () {   
        alert(a);
    }
}
通过这种方法,可以实现在 load 事件类型上绑定更多的响应回调函数。
window.onload = function () {
    f1();  //绑定响应函数1
    f2();  //绑定响应函数2
}
function f1() {
    alert("f1()");
}
function f2() {
    alert("f2()");
}
但是,如果分别绑定 load 事件处理函数,则会相互覆盖,最终只能够有一个绑定响应函数被调用。
window.onload = f1();
function f1(){
    alert("f1()");
}
function f2() {
    alert("f2()");
}
也可以通过事件注册的方式来实现。
if (window.addEventListener) {  //兼容DOM标准
    window.addEventListener ("load", f1, false);  //为load添加事件处理函数
    window.addEventListener ("load", f2,false);  //为load添加事件处理函数
} else {  //兼容IE事件模型
    window.attachEvent ("onload", f1);
    window.attachEvent ("onload", f2);
}

结构初始化

在传统事件模型中,load 是页面中最早被触发的事件。不过当使用 load 事件来初始化页面时可能会存在一个问题,就是当页面中包含很大的文件时,load 事件需要等到所有图像全部载入完成之后才会被触发。也许用户希望某些脚本能够在页面结构加载完毕之后就能够被执行。要怎么办呢?

这时可以考虑使用 DOMContentLoaded 事件类型。作为 DOM 标准事件,它是在 DOM 文档结构加载完毕的时候触发的,因此要比 load 事件类型先被触发。目前,Mozilla 和 Opera 新版本已经支持了该事件。而 IE 和 Safari 浏览器还不支持。

示例1

如果在标准 DOM 中,可以这样设计。
<script>
    window.onload = f1;
    if (document.addEventListener) {
        document.addEventListener ("DOMContentLoaded", f, false);
    }
    function f () { alert("我要提前执行了"); }
    function f1 () { alert("页面初始化完毕"); }
</script>
<img src="Winter.jpg">
这样,在图片加载之前会弹出“我要提前执行了”的提示信息,而当图片加载完毕之后会弹出“页面初始化完毕”。这说明在页面 HTML 结构加载完毕之后触发 DOMContentLoaded 事件类型,也就是说,在文档标签加载完毕时触发该事件并调用函数 f(),然后,当文档所有内容加载完毕(包括图片下载完毕)时才触发 load 事件类型,并调用函数 f1()。

示例2

由于 IE 事件模型不支持 DOMContentLoaded 事件类型,为了实现兼容处理,需要运用一点小技巧,即在文档中写入一个新的 script 元素,但是该元素会延迟到文件最后加载。然后,使用 Script 对象的 onreadystatechange 方法进行类似的 readyState 检查后及时调用载入事件。
if (window.ActiveXObject) {  //兼容IE事件模型
    document.write ("<script id=ie_onload defer src=javascript:void(0)><\/script");  //写入脚本标签
    document.getElementById("ie_load").onreadystatechange = function () {
        //判断脚本标签的状态
        if (this.readyState == "complete") {  //如果状态为完成,则说明文档结构加载已完毕
            this.onreadystatechange = null;  //清空当前反腐
            f();  //调用预先执行的回调函数
        }
    }
}
写入的 <script> 标签中包含了 defer属性,defer 表示“延期”的意思,使用 defer 属性可以让脚本在整个页面装载完成之后在解析,而非边加载边解析。这对于只包含事件触发的脚本来说,可以提高整个页面的加载速度。与 src 属性联合使用,还可以使这些脚本在后台被下载,而前台的内容正常显示给用户。目前只有 IE 事件模型支持该属性。当定义了 defer 属性后,<script> 标签中就不应包含 document.write 命令,因为 document.write 将产生直接输出的效果,而且不包含任何立即执行脚本要使用的全局变量或者函数。

<script> 标签在文档结构加载完毕之后才加载,于是,只要判断它的状态就可以确定当前文档结构是否已经加载完毕并触发响应的事件。

示例3

针对 Safari 浏览器,可以使用 setInterval() 函数周期性的检查 document 对象的 readyState 属性,随时监控文档是否加载完毕,如果完成则调用回调函数。
if (/WebKit/i.test(navigator.userAgent)) {  //兼容Safari浏览器
    var _timer = setInterval (function () {  //定义时间监测器
        if (/loaded|complete/.test(document.readyState) {  //如果当前状态显示完成
            clearInterval(_timer);  //清空时间监测器
            f();  //调用预先执行的回调函数
        }
    }, 10);
}
把上面 3 段条件合并在一起即可实现兼容不同浏览器的 DomContentLoaded 事件处理函数。

页面卸载

unload 表示卸载的意思,这个事件在从当前浏览器窗口内移动文档的位置时触发,也就是说,通过超链接、前进或后退按钮等方式词能够一个页面跳转到其他页面,或者关闭浏览器窗口时触发。

示例

下面函数的提示信息将在卸载页面时发生,即在离开页面或关闭窗口前执行。
window.onunload = f;
function f() {
    alert("888");
}
在 unload 事件类型中无法有效阻止默认行为,因为该事件结束后,页面将不复存在。由于在窗口关闭或离开页面之前只有很短的时间来执行事件处理函数,所以不建议使用该事件类型。使用该事件类型的最佳方式是取消该页面的对象引用。

beforeunload 事件类型与 unload 事件类型的功能相近,不过它更人性化,如果 beforeunload 事件处理函数返回字符串信息,那么该字符串会显示在一个确认对话框中,询问用户是否离开当前页面。例如,运行下面的示例,当刷新或关闭页面时会弹出以下提示信息。
window.beforeunload = function (e) {
    return "您的数据还没有保存!";
}
演示结构如下:

beforeunload 事件处理函数返回值可以为任意类型,IE 和 Safari 浏览器的 JavaScript 解释器能够调用 toString() 方法,并把它转换为字符串显示在提示对话框中;而对于 Mozilla 浏览器来说,则会视为空字符串显示。如果 beforeunload 事件处理函数没有返回值,则不会弹出任何提示对话框,此时与 unload 事件类型响应效果相同。

窗口重置

resize 事件类型是在浏览器窗口被重置时触发的,如当用户调整窗口大小,或者最大化、最小化、恢复窗口大小显示时触发 resize 事件。利用该事件可以跟踪窗口大小的变化以便动态调整页面元素的显示大小。

示例

下面的示例能够根据跟踪窗口大小变化及时调整页面内红色盒子的大小,使其始终保持与窗口固定比例的大小显示。
<div id="box"></div>
<script>
    var box = document.getElementById("box");  //获取盒子的指针引用
    box.style.position = "absolute";  //绝对定位
    box.style.backgroundColor = "red";  //背景色
    box.style.width = w() * 0.8 + "px";  //设置盒子宽度为窗口宽度的0.8倍
    box.style.height = h() * 0.8 + "px";  //设置盒子高度为窗口高度的0.8倍
    window.onresize = function () {  //注册事件处理函数,动态调整盒子大小
        box.style.width = w() * 0.8 + "px";
        box.style.height = h() * 0.8 + "px";
    }
    function w () {  //获取窗口宽度
        if (window.innerWidth) {  //兼容DOM
            return window.innerWidth;
        else if ((document.body) && (document.body.clientWidth))  //兼容IE
            return document.body.clientWidth;
    }
    function h () {  //获取窗口高度
        if (window.innerHeight) {  //兼容DOM
            return window.innerHeight;
        else if ((document.body) && (document.body.clientHeight))  //兼容IE
            return document.body.clientHeight;
    }
</script>

页面滚动

scroll 事件类型用于在浏览器窗口内移动文档的位置时触发,如通过键盘箭头键、翻页键或空格键移动稳定位置,或者通过滚动条滚动稳定位置。利用该事件可以跟踪文档位置变化,及时调整某些元素的的显示位置,确保它始终显示在屏幕可见区域内中。

示例

在下面示例中,控制红色小盒子始终位于窗口内坐标为(100px,100px)的位置。
<div id="box"></div>
<script>
    var box = document.getElementById("box");
    box.style.position = "absolute";
    box.style.backgroundColor = "red";
    box.style.width = "200px";
    box.style.height = "160px";
    window.onload = f;  //页面初始化时固定其位置
    window.onscroll = f;  //当文档位置发生变化时重新固定其位置
    function f(){  //元素位置固定函数
        box.style.left = 100 + parseInt(document.body.scrollLeft) + "px";
        box.style.top = 100 + parseInt(document.body.scrollTop) + "px";
    }
</script>
<div style="height:2000px;width:2000px;"></div>
还有一种方法,就是利用 settimeout() 函数实现每间隔一定时间校正一次元素的位置,不过这种方法的损耗比较大,不建议使用。

错误处理

error 事件类型是在 JavaScript 代码发生错误时触发的,利用该事件可以捕获并处理错误信息。error 事件类型与 try/catch 语句功能相似,都用来捕获页面错误信息。不过 error 事件类型无须传递事件对象,且可以包含已经发生错误的解释信息。

示例

在下面示例中,当页面发生编译错误时,将会触发 error 事件注册的事件处理函数,并弹出错误信息。
window.onerror = function(message){  // 捕获浏览器错误行为
    alert("错误原因:" + arguments[0] + "\n错误URL: " +  arguments[1] + "\n错误行号: " + arguments[2]);
    return true;  // 禁止浏览器显示标准出错信息
}
a.innerHTML = "";  // 制造错误机会
在 error 事件处理函数中,默认包含 3 个参数:其中第 1 个表示错误信息,第 2 个表示出错文件的 URL,第 3 个参数表示文件中错误位置的行号。

error 事件处理函数的返回值可以决定浏览器是否显示一个标准出错信息。如果返回值为 false,则浏览器会弹出错误提示对话框,显示标准的出错信息;如果返回值为 true,则浏览器不会显示标准出错信息。

编程帮,一个分享编程知识的公众号。跟着站长一起学习,每天都有进步。

通俗易懂,深入浅出,一篇文章只讲一个知识点。

文章不深奥,不需要钻研,在公交、在地铁、在厕所都可以阅读,随时随地涨姿势。

文章不涉及代码,不烧脑细胞,人人都可以学习。

当你决定关注「编程帮」,你已然超越了90%的程序员!

编程帮二维码
微信扫描二维码关注

所有教程

优秀文章