html
该方法接收三个参数:浏览器
type: 事件类型字符串,好比click、mouseover ,注意这里不要带ondom
listener: 事件处理函数,事件发生时,会调用该监听函数函数
useCapture: 可选参数,是-个布尔值,默认是false。学完DOM事件流后,咱们再进一步学习性能
eventTarget.attachEvent()方法将指定的监听器注册到 eventTarget(目标对象) 上,当该对象触发指定的事件时,指定的回调函数就会被执行。学习
该方法接收两个参数:this
eventNameWithOn: 事件类型字符串,好比onclick、 onmouseover,这里要带onatom
callback: 事件处理函数,当目标触发事件时回调函数被调用spa
注意: IE8 及早期版本支持3d
<button>传统注册事件</button>
<button>方法监听注册事件</button>
<button>ie9 attachEvent</button>
<script>
var btns = document.querySelectorAll('button');
// 1. 传统方式注册事件
btns[0].onclick = function() {
alert('hi');
}
btns[0].onclick = function() {
alert('hao a u');
}
// 2. 事件侦听注册事件 addEventListener
// (1) 里面的事件类型是字符串 一定加引号 并且不带on
// (2) 同一个元素 同一个事件能够添加多个侦听器(事件处理程序)
btns[1].addEventListener('click', function() {
alert(22);
})
btns[1].addEventListener('click', function() {
alert(33);
})
// 3. attachEvent ie9之前的版本支持
btns[2].attachEvent('onclick', function() {
alert(11);
})
</script>
封装一个函数,函数中判断浏览器的类型:
<div>1</div>
<div>2</div>
<div>3</div>
<script>
var divs = document.querySelectorAll('div');
divs[0].onclick = function() {
alert(11);
// 1. 传统方式删除事件
divs[0].onclick = null;
}
// 2. removeEventListener 删除事件
divs[1].addEventListener('click', fn) // 里面的fn 不须要加小括号调用
function fn() {
alert(22);
divs[1].removeEventListener('click', fn);
}
// 3. detachEvent
divs[2].attachEvent('onclick', fn1);
function fn1() {
alert(33);
divs[2].detachEvent('onclick', fn1);
}
</script>
删除事件兼容性解决方案
html中的标签都是相互嵌套的,咱们能够将元素想象成一个盒子装一个盒子,document是最外面的大盒子。
当你单击一个div时,同时你也单击了div的父元素,甚至整个页面。
那么是先执行父元素的单击事件,仍是先执行div的单击事件 ???
事件流描述的是从页面中接收事件的顺序。
事件发生时会在元素节点之间按照特定的顺序传播,这个传播过程即DOM事件流
好比:咱们给页面中的一个div注册了单击事件,当你单击了div时,也就单击了body,单击了html,单击了document。
当时的2大浏览器霸主谁也不服谁!
IE 提出从目标元素开始,而后一层一层向外接收事件并响应,也就是冒泡型事件流。
Netscape(网景公司)提出从最外层开始,而后一层一层向内接收事件并响应,也就是捕获型事件流。
江湖纷争,武林盟主也脑袋疼!!!
最终,w3c 采用折中的方式,平息了战火,制定了统一的标准 —--— 先捕获再冒泡。
现代浏览器都遵循了此标准,因此当事件发生时,会经历3个阶段。
DOM 事件流会经历3个阶段:
捕获阶段
当前目标阶段
冒泡阶段
咱们向水里面扔一块石头,首先它会有一个降低的过程,这个过程就能够理解为从最顶层向事件发生的最具体元素(目标点)的捕获过程;以后会产生泡泡,会在最低点( 最具体元素)以后漂浮到水面上,这个过程至关于事件冒泡。
事件冒泡
<div class="father">
<div class="son">son盒子</div>
</div>
<script>
// onclick 和 attachEvent(ie) 只在冒泡阶段触发
// 冒泡阶段 若是addEventListener 第三个参数是 false 或者 省略
// son -> father ->body -> html -> document
var son = document.querySelector('.son');
// 给son注册单击事件
son.addEventListener('click', function() {
alert('son');
}, false);
// 给father注册单击事件
var father = document.querySelector('.father');
father.addEventListener('click', function() {
alert('father');
}, false);
// 给document注册单击事件,省略第3个参数
document.addEventListener('click', function() {
alert('document');
})
</script>
事件捕获
<div class="father">
<div class="son">son盒子</div>
</div>
<script>
// 若是addEventListener() 第三个参数是 true 那么在捕获阶段触发
// document -> html -> body -> father -> son
var son = document.querySelector('.son');
// 给son注册单击事件,第3个参数为true
son.addEventListener('click', function() {
alert('son');
}, true);
var father = document.querySelector('.father');
// 给father注册单击事件,第3个参数为true
father.addEventListener('click', function() {
alert('father');
}, true);
// 给document注册单击事件,第3个参数为true
document.addEventListener('click', function() {
alert('document');
}, true)
</script>
官方解释: event对象表明事件的状态,好比键盘按键的状态鼠标的位置、鼠标按钮的状态。
简单理解:事件发生后,跟事件相关的一系列信息数据的集合都放到这个对象里面,这个对象就是事件对象。
好比:
谁绑定了这个事件。
鼠标触发事件的话,会获得鼠标的相关信息,如鼠标位置。
键盘触发事件的话,会获得键盘的相关信息,如按了哪一个键。
事件触发发生时就会产生事件对象,而且系统会以实参的形式传给事件处理函数。
因此,在事件处理函数中声明1个形参用来接收事件对象。
这个event是个形参,系统帮咱们设定为事件对象,不须要传递实参过去。 当咱们注册事件时,event 对象就会被系统自动建立,并依次传递给事件监听器(事件处理函数) .
事件对象自己的获取存在兼容问题:
标准浏览器中是浏览器给方法传递的参数,只须要定义形参 e 就能够获取到。
在 IE6~8 中,浏览器不会给方法传递参数,若是须要的话,须要到 window.event 中获取查找。
只要“||”前面为false, 无论“||”后面是true 仍是 false,都返回 “||” 后面的值。
只要“||”前面为true, 无论“||”后面是true 仍是 false,都返回 “||” 前面的值。
<div>123</div>
<script>
var div = document.querySelector('div');
div.onclick = function(e) {
// 事件对象
e = e || window.event;
console.log(e);
}
</script>
this 是事件绑定的元素(绑定这个事件处理函数的元素) 。
e.target 是事件触发的元素。
常状况下terget 和 this是一致的,
但有一种状况不一样,那就是在事件冒泡时(父子元素有相同事件,单击子元素,父元素的事件处理函数也会被触发执行),
这时候this指向的是父元素,由于它是绑定事件的元素对象,
而target指向的是子元素,由于他是触发事件的那个具体元素对象。
<div>123</div>
<script>
// 常见事件对象的属性和方法
// 1. e.target 返回的是触发事件的对象(元素) this 返回的是绑定事件的对象(元素)
// 区别 : e.target 点击了那个元素,就返回那个元素 this 那个元素绑定了这个点击事件,那么就返回谁
var div = document.querySelector('div');
div.addEventListener('click', function(e) {
// e.target 和 this指向的都是div
console.log(e.target);
console.log(this);
});
</script>
事件冒泡下的e.target和this
<ul>
<li>abc</li>
<li>abc</li>
<li>abc</li>
</ul>
<script>
var ul = document.querySelector('ul');
ul.addEventListener('click', function(e) {
// 咱们给ul 绑定了事件 那么this 就指向ul
console.log(this);
console.log(e.currentTarget);
// e.target 指向咱们点击的那个对象 谁触发了这个事件 咱们点击的是li e.target 指向的就是li
console.log(e.target);
})
// 了解兼容性
// div.onclick = function(e) {
// e = e || window.event;
// var target = e.target || e.srcElement;
// console.log(target);
// }
// 2. 了解 跟 this 有个很是类似的属性 currentTarget ie678不认识
</script>
html中一些标签有默认行为,例如a标签被单击后,默认会进行页面跳转。
<a href="http://www.baidu.com">百度</a>
<script>
// 常见事件对象的属性和方法
// 1. 返回事件类型
var div = document.querySelector('div');
div.addEventListener('click', fn);
div.addEventListener('mouseover', fn);
div.addEventListener('mouseout', fn);
function fn(e) {
console.log(e.type);
}
// 2. 阻止默认行为 让连接不跳转
var a = document.querySelector('a');
a.addEventListener('click', function(e) {
e.preventDefault(); // dom 标准写法
});
// 3. 传统的注册方式
a.onclick = function(e) {
// 普通浏览器 e.preventDefault(); 方法
e.preventDefault();
// 低版本浏览器 ie678 returnValue 属性
e.returnValue = false;
// 咱们能够利用return false 也能阻止默认行为 没有兼容性问题
return false;
}
</script>
事件冒泡:开始时由最具体的元素接收,而后逐级向上传播到到DOM最顶层节点。
事件冒泡自己的特性,会带来的坏处,也会带来的好处。
<div class="father">
<div class="son">son儿子</div>
</div>
<script>
var son = document.querySelector('.son');
// 给son注册单击事件
son.addEventListener('click', function(e) {
alert('son');
e.stopPropagation(); // stop 中止 Propagation 传播
window.event.cancelBubble = true; // 非标准 cancel 取消 bubble 泡泡 兼容性作法
}, false);
var father = document.querySelector('.father');
// 给father注册单击事件
father.addEventListener('click', function() {
alert('father');
}, false);
// 给document注册单击事件
document.addEventListener('click', function() {
alert('document');
})
</script>
阻止事件冒泡的兼容性处理
事件冒泡自己的特性,会带来的坏处,也会带来的好处。
把事情委托给别人,代为处理。
事件委托也称为事件代理,在 jQuery 里面称为事件委派。
说白了就是,不给子元素注册事件,给父元素注册事件,把处理代码在父元素的事件中执行。
生活中的代理:
js事件中的代理:
不是每一个子节点单独设置事件监听器,而是事件监听器设置在其父节点上,而后利用冒泡原理影响设置每一个子节点。(给父元素注册事件,利用事件冒泡,当子元素的事件触发,会冒泡到父元素,而后去控制相应的子元素。)
以上案例:给ul注册点击事件,而后利用事件对象的target来找到当前点击的li ,由于点击li,事件会冒泡到ul上,
ul有注册事件,就会触发事件监听器。
咱们只操做了一次 DOM ,提升了程序的性能。
动态新建立的子元素,也拥有事件。
<ul>
<li>知否知否,点我应有弹框在手!</li>
<li>知否知否,点我应有弹框在手!</li>
<li>知否知否,点我应有弹框在手!</li>
<li>知否知否,点我应有弹框在手!</li>
<li>知否知否,点我应有弹框在手!</li>
</ul>
<script>
// 事件委托的核心原理:给父节点添加侦听器, 利用事件冒泡影响每个子节点
var ul = document.querySelector('ul');
ul.addEventListener('click', function(e) {
// e.target 这个能够获得咱们点击的对象
e.target.style.backgroundColor = 'pink';
})
</script>