事件是元素天生就具备的能力,比如可以被点击。
绑定事件——>绑定事件的处理函数。
事件 + 事件的反馈 == 前端交互,交互体验
兼容性好;
一个元素同一种事件只能绑定一个事件处理函数,后写覆盖先写。
位置:
<button onclick="console.log(1)">button>
<button onclick="test">button>
<script>
function test(){
}
script>
注:若同时使用这两种句柄的形式绑定事件,js中的会覆盖行内写的。
注册(绑定)事件监听器。
W3C规范,IE9以下不兼容;
一个元素同一种事件可以绑定多个事件处理函数;
函数引用相同,事件处理函数只执行一次;
一个元素同一个事件绑定多个事件处理函数会有两种结果:
var oBtn = document.getElementsByTagName('button')[0];
// 注册事件监听器,事件处理函数为匿名函数
// 绑定的多个事件处理函数都会执行
oBtn.addEventListener('click',function(){
console.log(1);
}, false);
oBtn.addEventListener('click',function(){
console.log(1);
}, false);
// 注册事件监听器,事件处理函数为外部普通函数
// 绑定的多个事件处理函数只执行一次,相当于只绑定了一个事件处理函数
oBtn.addEventListener('click',test,false);
oBtn.addEventListener('click',test,false);
function test(){
console.log(2);
}
IE8及以下绑定方法
IE8及以下(谷歌中没有);
一个元素同一种事件可以绑定多个事件处理函数;
不看函数引用是否相同,事件处理函数全部执行;
其中this指向window,使用call/apply方法改变this指向。
var oBtn = document.getElementsByTagName('button')[0];
// IE8以下绑定方法(谷歌中没有)
oBtn.attachEvent('onclick',function(){
console.log(1);
});
oBtn.attachEvent('onclick',function(){
console.log(1);
});
oBtn.attachEvent('onclick',test);
oBtn.attachEvent('onclick',test);
function test(){
console.log(2);
}
// 事件绑定函数的兼容性写法:
// 参数依次代表 事件源,事件类型,事件处理函数
function addEvent(el, type, fn){
// 先寻找注册监听器 IE9及以上兼容
if(el.addEventListener){
el.addEventListener(type, fn, false);
}else if(el.attachEvent){
// 再兼容IE8及以下
el.attachEvent('on' + type, fn);
}else{
// 还不行的话使用兼容最好的句柄形式
el['on'+ type] = fn;
}
}
验证通过!
点击列表,输出列表的序号。
var oLi = document.getElementsByTagName('li'),
len = oLi.length;
for(var i = 0; i < len; i++){
// 产生了闭包现象
// 使用如下方法,点击时的i已经变成5,每次点击都是5
// oLi[i].onclick = function(){
// console.log(i);
// }
// 怎么解决这个问题 IIFE+闭包
(function(j){
oLi[j].addEventListener('click',function(){
console.log(j);
},false);
})(i)
}
浅了解一下使用IIFE的目的:
这里使用IIFE的目的在于使内部的函数变成一个闭包函数,可以访问外界的作用域;每次循环时,都可以获得一个新的立即执行函数,新的立即执行函数会拿到新的参数,闭包函数就拿到了新的参数j,每次循环以后j值就不一样了。
element.onclick = null/false
element.removeEventListener(事件名,函数名,xx)
,函数为外部函数。
element.removeEventListener(事件名,arguments.callee,xx)
非严格模式下使用arguments.callee拿到此函数的引用。
//绑定事件是什么样子,解除就什么样
element.addEventListener('click'、arguments.callee,false);
element.removeEventListener('click'、arguments.callee,false);
element.detachEvent(事件名,事件处理函数)
// 事件解除函数的兼容性写法
// 参数依次为:事件源,事件类型,事件处理函数
function removeEvent(el, type, fn){
if(el.addEventListener){
el.removeEventListener(type, fn);
}else if(el.attachEvent){
el.detachEvent('on' + type, fn);
}else{
el['on' + type] = null;
}
}
注意:一般执行一次或多次后再解除事件处理函数,那么解除事件就应该写到事件绑定内部,或者根据一些条件成立后再解除事件。
// 事件绑定测试
addEvent(oBtn, 'click', function(){
test();
//...一些条件
// 事件解除测试
removeEvent(oBtn, 'click', arguments.callee);
});
标签是内联元素(行内元素inline),即使display变成块级元素,DOM结构解析出来也是非嵌套的。
原则上内联元素不应该嵌套内联元素
<style>
/* 属性选择器 */
[href="https://www.taobao.com"]{
display: block;
width: 100px;
height: 100px;
background-color: skyblue;
}
style>
<a href="https://www.taobao.com">淘宝
<a href="https://www.baidu.com">百度a>
<p>11
<p>22p>
p>
a>
addEventListener(type, fn, false)
这种形式是事件冒泡。
DOM结构中存在嵌套关系,有了从内层到外层的事件冒泡现象:先执行事件源元素的事件处理函数,再执行父元素的同一种事件所触发的事件处理函数,直到顶层。(子元素的事件会从子元素起向父元素冒泡,从而触发父元素与子元素传递的同一事件,直到顶层)
addEventListener(type, fn, true)
这种形式是事件捕获。
DOM结构中存在嵌套关系,有了从外层到内层的事件捕获现象:先执行自身所在的顶层节点的相同事件,然后向下传递到自身。
DOM事件流分为三个阶段:
当一个元素又绑定了一个捕获事件,又绑定了一个冒泡事件,执行:由哪个元素触发事件,它就属于事件源,在DOM事件流中属于当前目标阶段。没有捕获和冒泡,就是单纯执行一个事件函数或多个事件函数,多个事件处理函数的具体执行顺序在不同浏览器,不同版本浏览器中不同;而其他元素的事件按照先捕获后冒泡执行。
简单来说:当一个元素又绑定了一个捕获事件,又绑定了一个冒泡事件,执行:事件源的事件处理函数正常执行(起一个传递事件的作用),其他元素的事件先捕获后冒泡。
有些事件没有捕获和冒泡现象:
focus blur change submit reset select
IE浏览器没有事件捕获
不想父级也执行同一个事件所引发的事件处理函数,所以要阻止冒泡默认事件。
W3C—>e.stopPropagation()
存在于Event.prototype上
IE——>e.cancelBubble = true
这里的e为事件对象,每个事件都有一个e在事件处理函数中。
阻止冒泡现象的兼容性写法:
// 消除事件默认冒泡现象,需要事件对象
// 而 IE8 中事件对象不在事件处理函数中,而在window上
// 需要使用兼容性写法
function cancelBubble(e){
var e = e || window.event;
// 首选W3C规则
if(e.stopPropagation){
e.stopPropagation()
}else{
e.cancelBubble = true;
}
}
使用位置:这个函数写到子元素的事件绑定函数中。
// 取消 右击浏览器默认出现菜单
document.oncontextmenu = function(e){
var e = e || window.event;
// 句柄形式中取消默认事件方法:
// 兼容性最好,addEventListener中不能用这个
// return false;
cancelPrevent(e);
}
// 取消默认事件兼容性写法
function cancelPrevent(e){
var e = e || window.event;
// w3c方法;一般 W3C 标准,IE9及以下都不支持
if(e.preventDefault){
e.preventDefault();
}else{
// IE9以下方法
e.returnValue = false;
}
}
<body>
<a href="https://www.baidu.com" target="_blank">百度a>
<a href="javascript:;">淘宝a>
<a href="javascript:void(0);">京东a>
<script>
var a = document.getElementsByTagName('a')[0];
// 方法3:
a.onclick = function(e){
var e = e || window.event;
// 点击百度不会跳转
e.preventDefault();
}
script>
body>
<body>
<a href="https://www.baidu.com" class="link" target="_blank">
<div class="inner">点击div>
a>
<script>
// 要求:点击文字不跳转,点击文字外部跳转
var inner = document.getElementsByClassName('inner')[0];
// 在div中清除 a 标签默认跳转事件
inner.addEventListener('click',function(e){
var e = e || window.event;
e.preventDefault();
}, false)
script>
body>
// submit默认事件:刷新页面去提交数据(同步跳转提交)
// 通过id获取元素
var submit = document.getElementById('submit');
submit.onclick = function(e){
var e = e || window.event;
// 这里没有用兼容性写法
e.preventDefault();
console.log('提交了');
}
DOM中的兼容性写法更多是一个知识储备和面试相关,所以重点肯定在于DOM原型链;DOM增删改查;所有事件,包括键盘;冒泡捕获,事件代理
在DOM中的兼容性写法大部分针对IE浏览器各版本,firefox有些也是会考虑的;但是现在大部分项目不会考虑,因为工程化可以对兼容性进行配置。
而chrome浏览器是迭代的,99%API都兼容。