Javascript 之 事件
事件流(描述的是从页面中接受事件的顺序)
1、IE 的事件冒泡流:即事件最开始由最具体的元素(文档中嵌套层次最深的那个点)接收,然后逐级向上传播至最不具体的那个节点(文档)。
2、Netscape 的事件捕获流:与 IE 的冒泡流截然相反,由不太具体的节点应该更早接收到事件,而最具体的节点最后接收到事件。
事件处理程序
1、HTML 事件处理程序,缺点: HTML 和 JS 代码紧密的耦合在一起了,修改时须多处修改,不方便
<button onclick="alert('Hello world!')">点击我</button>
=============================== 或者 ============================
<button onclick="hello();">点击我</button>
function hello () {
alert("Hello world!");
}
2、DOM0 级事件处理程序,是一个比较传统的方式:把一个函数赋值给一个事件的处理程序属性,是用的比较多的方法。优点:简单、跨浏览器
<button id="btn">点击我</button>
var btn = document.getElementById("btn");
btn.onclick = function () {
alert("Hello world!");
}
====================== 或者 ======================
btn.onclick = hello();
function hello () {
alert("Hello world!");
}
btn.onclick = null; // 取消元素绑定的 click 事件
3、DOM2 级事件处理程序。
addEventListener 是添加事件绑定, removeEventListener 是取消事件绑定。
都接收三个参数:要处理的事件名、作为事件处理程序的函数、布尔值(true 表示在捕获阶段调用事件处理程序, false 表示在冒泡阶段端用事件处理程序,默认为 fasle)
<button id="btn">点击我</button>
var btn = document.getElementById("btn");
btn.addEventListener("click", function(){
alert("Hello world!");
}, false)
====================== 或者 ==========================
btn.addEventListener("click", hello, false);
function hello () {
alert("Hello world!");
}
btn.removeEventListener("click", hello, false); // 删除元素的事件绑定。
注意:通过什么方式添加的事件,就要通过什么方式删除事件
4、IE 事件处理程序。添加事件处理程序是 attachEvent(),删除事件处理程序是 detachEvent,接收两个相同的参数:事件处理程序的名称、事件处理程序的函数
与 addEventListener 相比,没有第三个参数,因为 IE8 以及更早的浏览器版本只支持事件冒泡流
<button id="btn">点击我</button>
var btn = document.getElementById("btn");
btn.attachEvent("onclick", function () { // 在 IE 下的事件需要加前缀 on
alert("Hello world!");
})
================== 或者 =================
btn.attachEvent("onclick", hello);
function hello () {
alert("Hello world");
}
btn.detachEvent("onclick", hello); // 删除事件绑定程序
5、跨浏览器的事件处理程序,能力测试
var eventUtil = {
// 添加事件
addEvent: function (ele, type, fn) { // ele:元素 type:事件类型名称 fn:事件处理程序函数
if (ele.addEventListener) { // 判断浏览器时候支持 addEventListener
ele.addEventListener(type, fn, false);
} else if (ele.attachEvent) { // 判断浏览器是否支持 IE 的 attachEvent
ele.attachEvent(type, fn);
} else { // 通用的 DOM0 级方法
ele["on" + type] = fn;
}
},
// 删除事件
removEvent: function (ele, type, false) {
if (ele.removeEventListener) {
ele.removeEventListener(type, fn, false);
} else if (ele.detachEvent) {
ele.detachEvent(type, fn);
} else {
ele["on" + type] = null;
}
},
// 获取 event
getEvent: function (event) {
return event?event:window.event;
},
// 获取事件目标元素
getEventElement: function (event) {
return event.target || event.srcElement;
},
// 阻止事件默认行为
preventDefault: function (event) {
if (event.preventDefault) {
event.preventDefault();
} else {
event.returnValue = false;
}
},
// 阻止事件冒泡
stopPropagation: function (event) {
if (event.stopPropagation) {
event.stopPropation();
} else {
event.cancelBubble = true;
}
}
}
<button id="btn"></button>
var btn = document.getElementById("btn");
// 添加
event.addEvent(btn, "click", function () {
alert("Hello world!");
});
// 删除
event.removeEvent(btn, "click", function () {
alert("Hello world!");
})
==================== 或者 ======================
event.addEvent(btn, "click", hello);
event.removeEvent(btn, "click", hello);
function hello () {
alert("Hello world")!
}
用例:
<a href="www.baidu.com" id="link"></a>
var link = document.getElementById("link");
eventUtil.addEvent(link, "click", funciton (e) {
e = eventUtil.getEvent(e); // 获取 event 对象
alert(eventUtil.getEventElement(e).nodeName); // 获取事件目标元素
eventUtil.preventDefault(e); // 阻止事件默认行为
eventUtil.stopPropagation(e); // 阻止事件冒泡
})
事件对象(在触发 DOM 上的事件时都会产生一个对象,叫 event 对象)
1、DOM 中的事件对象
event.type // 事件类型
event.target // 事件目标
event.target.nodeName // 事件目标的节点名称
event.target.nodeType // 事件目标的节点类型
event.target.selectedIndex // 事件目标 select 标签选中的索引值,也就是选中了哪一个 option 标签
event.keyCode // 此属性用于得到键盘对应的键码值
event.stopPropagation() // 这个方法用于阻止事件冒泡
event.preventDefault() // 这个方法用于阻止事件的默认行为
2、IE 中的事件对象
event.type // 事件类型
event.srcElement // 事件目标
event.cancelBubble // 阻止事件冒泡 event.cancelBubble = true; 取消阻止事件冒泡 event.cancelBubble = false;
event.returnValue // 阻止事件的默认行为,默认值是 true 表示不阻止事件的默认行为, event.returnValue = false 可以设置阻止事件的默认行为
IE8 或者更低的浏览器
function ev (evetn) {
event = event || window.event;
var targetD = event.target || event.srcElement;
}
事件类型
鼠标事件都是在浏览器窗口中的特定位置上发生的,这个位置信息保存在事件的 clientX 和 clientY 属性中,所有浏览器都支持这两个属性,它们的值表示事件发生时鼠标指针在视口中的水平和垂直坐标,不包括页面滚动的距离
event.clientX // 鼠标指针在视口中的水平位置
event.clientY // 鼠标指针在视口中的垂直位置
mousedown // 在用户按下鼠标任意键时触发
mousemove // 当鼠标指针在元素内部移动时重复地触发
mouseup // 当用户释放鼠标按钮时触发
keydown // 当用户按下键盘上的任意键时触发,而且如果按住不放的话,会重复触发此事件
keypress // 当用户按下键盘上的字符键时触发,而且如果按住不放的发,会重复触发此事件
keyup // 当用户释放键盘上的任意键时触发
element.offsetLeft // 元素距离视口左边的距离
element.offsetTop // 元素距离视口上边的距离
document.documentElement.clientWidth || document.body.clientWidth // 窗口的宽度
document.documentElement.clientHeight || document.body.clientHeight // 窗口的高度
取消默认行为
<a href="http://www.baidu.com" id="link">百度</a>
var link = document.getElementById('link');
link.addEventListener('click', function (e) {
e.preventDefault(); // 取消 a 链接的默认跳转
console.log('clicked!');
})
阻止事件冒泡
<div id="dom">
<a id="link" href="http://www.baidu.com">激活</a>
<a href="http://www.qq.com">取消</a>
</div>
var link = document.getElementById('link');
link.addEventListener('click', function (e) {
e.preventDefault();
e.stopPropagation(); // 阻止内层 a 的事件冒泡到父元素 div 上
alert('激活');
})
var dom = document.getElementById('dom');
dom.addEventListener('click', function (e) {
var target = e.target;
e.preventDefault();
if (target.nodeName === 'A') {
alert('取消');
}
})
事件代理
<div id="dom">
<a href="http://www.baidu.com">百度</a>
<a href="http://www.qq.com">腾讯</a>
</div>
var dom = document.getElementById('dom');
dom.addEventListener('click', function (e) {
e.preventDefault();
var target = e.target; // 代理的重点,在获取 e.target 对象
if (target.nodeName === 'A') {
alert(target.innerHTML);
}
})
代理的好处: 1、代码简介; 2、减少浏览器内存占用
具体应用: 对于一个无限下拉加载图片的页面,如何给每个图片绑定事件,就是使用事件代理。给父元素绑定事件,通过冒泡机制,获取点击目标的 nodeName 是否是 img,再执行相应的函数
通用事件绑定
<div id="dom">
<a id="link" href="http://www.baidu.com">百度</a>
<a href="http://www.baidu.com">百度</a>
</div>
var dom = document.getElementById('dom');
bindEvent(dom, 'click', 'a', function (e) {
e.preventDefault();
console.log(this.innerHTML);
})
var link = document.getElementById('link');
bindEvent(link, 'click', function (e) {
e.preventDefault();
e.stopPropagation();
console.log(this.innerHTML);
})
function bindEvent (elem, type, selector, fn) {
if (fn == null) {
fn = selector;
selector = null;
}
elem.addEventListener(type, function (e) {
var target;
if (selector) {
// 使用代理
target = e.target;
if (target.matches(selector)) { // 在点击目标的元素中,是否存在 selector 选择器,有返回true,无返回false
fn.call(target, e); // 用 call 方法调用,把 target 当 this
}
} else {
// 不使用代理
fn(e);
}
})
}
var result = element.matches(selectorString); // selectorString 是一个 css 选择器字符串