事件相关浏览器兼容性代码,各种代码事件示例,右键菜单、拖拽功能、事件委托、模拟事件等代码示例……
一 一般事件行为的兼容性代码
/**
* 跨浏览器事件处理方法
* 注:只关注冒泡阶段
*/
var EventUtil = {
// 添加事件
addHandler: function(element, type, handler) {
if (element.addEventListener) {
// DOM2 添加事件
element.addEventListener(type, handler, false);
} else if (element.attachEvent) {
// IE 添加事件
element.attachEvent('on' + type, handler);
} else {
// DOM0 添加事件
element['on' + type] = handler;
}
},
// 删除事件
removeHandler: function(element, type, handler) {
if (element.removeEventListener) {
// DOM2 删除事件
element.removeEventListener(type, handler, false);
} else if (element.detachEvent) {
// IE 删除事件
element.detachEvent('on' + type, handler);
} else {
// DOM0 删除事件
element['on' + type] = null;
}
},
// 获取事件对象
getEvent: function(e) {
return e ? e : window.e;
},
// 获取事件目标(DOM)
getTarget: function(e) {
return e.target || e.srcElement;
}
// 阻止事件默认行为
preventDefault: function(e) {
if (e.preventDefault) {
e.preventDefault();
} else {
e.returnValue = false;
}
},
// 阻止冒泡
stopPropagation: function(e) {
if (e.stopPropagation) {
e.stopPropagation();
} else {
e.cancelBubble = true;
}
}
}
二 scroll 事件示例
滚动带滚动条的元素,在该元素中触发。可通过元素的 scrollLeft / scrollTop 来监听滚动
var div = document.getElementById('myDiv');
EventUtil.addHandler(div, 'scroll', function(e){
console.log(div.scrollTop);
})
如果是在 window 对象上:
EventUtil.addHandler(window, 'scroll', function(e){
if (document.compatMode == 'CSS1Compat') {
console.log(document.documentElement.scrollTop);
} else {
console.log(document.body.scrollTop);
}
})
三 获取鼠标位置
var div = document.getElementById('myDiv');
// 浏览器视口鼠标坐标
EventUtil.addHandler(div, 'click', function(e){
e = EventUtil.getEvent(e);
console.log(e.clientX, e.clientY);
})
// 页面中鼠标坐标,包含滚动条卷起的部分
EventUtil.addHandler(div, 'click', function(e){
e = EventUtil.getEvent(e);
var pageX = e.pageX,
pageY = e.pageY;
// 为了兼容IE8
if (pageX === undefined) {
pageX = e.clientX + (document.body.scrollLeft || document.documentElement.scrollLeft);
}
if (pageY === undefined) {
pageY = e.clientY + (document.body.scrollTop || document.documentElement.scrollTop);
}
console.log(e.clientX, e.clientY);
})
// 屏幕中鼠标坐标
EventUtil.addHandler(div, 'click', function(e){
e = EventUtil.getEvent(e);
console.log(e.screenX, e.screenY);
})
四 鼠标滚轮兼容性代码
// 鼠标滚轮值
EventUtil.getWheelDelta = function(e) {
if (e.wheelDelta) {
// 向前一次+120, Opera9.5- 浏览器相反
return (client.engine.opera && client.engine.opera < 9.5 ? -e.wheelDelta : e.wheelDelta);
} else {
// Firefox 向滚一次是-3,乘以40与其他浏览器保持一致
return -e.detail * 40;
}
}
五 获取键盘键码
EventUtil.getCharCode = function(e) {
if (typeof e.charCode === 'number') {
return e.charCode;
} else {
return e.keyCode;
}
}
六 右键菜单
<div id="myDiv" style="position:absolute;display:none;">右键这里</div>
<ul id="myMenu">
<li>菜单1</li>
<li>菜单2</li>
<li>菜单3</li>
</ul>
var div = document.getElementById('myDiv');
EventUtil.addHandler(div, 'contextmenu', function(e){
// 阻止默认行为
e = EventUtil.getEvent(e);
EventUtil.preventDefault();
// 展示位置
var menu = document.getElementById('myMenu');
menu.style.left = e.clientX + 'px';
menu.style.top = e.clientY + 'px';
menu.style.display = 'inline';
});
// 左键点击菜单消失
EventUtil.addHandler(document, 'click', function(e){
document.getElementById('myMenu').style.display = 'none';
});
七 阻止右键菜单及选中内容
可以阻止“审查元素”及复制页面内容。
// 注意:可在控制台上运行 document.oncontextmenu="" 破解
document.oncontextmenu = new Function("event.returnValue=false");
document.onselectstart = new Function("event.returnValue=false");
document.querySelector("body").onselectstart = function() {
return false;
};
通过 css 也可以阻止选中页面内容。
* {
moz-user-select: -moz-none;
-moz-user-select: none;
-o-user-select:none;
-khtml-user-select:none;
-webkit-user-select:none;
-ms-user-select:none;
user-select:none;
}
以上,包括有阻止 ctrl + c 快捷键方式的,均无法阻止调用开发者工具,然后复制 dom 的行为。
八 事件内存、性能原理及代码
添加到页面上的事件处理程序越多,内存中的对象就越多,造成页面渲染和就绪时间延迟、事件不灵敏等性能问题。可以通过“事件委托”和适时移除事件的方式减少内存消耗,优化性能。
1. 事件委托
利用事件冒泡的机制,指定一个事件处理程序来管理同一类型的所有事件。
<ul id="links">
<li id="doSomething">doSomething</li>
<li id="goSomewhere">goSomewhere</li>
<li id="sayHi">say hi</li>
</ul>
var list = document.getElementById('links');
EventUtil.addHandler(list, 'click', function(e){
e = EventUtil.getEvent(e);
var target = EventUtil.getTarget(e);
switch(target.id) {
case 'doSomething':
document.title = 'the document’s title was changed';
break;
case 'goSomewhere':
location.href = 'http://www.baidu.com';
break;
case 'sayHi':
alert('hi');
break;
}
})
适合采用事件委托的事件包括:click / mousedown / mouseup / keydown / keyup / keypress。
2. 移除事件
元素被删除或替换时,原来的事件并没有删除,而是继续滞留在内存里,造成内存的损耗。在处理 DOM 或卸载页面时,应该注意删除相关的事件。
九 事件调试
在 Chrome 浏览器开发者工具中,可以查看 DOM 绑定的事件。
<div><button id="btn1">Click1</button></div>
<script>
var btn = document.getElementById('btn1');
btn.addEventListener('click', function(){
console.log('click one');
}, false);
btn.addEventListener('click', function(){
console.log('click two');
}, false);
</script>
Click1 按钮绑定两次点击事件,开发者工具中可以查看,点击一次两个事件均会触发。
基于 jQuery 的事件绑定:
<div><button id="btn2">Click2</button></div>
<script src="https://apps.bdimg.com/libs/jquery/2.1.4/jquery.min.js"></script>
<script>
$('#btn2').on('click', function(){
console.log('click one');
})
$('#btn2').on('click', function(){
console.log('click two');
})
$('#btn2').on('mousemove', function(){
console.log('mousemove');
})
$('#btn2').on('mouseenter', function(){
console.log('mouseenter');
})
// jQuery 事件的卸载
// $('#btn2').off();
</script>
由图可见,Click2 按钮绑定了两次 click 事件,但开发者工具中只显示了一个,实际点击后,仍会触发两次,这里要注意。使用off方法,不传入参数,能将该 DOM 所有绑定的事件清除掉。