文档事件

beforeunload事件,unload事件,load事件,error事件,pageshow事件,pagehide事件

以下事件与网页的加载与卸载相关。

(1)beforeunload事件

beforeunload事件在窗口将要关闭,或者网页(即document对象)将要卸载时触发。它可以用来防止用户不小心关闭网页。

根据标准,只要在该事件的回调函数中,调用了event.preventDefault(),或者event.returnValue属性的值是一个非空的值,就会自动跳出一个确认框,让用户确认是否关闭网页。如果用户点击“取消”按钮,网页就不会关闭。event.returnValue属性的值,会显示在确认对话框之中。

window.addEventListener('beforeunload', function( event ) {event.returnValue = '你确认要离开吗?';
});

window.addEventListener(‘beforeunload’, function( event ) {
event.preventDefault();
});

但是,浏览器的行为很不一致,Chrome就不遵守event.preventDefault(),还是会关闭窗口,而IE需要显式返回一个非空的字符串。而且,大多数浏览器在对话框中不显示指定文本,只显示默认文本。因此,可以采用下面的写法,取得最大的兼容性。

window.addEventListener('beforeunload', function (e) {var confirmationMessage = '确认关闭窗口?';

e.returnValue = confirmationMessage;
return confirmationMessage;
});

需要特别注意的是,许多手机浏览器默认忽视这个事件,而桌面浏览器也可以这样设置,所以这个事件有可能根本不生效。所以,不能依赖它来阻止用户关闭窗口。

(2)unload事件

unload事件在窗口关闭或者document对象将要卸载时触发,发生在window、body、frameset等对象上面。它的触发顺序排在beforeunload、pagehide事件后面。unload事件只在页面没有被浏览器缓存时才会触发,换言之,如果通过按下“前进/后退”导致页面卸载,并不会触发unload事件。

当unload事件发生时,document对象处于一个特殊状态。所有资源依然存在,但是对用户来说都不可见,UI互动(window.open、alert、confirm方法等)全部无效。这时即使抛出错误,也不能停止文档的卸载。

window.addEventListener('unload', function(event) {console.log('文档将要卸载');
});

如果在window对象上定义了该事件,网页就不会被浏览器缓存。

(3)load事件,error事件

load事件在页面加载成功时触发,error事件在页面加载失败时触发。注意,页面从浏览器缓存加载,并不会触发load事件。

这两个事件实际上属于进度事件,不仅发生在document对象,还发生在各种外部资源上面。浏览网页就是一个加载各种资源的过程,图像(image)、样式表(style sheet)、脚本(script)、视频(video)、音频(audio)、Ajax请求(XMLHttpRequest)等等。这些资源和document对象、window对象、XMLHttpRequestUpload对象,都会触发load事件和error事件。

(4)pageshow事件,pagehide事件

默认情况下,浏览器会在当前会话(session)缓存页面,当用户点击“前进/后退”按钮时,浏览器就会从缓存中加载页面。

pageshow事件在页面加载时触发,包括第一次加载和从缓存加载两种情况。如果要指定页面每次加载(不管是不是从浏览器缓存)时都运行的代码,可以放在这个事件的监听函数。

第一次加载时,它的触发顺序排在load事件后面。从缓存加载时,load事件不会触发,因为网页在缓存中的样子通常是load事件的监听函数运行后的样子,所以不必重复执行。同理,如果是从缓存中加载页面,网页内初始化的JavaScript脚本(比如DOMContentLoaded事件的监听函数)也不会执行。

window.addEventListener('pageshow', function(event) {console.log('pageshow: ', event);
});

pageshow事件有一个persisted属性,返回一个布尔值。页面第一次加载时,这个属性是false;当页面从缓存加载时,这个属性是true。

