hello,JS:10-02事件对象和事件代理

一、事件的IE兼容性

在老版的IE浏览器中,不支持:addEventListenerremoveEventListener两种事件绑定的方法;支持(可实现):attachEventdetachEvent 两种方法,同时接收两个相同参数

  • a、事件处理程序名称
  • b、事件处理程序方法

由于IE支持事件冒泡,所以添加的程序会被添加到冒泡阶段,使用attachEvent可以添加事件处理程序:

1
2
3
4
5
6
7
8
9
<input id="btnClick"  type="button" value="Click Here" />

<script>
var btnClick = document.getElementById('btnClick')
var handler = function(){
alert(this.id)
}
btnClick.attachEvent('onclick',handler);
</script>

  • attachEvent只能在冒泡阶段监听事件,只有两个参数:(事件类型,事件处理函数)
  • ie中的this:它所得到的并不是当前元素,而是window对象,返回值则为undefined

二、跨浏览器的事件处理程序

了解不同的浏览器下处理事件处理程序的区别在添加事件处理程序事addEventListenerattachEvent主要有几个区别:

1、参数个数不相同,这个最直观,addEventListener有三个参数,attachEvent只有两个,attachEvent添加的事件处理程序只能发生在冒泡阶段,addEventListener第三个参数可以决定添加的事件处理程序是在捕获阶段还是冒泡阶段处理(我们一般为了浏览器兼容性都设置为冒泡阶段)

