JavaScript-事件(三)
2、DragEvent 接口
拖拉事件都继承了DragEvent接口,这个接口又继承了MouseEvent接口和Event接口。
浏览器原生提供一个DragEvent()构造函数,用来生成拖拉事件的实例对象。
new DragEvent(type, options)
DragEvent()构造函数接受两个参数,第一个参数是字符串,表示事件的类型,该参数必须;第二个参数是事件的配置对象,用来设置事件的属性,该参数可选。配置对象除了接受MouseEvent接口和Event接口的配置属性,还可以设置dataTransfer属性要么是null,要么是一个DataTransfer接口的实例。
DataTransfer的实例对象用来读写拖拉事件中传输的数据,详见下文《DataTransfer 接口》的部分。
3、DataTransfer 接口概述
所有拖拉事件的实例都有一个DragEvent.dataTransfer属性,用来读写需要传递的数据。这个属性的值是一个DataTransfer接口的实例。
浏览器原生提供一个DataTransfer()构造函数,用来生成DataTransfer实例对象。
var dataTrans = new DataTransfer();
DataTransfer()构造函数不接受参数。
拖拉的数据分成两方面:数据的种类(又称格式)和数据的值。数据的种类是一个 MIME 字符串(比如text/plain、image/jpeg),数据的值是一个字符串。一般来说,如果拖拉一段文本,则数据默认就是那段文本;如果拖拉一个链接,则数据默认就是链接的 URL。
拖拉事件开始时,开发者可以提供数据类型和数据值。拖拉过程中,开发者通过dragenter和dragover事件的监听函数,检查数据类型,以确定是否允许放下(drop)被拖拉的对象。比如,在只允许放下链接的区域,检查拖拉的数据类型是否为text/uri-list。
发生drop事件时,监听函数取出拖拉的数据,对其进行处理。
4、DataTransfer 的实例属性
4.1 DataTransfer.dropEffect 设置接受拖拉的区域的效果
DataTransfer.dropEffect属性用来设置放下(drop)被拖拉节点时的效果,会影响到拖拉经过相关区域时鼠标的形状。它可能取下面的值。
- copy:复制被拖拉的节点
- move:移动被拖拉的节点
- link:创建指向被拖拉的节点的链接
- none:无法放下被拖拉的节点
除了上面这些值,设置其他的值都是无效的。
target.addEventListener('dragover', function (e) {
e.preventDefault();
e.stopPropagation();
e.dataTransfer.dropEffect = 'copy';
});
上面代码中,被拖拉元素一旦drop,接受的区域会复制该节点。
dropEffect属性一般在dragenter和dragover事件的监听函数中设置,对于dragstart、drag、dragleave这三个事件,该属性不起作用。因为该属性只对接受被拖拉的节点的区域有效,对被拖拉的节点本身是无效的。进入目标区域后,拖拉行为会初始化成设定的效果。
4.2 DataTransfer.effectAllowed 设置被拖拉的节点允许的效果
DataTransfer.effectAllowed属性设置本次拖拉中允许的效果。它可能取下面的值。
- copy:复制被拖拉的节点
- move:移动被拖拉的节点
- link:创建指向被拖拉节点的链接
- copyLink:允许
copy或link - copyMove:允许
copy或move - linkMove:允许
link或move - all:允许所有效果
- none:无法放下被拖拉的节点
- uninitialized:默认值,等同于
all
如果某种效果是不允许的,用户就无法在目标节点中达成这种效果。
这个属性与dropEffect属性是同一件事的两个方面。前者设置被拖拉的节点允许的效果,后者设置接受拖拉的区域的效果,它们往往配合使用。
dragstart事件的监听函数,可以用来设置这个属性。其他事件的监听函数里面设置这个属性是无效的。
source.addEventListener('dragstart', function (e) { // 被拖拉节点上设置
e.dataTransfer.effectAllowed = 'move';
});
target.addEventListener('dragover', function (e) { // 接受区域节点上设置
e.dataTransfer.dropEffect = 'move';
});
只要dropEffect属性和effectAllowed属性之中,有一个为none,就无法在目标节点上完成drop操作。
4.3 DataTransfer.files 本地文件
DataTransfer.files属性是一个 FileList 对象,包含一组本地文件,可以用来在拖拉操作中传送。如果本次拖拉不涉及文件,则该属性为空的 FileList 对象。
例子:接收拖拉文件
// HTML 代码如下
// <div id="output" style="min-height: 200px;border: 1px solid black;">
// 文件拖拉到这里
// </div>
var div = document.getElementById('output');
div.addEventListener("dragenter", function( event ) {
div.textContent = '';
event.stopPropagation();
event.preventDefault();
}, false);
div.addEventListener("dragover", function( event ) {
event.stopPropagation();
event.preventDefault();
}, false);
div.addEventListener("drop", function( event ) {
event.stopPropagation();
event.preventDefault();
var files = event.dataTransfer.files;
for (var i = 0; i < files.length; i++) {
div.textContent += files[i].name + ' ' + files[i].size + '字节\n';
}
}, false);
上面代码中,通过dataTransfer.files属性读取被拖拉的文件的信息。如果想要读取文件内容,就要使用FileReader对象。
div.addEventListener('drop', function(e) {
e.preventDefault();
e.stopPropagation();
var fileList = e.dataTransfer.files;
if (fileList.length > 0) {
var file = fileList[0];
var reader = new FileReader();
reader.readAsDataURL(file);// 解析为url
reader.onloadend = function(e) {
if (e.target.readyState === FileReader.DONE) {
var content = reader.result;
div.innerHTML = '<img src="'+ content +'"> File: ' + file.name + '\n\n' + content;
}
}
reader.readAsBinaryString(file);
}
});
4.4 DataTransfer.types 数据格式
DataTransfer.types属性是一个只读的数组,每个成员是一个字符串,里面是拖拉的数据格式(通常是 MIME 值)。比如,如果拖拉的是文字,对应的成员就是text/plain。
下面是一个例子,通过检查dataTransfer属性的类型,决定是否允许在当前节点执行drop操作。
function contains(list, value){
for (var i = 0; i < list.length; ++i) {
if(list[i] === value) return true;
}
return false;
}
function doDragOver(event) {
var isLink = contains(event.dataTransfer.types, 'text/uri-list');
if (isLink) event.preventDefault();
}
上面代码中,只有当被拖拉的节点是一个链接时,才允许在当前节点放下。
4.5 DataTransfer.items
DataTransfer.items属性返回一个类似数组的只读对象(DataTransferItemList 实例),每个成员就是本次拖拉的一个对象(DataTransferItem 实例)。如果本次拖拉不包含对象,则返回一个空对象。
DataTransferItemList 实例具有以下的属性和方法。
length:返回成员的数量add(data, type):增加一个指定内容和类型(比如text/html和text/plain)的字符串作为成员add(file):add方法的另一种用法,增加一个文件作为成员remove(index):移除指定位置的成员clear():移除所有的成员
DataTransferItem 实例具有以下的属性和方法。
kind:返回成员的种类(string还是file)。type:返回成员的类型(通常是 MIME 值)。getAsFile():如果被拖拉是文件,返回该文件,否则返回null。getAsString(callback):如果被拖拉的是字符串,将该字符传入指定的回调函数处理。该方法是异步的,所以需要传入回调函数。
下面是一个例子。
div.addEventListener('drop', function (e) {
e.preventDefault();
if (e.dataTransfer.items != null) {
for (var i = 0; i < e.dataTransfer.items.length; i++) {
console.log(e.dataTransfer.items[i].kind + ': ' + e.dataTransfer.items[i].type);
}
}
});
5、DataTransfer 的实例方法
5.1 DataTransfer.setData() 设置拖拉事件所带有的数据
DataTransfer.setData()方法用来设置拖拉事件所带有的数据。该方法没有返回值。
event.dataTransfer.setData('text/plain', 'Text to drag');
上面代码为当前的拖拉事件加入纯文本数据。
该方法接受两个参数,都是字符串。第一个参数表示数据类型(比如text/plain),第二个参数是具体数据。如果指定类型的数据在dataTransfer属性不存在,那么这些数据将被加入,否则原有的数据将被新数据替换。
如果是拖拉文本框或者拖拉选中的文本,会默认将对应的文本数据,添加到dataTransfer属性,不用手动指定。
<div draggable="true">
aaa
</div>
上面代码中,拖拉这个<div>元素会自动带上文本数据aaa。
使用setData方法,可以替换到原有数据。
<div
draggable="true"
ondragstart="event.dataTransfer.setData('text/plain', 'bbb')"
>
aaa
</div>
上面代码中,拖拉数据实际上是bbb,而不是aaa。
下面是添加其他类型的数据。由于text/plain是最普遍支持的格式,为了保证兼容性,建议最后总是保存一份纯文本格式的数据。
var dt = event.dataTransfer;
// 添加链接
dt.setData('text/uri-list', 'http://www.example.com');
dt.setData('text/plain', 'http://www.example.com');
// 添加 HTML 代码
dt.setData('text/html', 'Hello there, <strong>stranger</strong>');
dt.setData('text/plain', 'Hello there, <strong>stranger</strong>');
// 添加图像的 URL
dt.setData('text/uri-list', imageurl);
dt.setData('text/plain', imageurl);
可以一次提供多种格式的数据。
var dt = event.dataTransfer;
dt.setData('application/x-bookmark', bookmarkString);
dt.setData('text/uri-list', 'http://www.example.com');
dt.setData('text/plain', 'http://www.example.com');
上面代码中,通过在同一个事件上面,存放三种类型的数据,使得拖拉事件可以在不同的对象上面,drop不同的值。注意,第一种格式是一个自定义格式,浏览器默认无法读取,这意味着,只有某个部署了特定代码的节点,才可能drop(读取到)这个数据。
5.2 DataTransfer.getData() 返回指定类型的数据
DataTransfer.getData()方法接受一个字符串(表示数据类型)作为参数,返回事件所带的指定类型的数据(通常是用setData方法添加的数据)。如果指定类型的数据不存在,则返回空字符串。通常只有drop事件触发后,才能取出数据。
下面是一个drop事件的监听函数,用来取出指定类型的数据。
function onDrop(event) {
var data = event.dataTransfer.getData('text/plain');
event.target.textContent = data;
event.preventDefault();
}
上面代码取出拖拉事件的文本数据,将其替换成当前节点的文本内容。注意,这时还必须取消浏览器的默认行为,因为假如用户拖拉的是一个链接,浏览器默认会在当前窗口打开这个链接。
getData方法返回的是一个字符串,如果其中包含多项数据,就必须手动解析。
function doDrop(event) {
var lines = event.dataTransfer.getData('text/uri-list').split('\n');
for (let line of lines) {
let link = document.createElement('a');
link.href = line;
link.textContent = line;
event.target.appendChild(link);
}
event.preventDefault();
}
上面代码中,getData方法返回的是一组链接,就必须自行解析。
类型值指定为URL,可以取出第一个有效链接。
var link = event.dataTransfer.getData('URL');
下面的例子是从多种类型的数据里面取出数据。
function doDrop(event) {
var types = event.dataTransfer.types;
var supportedTypes = ['text/uri-list', 'text/plain'];
types = supportedTypes.filter(function (value) { types.includes(value) });
if (types.length) {
var data = event.dataTransfer.getData(types[0]);
}
event.preventDefault();
}
5.3 DataTransfer.clearData() 清除指定或全部数据
DataTransfer.clearData()方法接受一个字符串(表示数据类型)作为参数,删除事件所带的指定类型的数据。如果没有指定类型,则删除所有数据。如果指定类型不存在,则调用该方法不会产生任何效果。
event.dataTransfer.clearData('text/uri-list');
上面代码清除事件所带的text/uri-list类型的数据。
该方法不会移除拖拉的文件,因此调用该方法后,DataTransfer.types属性可能依然会返回Files类型(前提是存在文件拖拉)。
注意,该方法只能在dragstart事件的监听函数之中使用,因为这是拖拉操作的数据唯一可写的时机。
5.4 DataTransfer.setDragImage() 设置拖动过程中的图片
拖动过程中(dragstart事件触发后),浏览器会显示一张图片跟随鼠标一起移动,表示被拖动的节点。这张图片是自动创造的,通常显示为被拖动节点的外观,不需要自己动手设置。
DataTransfer.setDragImage()方法可以自定义这张图片。它接受三个参数。第一个是<img>节点或者<canvas>节点,如果省略或为null,则使用被拖动的节点的外观;第二个和第三个参数为鼠标相对于该图片左上角的横坐标和右坐标。
下面是一个例子。
/* HTML 代码如下
<div id="drag-with-image" class="dragdemo" draggable="true">
drag me
</div>
*/
var div = document.getElementById('drag-with-image');
div.addEventListener('dragstart', function (e) {
var img = document.createElement('img');
img.src = 'http://path/to/img';
e.dataTransfer.setDragImage(img, 0, 0);
}, false);
十、其他常见事件
1、资源事件
1.1 beforeunload 事件 (关闭窗口前调用)
beforeunload事件在窗口、文档、各种资源将要卸载前触发。它可以用来防止用户不小心卸载资源。
如果该事件对象的returnValue属性是一个非空字符串,那么浏览器就会弹出一个对话框,询问用户是否要卸载该资源。但是,用户指定的字符串可能无法显示,浏览器会展示预定义的字符串。如果用户点击“取消”按钮,资源就不会卸载。
window.addEventListener('beforeunload', function (event) {
event.returnValue = '你确定离开吗?';
});
上面代码中,用户如果关闭窗口,浏览器会弹出一个窗口,要求用户确认。
浏览器对这个事件的行为很不一致,有的浏览器调用event.preventDefault(),也会弹出对话框。IE 浏览器需要显式返回一个非空的字符串,才会弹出对话框。而且,大多数浏览器在对话框中不显示指定文本,只显示默认文本。因此,可以采用下面的写法,取得最大的兼容性。
window.addEventListener('beforeunload', function (e) {
var confirmationMessage = '确认关闭窗口?';
e.returnValue = confirmationMessage;
return confirmationMessage;
});
注意,许多手机浏览器默认忽略这个事件,桌面浏览器也有办法忽略这个事件。所以,它可能根本不会生效,不能依赖它来阻止用户关闭窗口。另外,一旦使用了beforeunload事件,浏览器就不会缓存当前网页,使用“回退”按钮将重新向服务器请求网页。这是因为监听这个事件的目的,一般是修改初始状态,这时缓存初始页面就没意义了。
基本上,只有一种场合可以监听unload事件,其他情况都不应该监听:用户修改了表单,还没有保存就要离开。
1.2 unload 事件 (即将关闭窗口时调用)
unload事件在窗口关闭或者document对象将要卸载时触发。它的触发顺序排在beforeunload、pagehide事件后面。
unload事件发生时,文档处于一个特殊状态。所有资源依然存在,但是对用户来说都不可见,UI 互动全部无效。这个事件是无法取消的,即使在监听函数里面抛出错误,也不能停止文档的卸载。
window.addEventListener('unload', function(event) {
console.log('文档将要卸载');
});
手机上,浏览器或系统可能会直接丢弃网页,这时该事件根本不会发生。而且跟beforeunload事件一样,一旦使用了unload事件,浏览器就不会缓存当前网页,理由同上。因此,任何情况下都不应该依赖这个事件,指定网页卸载时要执行的代码,可以考虑完全不使用这个事件。
1.3 load 事件,error 事件 ,abort事件 (页面或某个资源加载成功/失败/取消时调用)
load事件在页面或某个资源加载成功时触发。注意,页面或资源从浏览器缓存加载,并不会触发load事件。
window.addEventListener('load', function(event) {
console.log('所有资源都加载完成');
});
error事件是在页面或资源加载失败时触发。
abort事件是在用户取消加载时触发。
这三个事件实际上属于进度事件,不仅发生在document对象,还发生在各种外部资源上面。浏览网页就是一个加载各种资源的过程,图像(image)、样式表(style sheet)、脚本(script)、视频(video)、音频(audio)、Ajax请求(XMLHttpRequest)等等。这些资源和document对象、window对象、XMLHttpRequestUpload 对象,都会触发load事件和error事件。
触发这三个事件的对象有:
- window
- document
- body
- img
- style
- script
- video
- audio
- Ajax
- 等等
2、session 历史事件
2.1 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事件实例也有一个persisted属性,将这个属性设为true,就表示页面要保存在缓存中;设为false,表示网页不保存在缓存中,这时如果设置了unload 事件的监听函数,该函数将在 pagehide 事件后立即运行。
如果页面包含<frame>或<iframe>元素,则<frame>页面的pageshow事件和pagehide事件,都会在主页面之前触发。
注意,这两个事件只在浏览器的history(历史)对象发生变化时触发,跟网页是否可见没有关系。
2.2 popstate 事件(在浏览器的history对象的当前记录发生显式切换时触发)
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 不触发该事件。
2.3 hashchange 事件 (hash发生变化时触发)
hashchange事件在 URL 的 hash 部分(即#号后面的部分,包括#号)发生变化时触发。该事件一般在window对象上监听。
hashchange的事件实例具有两个特有属性:oldURL属性和newURL属性,分别表示变化前后的完整 URL。
// URL 是 http://www.example.com/
window.addEventListener('hashchange', myFunction);
function myFunction(e) {
console.log(e.oldURL);
console.log(e.newURL);
}
location.hash = 'part2';
// http://www.example.com/
// http://www.example.com/#part2
3、网页状态事件
3.1 DOMContentLoaded 事件 (DOM内容加载完成后触发)
网页下载并解析完成以后,浏览器就会在document对象上触发 DOMContentLoaded 事件。这时,仅仅完成了网页的解析(整张页面的 DOM 生成了),所有外部资源(样式表、脚本、iframe 等等)可能还没有下载结束。也就是说,这个事件比load事件,发生时间早得多。
document.addEventListener('DOMContentLoaded', function (event) {
console.log('DOM生成');
});
注意,网页的 JavaScript 脚本是同步执行的,脚本一旦发生堵塞,将推迟触发DOMContentLoaded事件。
document.addEventListener('DOMContentLoaded', function (event) {
console.log('DOM 生成');
});
// 这段代码会推迟触发 DOMContentLoaded 事件
for(var i = 0; i < 1000000000; i++) {
// ...
}
3.2 readystatechange 事件(Document 对象和 XMLHttpRequest 对象的readyState属性发生变化时触发)
readystatechange事件当 Document 对象和 XMLHttpRequest 对象的readyState属性发生变化时触发。document.readyState有三个可能的值:loading(网页正在加载)、interactive(网页已经解析完成,但是外部资源仍然处在加载状态)和complete(网页和所有外部资源已经结束加载,load事件即将触发)。
document.onreadystatechange = function () {
if (document.readyState === 'interactive') {
// ...
}
}
这个事件可以看作DOMContentLoaded事件的另一种实现方法。
4、窗口事件
4.1 scroll 事件 (文档或文档元素滚动时触发)
scroll事件在文档或文档元素滚动时触发,主要出现在用户拖动滚动条。
window.addEventListener('scroll', callback);
该事件会连续地大量触发,所以它的监听函数之中不应该有非常耗费计算的操作。推荐的做法是使用requestAnimationFrame或setTimeout控制该事件的触发频率,然后可以结合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() { // 结合此方法控制在每秒60次
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次。具体来说,就是scroll事件只要频率低于每秒60次,就会触发optimizedScroll事件,从而执行optimizedScroll事件的监听函数。
改用setTimeout方法,可以放置更大的时间间隔。
(function() {
window.addEventListener('scroll', scrollThrottler, false);
var scrollTimeout;
function scrollThrottler() {
if (!scrollTimeout) {
scrollTimeout = setTimeout(function () {
scrollTimeout = null;
actualScrollHandler();
}, 66);
}
}
function actualScrollHandler() {
// ...
}
}());
上面代码中,每次scroll事件都会执行scrollThrottler函数。该函数里面有一个定时器setTimeout,每66毫秒触发一次(每秒15次)真正执行的任务actualScrollHandler。
下面是一个更一般的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));
本书前面介绍过debounce的概念,throttle与它区别在于,throttle是“节流”,确保一段时间内只执行一次,而debounce是“防抖”,要连续操作结束后再执行。以网页滚动为例,debounce要等到用户停止滚动后才执行,throttle则是如果用户一直在滚动网页,那么在滚动过程中还是会执行。
4.2 resize 事件(窗口大小变化时触发)
resize事件在改变浏览器窗口大小时触发,主要发生在window对象上面。
var resizeMethod = function () {
if (document.body.clientWidth < 768) {
console.log('移动设备的视口');
}
};
window.addEventListener('resize', resizeMethod, true);
该事件也会连续地大量触发,所以最好像上面的scroll事件一样,通过throttle函数控制事件触发频率。
4.3 fullscreenchange 事件(元素进入/退出全屏时触发),fullscreenerror 事件(无法切换全屏时触发)
fullscreenchange事件在元素进入或退出全屏状态时触发,该事件发生在document对象上面。
注意,此事件非浏览器的进入/退出全屏时触发的事件。
document.addEventListener('fullscreenchange', function (event) {
console.log(document.fullscreenElement); // 全屏的元素,如果为null时表示已退出全屏
});
document.addEventListener('click', function (event) {
document.querySelector('div').requestFullscreen(); // 设置元素为全屏展示
});
fullscreenerror事件在浏览器无法切换到全屏状态时触发。
5、剪贴板事件
以下三个事件属于剪贴板操作的相关事件。
cut:将选中的内容从文档中移除,加入剪贴板时触发。【剪切】copy:进行复制动作时触发。【拷贝】paste:剪贴板内容粘贴到文档后触发。【粘贴】
这三个事件都是**ClipboardEvent接口的实例**。ClipboardEvent有一个实例属性clipboardData,是一个 DataTransfer 对象,存放剪贴的数据。具体的 API 接口和操作方法,请参见《拖拉事件》的 DataTransfer 对象部分。
document.addEventListener('copy', function (e) {
e.clipboardData.setData('text/plain', 'Hello, world!');
e.clipboardData.setData('text/html', '<b>Hello, world!</b>');
e.preventDefault();
});
上面的代码使得复制进入剪贴板的,都是开发者指定的数据,而不是用户想要拷贝的数据。
6、焦点事件
焦点事件发生在元素节点和document对象上面,与获得或失去焦点相关。它主要包括以下四个事件。
focus:元素节点获得焦点后触发,该事件不会冒泡。blur:元素节点失去焦点后触发,该事件不会冒泡。focusin:元素节点将要获得焦点时触发,发生在focus事件之前。该事件会冒泡。focusout:元素节点将要失去焦点时触发,发生在blur事件之前。该事件会冒泡。
这四个事件都继承了FocusEvent接口。FocusEvent实例具有以下属性。
FocusEvent.target:事件的目标节点。FocusEvent.relatedTarget:对于focusin事件,返回失去焦点的节点;对于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);
上面代码针对表单的文本输入框,接受焦点时设置背景色,失去焦点时去除背景色。
7、CustomEvent 接口(自定义事件)
CustomEvent 接口用于生成自定义的事件实例。那些浏览器预定义的事件,虽然可以手动生成,但是往往不能在事件上绑定数据。如果需要在触发事件的同时,传入指定的数据,就可以使用 CustomEvent 接口生成的自定义事件对象。
浏览器原生提供CustomEvent()构造函数,用来生成 CustomEvent 事件实例。
new CustomEvent(type, options)
CustomEvent()构造函数接受两个参数。第一个参数是字符串,表示事件的名字,这是必须的。第二个参数是事件的配置对象,这个参数是可选的。CustomEvent的配置对象除了接受 Event 事件的配置属性,只有一个自己的属性。
detail:表示事件的附带数据,默认为null。
下面是一个例子。
var event = new CustomEvent('build', { 'detail': 'hello' });
function eventHandler(e) {
console.log(e.detail);
}
document.body.addEventListener('build', function (e) {
console.log(e.detail);
});
document.body.dispatchEvent(event);
上面代码中,我们手动定义了build事件。该事件触发后,会被监听到,从而输出该事件实例的detail属性(即字符串hello)。
下面是另一个例子。
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);
上面代码也说明,CustomEvent 的事件实例,除了具有 Event 接口的实例属性,还具有detail属性。
十一、GlobalEventHandlers 接口 (全局事件处理接口)
指定事件的回调函数,推荐使用的方法是元素的addEventListener方法。
div.addEventListener('click', clickHandler, false);
除了之外,还有一种方法可以直接指定事件的回调函数。
div.onclick = clickHandler;
这个接口是由GlobalEventHandlers接口提供的。它的优点是使用比较方便,缺点是只能为每个事件指定一个回调函数,并且无法指定事件触发的阶段(捕获阶段还是冒泡阶段)。
HTMLElement、Document和Window都继承了这个接口,也就是说,各种 HTML 元素、document对象、window对象上面都可以使用GlobalEventHandlers接口提供的属性。下面就列出这个接口提供的主要的事件属性。
1、GlobalEventHandlers.onabort (中断事件)
某个对象的abort事件(停止加载)发生时,就会调用onabort属性指定的回调函数。
各种元素的停止加载事件,到底如何触发,目前并没有统一的规定。因此实际上,这个属性现在一般只用在<img>元素上面。
// HTML 代码如下
// <img src="example.jpg" id="img">
var img = document.getElementById('img');
img.onabort = function () {
console.log('图片加载中断');
}
2、GlobalEventHandlers.onerror (错误事件)
error事件发生时,就会调用onerror属性指定的回调函数。
error事件分成两种。
一种是 JavaScript 的运行时错误,这会传到window对象,导致window.onerror()。
window.onerror = function (message, source, lineno, colno, error) {
// ...
}
window.onerror的处理函数共接受五个参数,含义如下。
- message:错误信息字符串
- source:报错脚本的 URL
- lineno:报错的行号,是一个整数
- colno:报错的列号,是一个整数
- error: 错误对象
另一种是资源加载错误,比如<img>或<script>加载的资源出现加载错误。这时,Error 对象会传到对应的元素,导致该元素的onerror属性开始执行。
element.onerror = function (event) {
// ...
}
注意,一般来说,资源的加载错误不会触发window.onerror。
3、GlobalEventHandlers.onload(加载完成事件)、GlobalEventHandlers.onloadstart(开始加载事件)
元素完成加载时,会触发load事件,执行onload()。它的典型使用场景是window对象和<img>元素。对于window对象来说,只有页面的所有资源加载完成(包括图片、脚本、样式表、字体等所有外部资源),才会触发load事件。
对于<img>和<video>等元素,加载开始时还会触发loadstart事件,导致执行onloadstart。
4、GlobalEventHandlers.onfocus(获取焦点事件),GlobalEventHandlers.onblur(失去焦点事件)
当前元素获得焦点时,会触发element.onfocus;失去焦点时,会触发element.onblur。
element.onfocus = function () {
console.log("onfocus event detected!");
};
element.onblur = function () {
console.log("onblur event detected!");
};
注意,如果不是可以接受用户输入的元素,要触发onfocus,该元素必须有tabindex属性。
5、GlobalEventHandlers.onscroll(滚动事件)
页面或元素滚动时,会触发scroll事件,导致执行onscroll()。
6、GlobalEventHandlers.oncontextmenu(右键菜单事件),GlobalEventHandlers.onshow(显示右键菜单时触发)
用户在页面上按下鼠标的右键,会触发contextmenu事件,导致执行oncontextmenu()。如果该属性执行后返回false,就等于禁止了右键菜单。document.oncontextmenu与window.oncontextmenu效果一样。
document.oncontextmenu = function () {// 禁用右键菜单
return false;
};
上面代码中,oncontextmenu属性执行后返回false,右键菜单就不会出现。
元素的右键菜单显示时,会触发该元素的onshow监听函数。
7、其他的事件属性
鼠标的事件属性。
- onclick
- ondblclick
- onmousedown
- onmouseenter
- onmouseleave
- onmousemove
- onmouseout
- onmouseover
- onmouseup
- onwheel
键盘的事件属性。
- onkeydown
- onkeypress
- onkeyup
焦点的事件属性。
- onblur
- onfocus
表单的事件属性。
- oninput
- onchange
- onsubmit
- onreset
- oninvalid
- onselect
触摸的事件属性。
- ontouchcancel
- ontouchend
- ontouchmove
- ontouchstart
拖动的事件属性分成两类:一类与被拖动元素相关,另一类与接收被拖动元素的容器元素相关。
被拖动元素的事件属性。
- ondragstart:拖动开始
- ondrag:拖动过程中,每隔几百毫秒触发一次
- ondragend:拖动结束
接收被拖动元素的容器元素的事件属性。
- ondragenter:被拖动元素进入容器元素。
- ondragleave:被拖动元素离开容器元素。
- ondragover:被拖动元素在容器元素上方,每隔几百毫秒触发一次。
- ondrop:松开鼠标后,被拖动元素放入容器元素。
<dialog>对话框元素的事件属性。
- oncancel
- onclose
- 点赞
- 收藏
- 关注作者
评论(0)