饥人谷学习进阶第 12 天
事件对象
在触发DOM上某个事件时会产生一个事件对象event,这个对象包含着所有与事件有关的信息,包括产生事件的元素、事件类型等相关信息。所有浏览器都支持event对象,但支持方式不同。
跨浏览器的事件处理程序
前面内容我们可以看到,在不同的浏览器下,添加和移除事件处理程序方式不相同,要想写出跨浏览器的事件处理程序,首先我们要了解不同的浏览器下处理事件处理程序的区别
在添加事件处理程序事addEventListener和attachEvent主要有几个区别
-
参数个数不相同,这个最直观,addEventListener有三个参数,attachEvent只有两个,attachEvent添加的事件处理程序只能发生在冒泡阶段,addEventListener第三个参数可以决定添加的事件处理程序是在捕获阶段还是冒泡阶段处理(我们一般为了浏览器兼容性都设置为冒泡阶段)
-
第一个参数意义不同,addEventListener第一个参数是事件类型(比如click,load),而attachEvent第一个参数指明的是事件处理函数名称(onclick,onload)
-
事件处理程序的作用域不相同,addEventListener的作用域是元素本身,this是指的触发元素,而attachEvent事件处理程序会在全局变量内运行,this是window,所以刚才例子才会返回undefined,而不是元素id
-
为一个事件添加多个事件处理程序时,执行顺序不同,addEventListener添加会按照添加顺序执行,而attachEvent添加多个事件处理程序时顺序无规律(添加的方法少的时候大多是按添加顺序的反顺序执行的,但是添加的多了就无规律了),所以添加多个的时候,不依赖执行顺序的还好,若是依赖于函数执行顺序,最好自己处理,不要指望浏览器
function addEvent(node, type, handler) {
if (!node) return false;
if (node.addEventListener) {
node.addEventListener(type, handler, false);
return true;
}
else if (node.attachEvent) {
node.attachEvent('on'+type, handler);
return true;
}
return false;
}
首先我们解决了第一个问题参数个数不同,现在三个参数,采用事件冒泡阶段触发
第二个问题也得以解决,如果是IE,我们给type添加上on
第四个问题目前还没有解决方案,需要用户自己注意,一般情况下,大家也不会添加很多事件处理程序
但是没有解决第三个问题,由于处理程序作用域不同,如果handler内有this之类操作,那么就会出错。在IE下,实际上大多数函数都会有this操作
function addEvent(node, type, handler) {
if (!node) return false;
if (node.addEventListener) {
node.addEventListener(type, handler, false);
return true;
}
else if (node.attachEvent) {
node.attachEvent('on' + type, function() { handler.apply(node); });
return true;
}
return false;
}
这样处理就可以解决this的问题了,但是新的问题又来了,我们这样等于添加了一个匿名的事件处理程序,无法用detachEvent取消事件处理程序,有很多解决方案,我们可以借鉴大师的处理方式,jQuery创始人John Resig是这样做的
function addEvent(node, type, handler) {
if (!node) return false;
if (node.addEventListener) {
node.addEventListener(type, handler, false);
return true;
}
else if (node.attachEvent) {
node['e' + type + handler] = handler;
node[type + handler] = function() {
node['e' + type + handler](window.event);
};
node.attachEvent('on' + type, node[type + handler]);
return true;
}
return false;
}
在取消事件处理程序的时候
function removeEvent(node, type, handler) {
if (!node) return false;
if (node.removeEventListener) {
node.removeEventListener(type, handler, false);
return true;
}
else if (node.detachEvent) {
node.detachEvent('on' + type, node[type + handler]);
node[type + handler] = null;
}
return false;
}
DOM中的事件对象
兼容DOM的浏览器会产生一个event对象传入事件处理程序中。
event对象包含与创建它的特定事件有关的属性和方法,触发事件的类型不同,可用的属性和方法也不同,但是所有事件都回包含
属性/方法 | 类型 | 读/写 | 说明 |
---|---|---|---|
bubbles | Boolean | 只读 | 事件是否冒泡 |
cancelable | Boolean | 只读 | 是否可以取消事件的默认行为 |
currentTarget | Element | 只读 | 事件处理程序当前处理元素 |
detail | Integer | 只读 | 与事件相关细节信息 |
eventPhase | Integer | 只读 | 事件处理程序阶段:1.捕获阶段,2.处于目标阶段,3.冒泡阶段 |
preventDefault() | Function | 只读 | 取消事件默认行为 |
stopPropagation() | Function | 只读 | 取消事件进一步捕获或冒泡 |
target | Element | 只读 | 事件的目标元素 |
type | String | 只读 | 被触发的事件类型 |
view | AbstractView | 只读 | 与事件关联的抽象视图,等同于发生事件的window对象 |
在事件处理程序内部,this
始终等同于 currentTarget
,而target是事件的实际目标。
要阻止事件的默认行为,可以使用 preventDefault()
方法,前提是cancelable值为 true。
阻止默认事件:
<a href="http://baid.com">baidu</a>
<script>
document.querySelector('a').onclick= function(e){
e.preventDefault()
console.log(this.href)
if(/baidu.com/.test(this.href)){
location.href = this.href
}
}
</script>
<form action="/login">
<input type="text" name="username">
<input type="submit">
</form>
<script>
document.querySelector('form').addEventListener('submit', function(evt){
evt.preventDefault()
if(document.querySelector('input[name=username]').value === 'jirengu'){
this.submit()
}
})
</script>
stopPropagation()
方法可以停止事件在DOM层次的传播,即取消进一步的事件捕获或冒泡。可以在button的事件处理程序中调用stopPropagation()从而避免注册在body上的事件发生
var handler = function (e) {
alert(e.type);
e.stopPropagation();
}
addEvent(document.body, 'click', function () { alert('Clicked body')});
var btnClick = document.getElementById('btnClick');
addEvent(btnClick, 'click', handler);
若是注释掉e.stopPropagation(); 在点击button的时候,由于事件冒泡,body的click事件也会触发,但是调用这句后,事件会停止传播
IE中的事件对象
访问IE中的event对象有几种不同的方式,取决于指定事件处理程序的方法。直接为DOM元素添加事件处理程序时,event对象作为window对象的一个属性存在
var handler = function () {
var e = window.event;
alert(e.type);
}
var btnClick = document.getElementById('btnClick');
btnClick.onclick = handler;
通过window.event取得了event对象,并检测到了其类型,可是如果事件处理程序是通过attachEvent添加的,那么就会有一个event对象被传入事件处理程序中
var handler = function (e) {
alert(e.type);
}
var btnClick = document.getElementById('btnClick');
attachEvent(btnClick, handler);
也可以通过window对象访问event,方便起见,我们一般会传入event对象,IE中所有的事件都包含以下属性方法
属性/方法 | 类型 | 读/写 | 说明 |
---|---|---|---|
cancelBubble | Boolean | 读/写 | 默认为false,设置为true之后可以取消事件冒泡 |
returnValue | Boolean | 读/写 | 默认true,设为false可以取消事件默认行为 |
srcElement | Element | 只读 | 事件的目标元素 |
type | String | 只读 | 被触发的事件类型 |
跨浏览器的事件对象
function getEvent(e) {
return e || window.event;
}
function getTarget(e) {
return e.target || e.scrElement;
}
function preventDefault(e) {
if (e.preventDefault)
e.preventDefault();
else
e.returnValue = false;
}
function stopPropagation(e) {
if (e.stopPropagation)
e.stopPropagation();
else
e.cancelBubble = true;
}
事件代理 !
<div class = "container">
<div class = "box">box1</div>
<div class = "box">box2</div>
<div class = "box">box3</div>
</div>
<button id = "add">add</button>
<script>
function $(selector){
return document.querySelector(selector)
}
function $$(selector){
return document.querySelectorAll(selector)
}
$('.container').onclick = function(e){
console.log(this)
console.log(e.target)
if (e.target.classList.contains('box')){
console.log(e.target.innerText)
}
}
var i = 4
$(#add).onclick = function(){
var box = document.createElement('div')
box.classList.add('box')
box.innerText = 'box' + (i++)
$('.container').appendChild(box)
}
</script>
常见HTML的事件
鼠标事件:
onmousedown, onmouseup,
onclick:鼠标单击
ondblclick:鼠标双击事件
onmousewheel:鼠标滚轮滚动
onmousemove,
mouseover:鼠标在上面时
mouseout:鼠标移出时
mouseenter:鼠标进入时
mouseleave:鼠标移出离开时
区别:mouseover和mouseout如果元素中还有孩子,并把鼠标移到孩子上时(移出孩子)会再次触发mouseover(mouseout),应用场景:当需要计数元素中孩子的个数层数时
mouseenter和mouseleave不会产生上面的效果
触摸事件:(手机)
ontouchstart, ontouchend, ontouchmove
键盘事件:
onkeydown:键盘按下按键时触发
onkeyup:键盘按下按键松开时触发
onkeypress:键盘按下一个键并释放时触发
页面相关事件:
onload(页面上的所有资源加载完成时触发,触发时机特别晚), onmove(浏览器窗口被移动时触发), onresize(浏览器的窗口大小被改变时触发), onscroll(滚动条位置发生变化时触发)
注意:scroll和resize会触发多次,可以用函数节流优化性能
DOMContentLoaded(DOM结构解析渲染完成时)
表单相关事件
onblur(元素失去焦点时触发), onchange(元素失去焦点且元素内容发生改变时触发), onfocus(元素获得焦点时触发), onreset(表单中reset属性被激活时触发), onsubmit(表单被提交时触发);oninput(在input元素内容修改后立即被触发,兼容IE9+)
编辑事件
onbeforecopy:当页面当前的被选择内容将要复制到浏览者系统的剪贴板前触发此事件;
onbeforecut:当页面中的一部分或者全部的内容将被移离当前页面[剪贴]并移动到浏览者的系统剪贴板时触发此事件;
onbeforeeditfocus:当前元素将要进入编辑状态;
onbeforepaste:内容将要从浏览者的系统剪贴板传送[粘贴]到页面中时触发此事件;
onbeforeupdate:当浏览者粘贴系统剪贴板中的内容时通知目标对象;
oncontextmenu:当浏览者按下鼠标右键出现菜单时或者通过键盘的按键触发页面菜单时触发的事件;
oncopy:当页面当前的被选择内容被复制后触发此事件;
oncut:当页面当前的被选择内容被剪切时触发此事件;
onlosecapture:当元素失去鼠标移动所形成的选择焦点时触发此事件;
onpaste:当内容被粘贴时触发此事件;
onselect:当文本内容被选择时的事件;
onselectstart:当文本内容选择将开始发生时触发的事件;
拖动事件
ondrag:当某个对象被拖动时触发此事件 [活动事件];
ondragdrop:一个外部对象被鼠标拖进当前窗口时触发;
ondragend:当鼠标拖动结束时触发此事件;
ondragenter:当对象被鼠标拖动的对象进入其容器范围内时触发此事件;
ondragleave:当对象被鼠标拖动的对象离开其容器范围内时触发此事件;
ondragover:当某被拖动的对象在另一对象容器范围内拖动时触发此事件;
ondragstart:当某对象将被拖动时触发此事件;
ondrop:在一个拖动过程中,释放鼠标键时触发此事件
网友评论