2、第一个参数意义不同,addEventListener第一个参数是事件类型(比如clickload),而attachEvent第一个参数指明的是事件处理函数名称(onclickonload

3、事件处理程序的作用域不相同,addEventListener的作用域是元素本身,this是指的触发元素,而attachEvent事件处理程序会在全局变量内运行,this是window,所以刚才例子才会返回undefined,而不是元素id

4、为一个事件添加多个事件处理程序时,执行顺序不同,addEventListener添加会按照添加顺序执行,而attachEvent添加多个事件处理程序时顺序无规律(添加的方法少的时候大多是按添加顺序的反顺序执行的,但是添加的多了就无规律了),所以添加多个的时候,不依赖执行顺序的还好,若是依赖于函数执行顺序,最好自己处理,不要指望浏览器

三、事件对象

如刚才例子中在控制台上打印出事件,事件内都是一些对象(带有属性和值),可以从这堆属性中观察到一些重要的参考(只是部分例举),如:

1
2
3
4
5
altKey:false  //表示在点击事件的时候,没有点alt键
bubbles:true //表示这个事件是冒泡
clientX:39
clientY:18 //表示它的一个位置
toElement:button#btn //说明当前传递的元素

介绍几个常用属性:

  • stopPropagation()
    如图:没加载
    阻止冒泡继续?
    在dom事件流中,分别会在捕获和冒泡阶段都绑定事件,先捕获后冒泡进行输出。假设我们现在不管捕获,只管冒泡,并给body绑定一个监听事件,当它听到事件做了一件事:一点stopPropagation()就停止冒泡,即点击div之后,body监听到消息,后面的页面元素渲染就不再处理。即将事件冒泡停止,不会再上传消息。捕获也亦然。

  • preventDefault()
    浏览器的默认事件如何阻止?
    某些元素拥有默认事件,为浏览器的默认行为。如a链接点击时则会跳转、如form表单中table=submit,当点击该按钮时,浏览器会把它所在的form表单做一次提交。假设想阻止其默认行为,则可以通过绑定事件:preventDefault()阻止其行为。之后再做一些校验或判断,用JS做当前页面跳转。即在跳转这一层级可以做些事:假设制定一个域名的a链接才能跳转(而页面则是用户可自行写链接)先阻止其默认时间,再获取当前herf的值、hostname(域名)

假设表单提交,用户校验,校验成功之后,就手动去做一些跳转

  • e.stopPropagation() 取消事件进一步捕获或冒泡
    事件冒泡和事件捕获的应用场景
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    //选中元素
    var container = document.querySelector('.container')

    var box = document.querySelector('.box')

    var target = document.querySelector('.target')

    //绑定事件
    container.addEventListener('click', function(e){
    console.log('container 捕获 click...')
    },true)

    box.addEventListener('click', function(e){
    console.log('box 捕获 click...')
    },true)

    target.addEventListener('click',function(e){
    console.log('target 捕获 click...')
    },true)


    container.addEventListener('click', function(e){
    console.log('container 冒泡 click...')
    },false)

    box.addEventListener('click', function(e){
    e.stopPropagation()
    console.log('box 冒泡 click...')
    },false)

    target.addEventListener('click',function(e){
    console.log('target 冒泡 click...')
    },false)

如图:

多个阻止函数来阻止冒泡事件

  • e.preventDefault() 阻止事件默认行为
    链接:阻止事件默认行为
    刚开始是这样的:没有跳转,只有一直输出:

    代码:
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    <!DOCTYPE html>
    <html>
    <head>
    <meta charset="utf-8">
    <title>阻止默认事件</title>
    </head>
    <body>
    <a href="http://baidu.com">baidu</a>
    </body>
    </html>

    <script>
    document.querySelector('a').onclick = function(e){
    e.preventDefault()
    console.log(this.href)
    }
    </script>

接着看图所示,添加一个if判断,再点击baidu链接,控制台只输出一次地址,页面则出现百度的网页:

代码:

1
2
3
4
5
6
7
8
9
10
11
//html同上

<script>
document.querySelector('a').onclick = function(e){
e.preventDefault()
console.log(this.href)
if(/baidu.com/.test(this.href)){
location.href = this.href
}
}//函数表示:如果这个链接是baidu.com,那就跳转
</script>

假如html代码中

1
<a href="http://baidu.com">baidu</a>

改为:

1
<a href="http://baid.com">baidu</a>

最后页面和控制台都不会有任何反应。而这就是e.preventDefault() 阻止事件默认行为

四、常用HTML事件及演示

例子链接:缺常见事件使用演示链接

五、事件代理

链接:事件代理的一些尝试
首先,我们为两个box绑定两个事件,先绑定box1,如图:
通过选择参数$('.box')作为box1的当前元素,所以再去绑定事件之后,则只会出现第一个box1文本内容。

但是,我们尝试地使用函数$$(selector)绑定两个元素的事件,再点击box1和box2没有任何输出,如图:

通过页面控制台检验:

1
2
3
4
5
6
7
8
$$('.box')
--> NodeList(2) [div.box, div.box]//1、确实出现了所选的两个元素,但是要确认有没有onclick
0: div.box
1: div.box
length: 2
__proto__: NodeList //3、我们所看到NodeList,是一个类数组对象,里面的属性值并没有onclick和addEventListener
$$('.box').onclick //2、于是测试之后undefined,即绑定事件只能针对单个去绑定事件
--> undefined

那如何解决两个元素同时绑定事件呢?还是从控制台nodelist的对象中寻找可用的参数去解决,即有forEach遍历两个元素,实现两个都绑定了事件,即:

1
2
3
4
5
6
7
8
9
10
11
12
//html同上

<script>
function $$(selector){
return document.querySelectorAll(selector)
}
$$('.box').forEach(function(node){
node.onclick = function(){
console.log(this.innerText)
}
})
</script>

图:
那么,我们有没有更简单的方法实现当前所有元素都绑定了事件?看html即可以知道,我们可以直接绑定父元素container,即

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>JS Bin</title>
</head>
<body>
<div class="container">
<div class="box">box1</div>
<div class="box">box2</div>
<div class="hello">hello</div>
</div>

</body>
</html>

<script>
function $(selector){
return document.querySelector(selector)
}
function $$(selector){
return document.querySelectorAll(selector)
}
$('.container').onclick = function(e){
if(e.target.classList.contains('box')){
console.log(e.target.innerText)
}
}//表示:如果我点击了一个元素(e.target),它的classList包含了'box',
//那么它就输出这个元素的文本内容。具有语义化
</script>

再想到更多的场景,如有一个按钮,如何绑定这个按钮实现这样一个需求:当点击这个按钮的时候,则会在父元素下再添加一个box。这个如何实现?如图:
代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>JS Bin</title>
</head>
<body>
<div class="container">
<div class="box">box1</div>
<div class="box">box2</div>
<div class="box">box3</div>
<div class="hello">hello</div>
</div>
<button id="add">add</button>
<!--需求:当点击这个按钮的时候,则会在父元素下再添加一个box-->
</body>
</html>


<script>
function $(selector){
return document.querySelector(selector)
}

function $$(selector){
return document.querySelectorAll(selector)
}

$('.container').onclick = function(e){
if(e.target.classList.contains('box')){
console.log(e.target.innerText)
}
}//事件代理的核心所在

//表示:如果我点击了一个元素(e.target),它的classList包含了'box',那么它就输出这个元素的文本内容。具有语义化


var i=4 //这是因为之前有box3了
$('#add').onclick = function(){
var box = document.createElement('div')//创建一个box元素
box.classList.add('box')//创建的当前元素去添加一个class叫做box
box.innerText ='box' + (i++)//表示每点击一次i就增加一个
$('.container').appendChild(box)//最后将box这个元素添加进.container里面
}
</script>

-------------本文结束感谢您的阅读-------------