window.addEventListener('pageshow', function(event){if (event.persisted) {// ...}
});

pagehide事件与pageshow事件类似,当用户通过“前进/后退”按钮,离开当前页面时触发。它与unload事件的区别在于,如果在window对象上定义unload事件的监听函数之后,页面不会保存在缓存中,而使用pagehide事件,页面会保存在缓存中。

pagehide事件的event对象有一个persisted属性,将这个属性设为true,就表示页面要保存在缓存中;设为false,表示网页不保存在缓存中,这时如果设置了unload事件的监听函数,该函数将在pagehide事件后立即运行。

如果页面包含frame或iframe元素,则frame页面的pageshow事件和pagehide事件,都会在主页面之前触发。

DOMContentLoaded事件,readystatechange事件

以下事件与文档状态相关。

(1)DOMContentLoaded事件

当HTML文档下载并解析完成以后,就会在document对象上触发DOMContentLoaded事件。这时,仅仅完成了HTML文档的解析(整张页面的DOM生成),所有外部资源(样式表、脚本、iframe等等)可能还没有下载结束。也就是说,这个事件比load事件,发生时间早得多。

document.addEventListener("DOMContentLoaded", function(event) {console.log("DOM生成");
});

注意,网页的JavaScript脚本是同步执行的,所以定义DOMContentLoaded事件的监听函数,应该放在所有脚本的最前面。否则脚本一旦发生堵塞,将推迟触发DOMContentLoaded事件。

(2)readystatechange事件

readystatechange事件发生在Document对象和XMLHttpRequest对象,当它们的readyState属性发生变化时触发。

document.onreadystatechange = function () {if (document.readyState == "interactive") {// ...}
}

IE8不支持DOMContentLoaded事件,但是支持这个事件。因此,可以使用readystatechange事件,在低版本的IE中代替DOMContentLoaded事件。

scroll事件,resize事件

以下事件与窗口行为有关。

(1)scroll事件

scroll事件在文档或文档元素滚动时触发,主要出现在用户拖动滚动条。

window.addEventListener('scroll', callback);

由于该事件会连续地大量触发,所以它的监听函数之中不应该有非常耗费计算的操作。推荐的做法是使用requestAnimationFramesetTimeout控制该事件的触发频率,然后可以结合customEvent抛出一个新事件。

(function() {var throttle = function(type, name, obj) {var obj = obj || window;var running = false;var func = function() {if (running) { return; }running = true;requestAnimationFrame(function() {obj.dispatchEvent(new CustomEvent(name));running = false;});};obj.addEventListener(type, func);};

// 将scroll事件重定义为optimizedScroll事件
throttle(‘scroll’, ‘optimizedScroll’);
})();

window.addEventListener(‘optimizedScroll’, function() {
console.log(“Resource conscious scroll callback!”);
});

上面代码中,throttle函数用于控制事件触发频率,requestAnimationFrame方法保证每次页面重绘(每秒60次),只会触发一次scroll事件的监听函数。也就是说,上面方法将scroll事件的触发频率,限制在每秒60次。

改用setTimeout方法,可以放置更大的时间间隔。

(function() {window.addEventListener('scroll', scrollThrottler, false);

var scrollTimeout;
function scrollThrottler() {
if (!scrollTimeout) {
scrollTimeout = setTimeout(function() {
scrollTimeout = null;
actualScrollHandler();
}, 66);
}
}

function actualScrollHandler() {
// …
}
}());

上面代码中,setTimeout指定scroll事件的监听函数,每66毫秒触发一次(每秒15次)。

下面是一个更一般的throttle函数的写法。

function throttle(fn, wait) {var time = Date.now();return function() {if ((time + wait - Date.now()) < 0) {fn();time = Date.now();}}
}

window.addEventListener(‘scroll’, throttle(callback, 1000));

上面的代码将scroll事件的触发频率,限制在一秒一次。

lodash函数库提供了现成的throttle函数,可以直接引用。

window.addEventListener('scroll', _.throttle(callback, 1000));

(2)resize事件

resize事件在改变浏览器窗口大小时触发,发生在window、body、frameset对象上面。

var resizeMethod = function(){if (document.body.clientWidth < 768) {console.log('移动设备');}
};

window.addEventListener(“resize”, resizeMethod, true);

该事件也会连续地大量触发,所以最好像上面的scroll事件一样,通过throttle函数控制事件触发频率。

hashchange事件,popstate事件

以下事件与文档的URL变化相关。

(1)hashchange事件

hashchange事件在URL的hash部分(即#号后面的部分,包括#号)发生变化时触发。如果老式浏览器不支持该属性,可以通过定期检查location.hash属性,模拟该事件,下面就是代码。

(function(window) {if ( "onhashchange" in window.document.body ) { return; }

var location = window.location;
var oldURL = location.href;
var oldHash = location.hash;

// 每隔100毫秒检查一下URL的hash
setInterval(function() {
var newURL = location.href;
var newHash = location.hash;

<span class="k">if</span> <span class="p">(</span> <span class="nx">newHash</span> <span class="o">!=</span> <span class="nx">oldHash</span> <span class="o">&amp;&amp;</span> <span class="k">typeof</span> <span class="nb">window</span><span class="p">.</span><span class="nx">onhashchange</span> <span class="o">===</span> <span class="s2">"function"</span> <span class="p">)</span> <span class="p">{</span><span class="nb">window</span><span class="p">.</span><span class="nx">onhashchange</span><span class="p">({</span><span class="na">type</span><span class="p">:</span> <span class="s2">"hashchange"</span><span class="p">,</span><span class="na">oldURL</span><span class="p">:</span> <span class="nx">oldURL</span><span class="p">,</span><span class="na">newURL</span><span class="p">:</span> <span class="nx">newURL</span><span class="p">});</span><span class="nx">oldURL</span> <span class="o">=</span> <span class="nx">newURL</span><span class="p">;</span><span class="nx">oldHash</span> <span class="o">=</span> <span class="nx">newHash</span><span class="p">;</span>
<span class="p">}</span>

}, 100);

})(window);

hashchange事件对象除了继承Event对象,还有oldURL属性和newURL属性,分别表示变化前后的URL。

(2)popstate事件

popstate事件在浏览器的history对象的当前记录发生显式切换时触发。注意,调用history.pushState()或history.replaceState(),并不会触发popstate事件。该事件只在用户在history记录之间显式切换时触发,比如鼠标点击“后退/前进”按钮,或者在脚本中调用history.back()、history.forward()、history.go()时触发。

该事件对象有一个state属性,保存history.pushState方法和history.replaceState方法为当前记录添加的state对象。

window.onpopstate = function(event) {console.log("state: " + event.state);
};
history.pushState({page: 1}, "title 1", "?page=1");
history.pushState({page: 2}, "title 2", "?page=2");
history.replaceState({page: 3}, "title 3", "?page=3");
history.back(); // state: {"page":1}
history.back(); // state: null
history.go(2);  // state: {"page":3}

上面代码中,pushState方法向history添加了两条记录,然后replaceState方法替换掉当前记录。因此,连续两次back方法,会让当前条目退回到原始网址,它没有附带state对象,所以事件的state属性为null,然后前进两条记录,又回到replaceState方法添加的记录。

浏览器对于页面首次加载,是否触发popstate事件,处理不一样,Firefox不触发该事件。

cut事件,copy事件,paste事件

以下三个事件属于文本操作触发的事件。

  • cut事件:在将选中的内容从文档中移除,加入剪贴板后触发。

  • copy事件:在选中的内容加入剪贴板后触发。

  • paste事件:在剪贴板内容被粘贴到文档后触发。

这三个事件都有一个clipboardData只读属性。该属性存放剪贴的数据,是一个DataTransfer对象,具体的API接口和操作方法,请参见《触摸事件》的DataTransfer对象章节。

焦点事件

焦点事件发生在Element节点和document对象上面,与获得或失去焦点相关。它主要包括以下四个事件。

  • focus事件:Element节点获得焦点后触发,该事件不会冒泡。

  • blur事件:Element节点失去焦点后触发,该事件不会冒泡。

  • focusin事件:Element节点将要获得焦点时触发,发生在focus事件之前。该事件会冒泡。Firefox不支持该事件。

  • focusout事件:Element节点将要失去焦点时触发,发生在blur事件之前。该事件会冒泡。Firefox不支持该事件。

这四个事件的事件对象,带有target属性(返回事件的目标节点)和relatedTarget属性(返回一个Element节点)。对于focusin事件,relatedTarget属性表示失去焦点的节点;对于focusout事件,表示将要接受焦点的节点;对于focus和blur事件,该属性返回null。

由于focus和blur事件不会冒泡,只能在捕获阶段触发,所以addEventListener方法的第三个参数需要设为true。

form.addEventListener("focus", function( event ) {event.target.style.background = "pink";
}, true);
form.addEventListener("blur", function( event ) {event.target.style.background = "";
}, true);

上面代码设置表单的文本输入框,在接受焦点时设置背景色,在失去焦点时去除背景色。

浏览器提供一个FocusEvent构造函数,可以用它生成焦点事件的实例。

var focusEvent = new FocusEvent(typeArg, focusEventInit);

上面代码中,FocusEvent构造函数的第一个参数为事件类型,第二个参数是可选的配置对象,用来配置FocusEvent对象。

自定义事件和事件模拟

除了浏览器预定义的那些事件,用户还可以自定义事件,然后手动触发。

// 新建事件实例
var event = new Event('build');

// 添加监听函数
elem.addEventListener(‘build’, function (e) { }, false);

// 触发事件
elem.dispatchEvent(event);

上面代码触发了自定义事件,该事件会层层向上冒泡。在冒泡过程中,如果有一个元素定义了该事件的监听函数,该监听函数就会触发。

由于IE不支持这个API,如果在IE中自定义事件,需要使用后文的“老式方法”。

CustomEvent()

Event构造函数只能指定事件名,不能在事件上绑定数据。如果需要在触发事件的同时,传入指定的数据,需要使用CustomEvent构造函数生成自定义的事件对象。

var event = new CustomEvent('build', { 'detail': 'hello' });
function eventHandler(e) {console.log(e.detail);
}

上面代码中,CustomEvent构造函数的第一个参数是事件名称,第二个参数是一个对象,该对象的detail属性会绑定在事件对象之上。

下面是另一个例子。

var myEvent = new CustomEvent("myevent", {detail: {foo: "bar"},bubbles: true,cancelable: false
});

el.addEventListener(‘myevent’, function(event) {
console.log('Hello ’ + event.detail.foo);
});

el.dispatchEvent(myEvent);

IE不支持这个方法,可以用下面的垫片函数模拟。

(function () {function CustomEvent ( event, params ) {params = params || { bubbles: false, cancelable: false, detail: undefined };var evt = document.createEvent( 'CustomEvent' );evt.initCustomEvent( event, params.bubbles, params.cancelable, params.detail );return evt;}

CustomEvent.prototype = window.Event.prototype;

window.CustomEvent = CustomEvent;
})();

事件的模拟

有时,需要在脚本中模拟触发某种类型的事件,这时就必须使用这种事件的构造函数。

下面是一个通过MouseEvent构造函数,模拟触发click鼠标事件的例子。

function simulateClick() {var event = new MouseEvent('click', {'bubbles': true,'cancelable': true});var cb = document.getElementById('checkbox');cb.dispatchEvent(event);
}

自定义事件的老式写法

老式浏览器不一定支持各种类型事件的构造函数。因此,有时为了兼容,会用到一些非标准的方法。这些方法未来会被逐步淘汰,但是目前浏览器还广泛支持。除非是为了兼容老式浏览器,尽量不要使用。

(1)document.createEvent()

document.createEvent方法用来新建指定类型的事件。它所生成的Event实例,可以传入dispatchEvent方法。

// 新建Event实例
var event = document.createEvent('Event');

// 事件的初始化
event.initEvent(‘build’, true, true);

// 加上监听函数
document.addEventListener(‘build’, doSomething, false);

// 触发事件
document.dispatchEvent(event);

createEvent方法接受一个字符串作为参数,可能的值参见下表“数据类型”一栏。使用了某一种“事件类型”,就必须使用对应的事件初始化方法。

事件类型 事件初始化方法
UIEvents event.initUIEvent
MouseEvents event.initMouseEvent
MutationEvents event.initMutationEvent
HTMLEvents event.initEvent
Event event.initEvent
CustomEvent event.initCustomEvent
KeyboardEvent event.initKeyEvent

(2)event.initEvent()

事件对象的initEvent方法,用来初始化事件对象,还能向事件对象添加属性。该方法的参数必须是一个使用Document.createEvent()生成的Event实例,而且必须在dispatchEvent方法之前调用。

var event = document.createEvent('Event');
event.initEvent('my-custom-event', true, true, {foo:'bar'});
someElement.dispatchEvent(event);

initEvent方法可以接受四个参数。

  • type:事件名称,格式为字符串。
  • bubbles:事件是否应该冒泡,格式为布尔值。可以使用event.bubbles属性读取它的值。
  • cancelable:事件是否能被取消,格式为布尔值。可以使用event.cancelable属性读取它的值。
  • option:为事件对象指定额外的属性。

事件模拟的老式写法

事件模拟的非标准做法是,对document.createEvent方法生成的事件对象,使用对应的事件初始化方法进行初始化。比如,click事件对象属于MouseEvent对象,也属于UIEvent对象,因此要用initMouseEvent方法或initUIEvent方法进行初始化。

(1)event.initMouseEvent()

initMouseEvent方法用来初始化Document.createEvent方法新建的鼠标事件。该方法必须在事件新建(document.createEvent方法)之后、触发(dispatchEvent方法)之前调用。

initMouseEvent方法有很长的参数。

event.initMouseEvent(type, canBubble, cancelable, view,detail, screenX, screenY, clientX, clientY,ctrlKey, altKey, shiftKey, metaKey,button, relatedTarget
);

上面这些参数的含义,参见MouseEvent构造函数的部分。

模仿并触发click事件的写法如下。

var simulateDivClick = document.createEvent('MouseEvents');

simulateDivClick.initMouseEvent(‘click’,true,true,
document.defaultView,0,0,0,0,0,false,
false,false,0,null,null
);

divElement.dispatchEvent(simulateDivClick);

(2)UIEvent.initUIEvent()

UIEvent.initUIEvent()用来初始化一个UI事件。该方法必须在事件新建(document.createEvent方法)之后、触发(dispatchEvent方法)之前调用。

event.initUIEvent(type, canBubble, cancelable, view, detail)

该方法的参数含义,可以参见MouseEvent构造函数的部分。其中,detail参数是一个数值,含义与事件类型有关,对于鼠标事件,这个值表示鼠标按键在某个位置按下的次数。

[js点滴]JavaScript之文档事件08相关推荐

  1. [js点滴]JavaScript事件详解

    Event对象 目录 事件是一种异步编程的实现方式,本质上是程序各个组成部分之间的通信.DOM支持大量的事件,本节介绍DOM的事件编程. EventTarget接口 DOM的事件操作(监听和触发),都 ...

  2. node.js服务端笔记文档学会写接口,学习分类:path、包、模块化、fs、express、中间件、jwt、开发模式、cors。

    node.js 学习笔记 node.js服务端笔记文档学会写接口,path.包.模块化.fs.express.中间件.JWT.开发模式.cors. gitee:代码接口笔记 1什么是node.js n ...

  3. html5在线显示word文档,JS实现获取word文档内容并输出显示到html页面示例

    本文实例讲述了js实现获取word文档内容并输出显示到html页面.分享给大家供大家参考,具体如下: title var w = new activexobject('word.application ...

  4. jquery.cookie 使用文档,$.cookie() 文档教程, js 操作 cookie 教程文档。

    jquery.cookie 使用文档,$.cookie() 文档教程, js 操作 cookie 教程文档. jquery.cookie中的操作: jquery.cookie.js是一个基于jquer ...

  5. pdf.js在线查看(文档流/地址)

    pdf.js在线查看(文档流/地址) 工作中需要在移动端在线查看pdf文件,但由于pdf文件存放在第三方的服务器中,由于各种原因无法直接返回pdf文件地址给前台,后来确定返给前台是一个base64的流 ...

  6. JS实现获取word文档内容并输出显示到html页面示例,和将页面数据写入txt文件

    JS实现获取word文档内容并输出显示到html页面示例 注意:这里使用了ActiveXObject组建,因此需要使用IE内核浏览器运行本代码. <!DOCTYPE html> <h ...

  7. js从服务器获取word文档,javascript - 使用Office.js API将Word文档(.docx)保存到后端服务器 - 堆栈内存溢出...

    我在将byte数组(使用Office.js从Microsoft Office的任务窗格中获取)保存到Word文档文件(在服务器端)时遇到了一些麻烦. 这就是我在做什么: 我正在使用此库获取Word文档 ...

  8. JavaScript的文档窗口事件

    文档窗口事件 Load 当指定的元素已加载时,触发 Resize 当调整浏览器窗口大小时,触发 Scroll 当用户滚动指定的元素时,触发 适用于所有可滚动的元素,window对象浏览器窗口 Unlo ...

  9. js、jq知识点文档

    JavaScript知识点 第一章JavaScript概述 1.了解JavaScript的作用 表单验证 实现网页动态效果 2.了解JavaScript的特点 概念:Javascript是一种基于对象 ...

最新文章

  1. 初学者宝典:C语言入门基础知识大全(下)
  2. 【数据库系统】SQL修改的注意事项
  3. php 函数 中文,PHP语言之PHP中文函数连载(二)
  4. PostgreSQL在Update时使用Substring函数截取字符串并且加上CASE WHEN THEN条件判断
  5. 在控制台打印半径为R的圆
  6. 你真的需要全栈开发吗?
  7. elementui如何在input 框中搜索_【挑战自学Python编程】第八天:while循环以及input()函数...
  8. 跟小丸子学基础口语16-20
  9. python的输出语句_python 中简单的输出语句
  10. 树莓派安装centos系统
  11. python可以做手机脚本吗,如何将Python自动化测试脚本放在手机上运行
  12. 梁建章:预计半年后中国会有条件开放国际旅游
  13. Java Seckill Module:seckill
  14. GHO文件转iso文件能启动安装
  15. jqgrid 加载mysql数据_利用jqgrid+加mysql的text类型实现简单自定义数据模型
  16. Ensiko:含有勒索软件功能的Webshell
  17. 诺基亚推出全球最快路由器 与思科争夺苹果等巨头订单
  18. c语言花园自动喷淋系统,智慧小区花园自动浇灌喷淋控制系统
  19. 【持续更新】JavaScript常见面试题整理
  20. 图卷积网络(GCN)简单理解

热门文章

  1. CoreML 机器学习 VISION
  2. 是时候全面了解一下window.console了!
  3. CarSim仿真快速入门(十八)-转向系统(1)
  4. java eclipse字体大小设置_eclipse字体大小如何设置-eclipse字体大小设置方法 - 河东软件园...
  5. radio设置颜色html,HTML下使用Radio设置选择样式。
  6. python设置画图风格_Python可视化33|matplotlib-rcParams及绘图风格(style)设置详解
  7. 学校机房电脑经常中病毒,有什么方法可以解决?
  8. torch中.data和.detach()的区别
  9. java 连接rac_jdbc连接遭遇RAC设备
  10. 【音频】AAC格式解析