JavaScript事件对象

解决一个单一问题往往需要多个知识点的辅助,产生这个问题的原因也是对多个知识点的理解不够透彻。

事件对象

当事件的响应函数被触发时,浏览器每次都会将一个事件对象作为实参传递进事件响应函数,该事件对象包含了该事件的一切信息。

再IE8及以下浏览器中,是将事件对象作为window属性保存的

解决事件对象兼容性问题

事件冒泡-事件捕获

事件冒泡-事件捕获分别由微软和网景公司提出,这两种概念都是为了解决页面中事件发生顺序(事件流)而提出的

事件冒泡(主流)

考虑以下代码

 1 <!DOCTYPE html>
 2 <html>
 3     <head>
 4         <meta charset="utf-8" />
 5         <title>事件冒泡</title>
 6     </head>
 7     <body>
 8         <div id="one">
 9             <div id="two">
10                 <div id="three">
11                     <p></p>
12                 </div>
13             </div>
14         </div>
15     </body>
16 </html>

当给id为one,two,three的div绑定单击事件时

点击p标签会依次触发three,two,one的单击事件

将这种现象形象的称之为事件冒泡,如同水里的泡泡一样从水下浮上去

事件捕获

与事件冒泡相反,事件会从最外层开始发生,直到最具体的元素。

事件委派(事件冒泡的应用)

将事件统一绑定至祖先元素,利用冒泡,在点击子类元素时,冒泡至父类元素完成点击响应事件

优点是只需要绑定一次点击响应事件,即使后续添加的子类元素也无需重新绑定

未使用事件委派

<!DOCTYPE html>
<html>
    <head>
        <meta charset="utf-8" />
        <title>事件冒泡</title>
    </head>
    <body>
        <button type="button" id="btn">添加超链接</button>
        <ul id="ul">
            <li><a href="javascript:;">超链接1</a></li>
            <li><a href="javascript:;">超链接2</a></li>
            <li><a href="javascript:;">超链接3</a></li>
        </ul>
    </body>
    <script type="text/javascript">
        //为每一个超链接绑定单击响应函数
        var allA = document.getElementsByTagName("a");
        for(var i=0;i<allA.length;i++){
            allA[i].onclick = function(){
                alert("a")
            }
        }
        
        //点击button按钮添加li标签
        var btn = document.getElementById("btn");
        btn.onclick = function(){
            var li = document.createElement("li");
            li.innerHTML = "<a href='javascript:;'>新建的li</a>";
            
            var ul = document.getElementById("ul");
            ul.appendChild(li);
        }
    </script>
</html>

使用事件委派

<!DOCTYPE html>
<html>
    <head>
        <meta charset="utf-8" />
        <title>事件冒泡</title>
    </head>
    <body>
        <button type="button" id="btn">添加超链接</button>
        <ul id="ul">
            <li><a href="javascript:;">超链接1</a></li>
            <li><a href="javascript:;">超链接2</a></li>
            <li><a href="javascript:;">超链接3</a></li>
        </ul>
    </body>
    <script type="text/javascript">
        //为ul绑定单击响应事件
        var ul = document.getElementById("ul");
        ul.onclick = function(){
            alert("a");
        }
        
        //点击button按钮添加li标签
        var btn = document.getElementById("btn");
        btn.onclick = function(){
            var li = document.createElement("li");
            li.innerHTML = "<a href='javascript:;'>新建的li</a>";
            
            
            ul.appendChild(li);
        }
    </script>
</html>

可以看到代码简洁了许多,但问题也随之而来

ul是块级元素,占满一行,给ul绑定的点击响应函数是只要点击ul就会响应,这与我们的目标 ‘单机a标签响应的目的相差甚远’

点击红色区域就会响应

那么,该如何解决

<!DOCTYPE html>
<html>
    <head>
        <meta charset="utf-8" />
        <title>事件冒泡</title>
    </head>
    <body>
        <button type="button" id="btn">添加超链接</button>
        <ul id="ul">
            <li><a href="javascript:;" class="index">超链接1</a></li>
            <li><a href="javascript:;" class="index">超链接2</a></li>
            <li><a href="javascript:;" class="index">超链接3</a></li>
        </ul>
    </body>
    <script type="text/javascript">
        //为ul绑定单击响应事件
        var ul = document.getElementById("ul");
        ul.onclick = function(event){
            if(event.target.className == "index"){
                alert("1");
            }
        }
        
        
        
        //点击button按钮添加li标签
        var btn = document.getElementById("btn");
        btn.onclick = function(){
            var li = document.createElement("li");
            li.innerHTML = "<a href='javascript:;' class='index'>新建的li</a>";
            
            
            ul.appendChild(li);
        }
    </script>
</html>

在执行响应函数时,添加一个判断(触发事件的元素某个属性值是否为预期的属性值),进行响应

需要注意的是,这样做有隐患,因为class通常可以写多个,如

class="index main"

这个问题可以用正则表达式来判断解决

事件绑定

使用 object.function 的形式绑定响应函数,只能绑定一个,绑定多个后面的会覆盖前面的

addEventListener

使用该函数可以为同一个对象,同一个事件绑定多个响应函数

以下内容摘自JS中事件冒泡与捕获 - SegmentFault 思否

网景 和 微软 曾经的战争还是比较火热的,当时, 网景主张捕获方式,微软主张冒泡方式。后来 w3c 采用折中的方式,平息了战火,制定了统一的标准——先捕获再冒泡。

由此可见鲁迅先生所说的中国人喜欢用折中的方式解决问题,也并非是中国人独有的特点
addEventListener的第三个参数就是为冒泡和捕获准备的.
addEventListener有三个参数:

element.addEventListener(event, function, useCapture)

第一个参数是需要绑定的事件,onclick写为click
第二个参数是触发事件后要执行的函数
第三个参数默认值是false,表示在事件冒泡阶段调用事件处理函数;如果参数为true,则表示在事件捕获阶段调用处理函数。

IE8中使用attachEvent来达到相同目的

element.attachEvent(event, function)

第一个参数是需要绑定的事件,onclick写为onclick
第二个参数是触发事件后要执行的函数

后绑定先执行

bind函数

function bind(obj,evenStr,callback){
            if(obj.addEventListener){
                //大部分浏览器
                obj.addEventListener(evenStr,callback,false);
            }else{
                //IE8及以下
                obj.attachEvent("on"+evenStr,function(){
                    //统一this指向问题
                    callback.call(obj);
                    
                });
            }
        }

 

posted @ 2022-02-14 21:28  也许不易  阅读(46)  评论(0)    收藏  举报