JavaScript中的事件

时间:2021-1-8 作者:admin

事件流

JavaScript操作css称为脚本化CSS,而JavaScript与HTML的交互是通过事件实现的。事件就是文档或浏览器窗口中发生的一些特定的交互瞬间,而事件流(又叫事件传播)描述的是从页面中接收事件的顺序。

事件流的三个阶段

  • 事件捕获阶段
  • 处于目标阶段
  • 事件冒泡阶段

事件捕获

不太具体的节点(window/document)更早的接收事件,往具体的节点进行传播,最具体的节点应该在最后接收到事件。

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0, minimum-scale=1,maximum=1,user-scalable=no">
    <title>Document</title>
    <style type="text/css">
        #box{
            width: 200px;
            height: 200px;
            background-color: red;
        }
    </style>
</head>
<body>
    <div id="box"></div> 
    <script type="text/javascript">
        var box = document.getElementById("box");
        box.addEventListener('click',function(){
            box.innerHTML += "div\n"
        },true);//false 表示冒泡阶段
        document.body.addEventListener('click',function(){
            box.innerHTML += "body\n"
        },true);
        document.documentElement.addEventListener('click',function(){
            box.innerHTML += "html\n"
        },true);
        document.addEventListener('click',function(){
            box.innerHTML += "document\n"
        },true);
        window.addEventListener('click',function(){
            box.innerHTML += "window\n"
        },true);

    </script>
</body>
</html>

事件冒泡

事件开始时由最具体的节点接收,然后逐级向上传播到较为不具体的节点(文档)

注意:ie9以下仅冒泡到document

测试代码

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0, minimum-scale=1,maximum=1,user-scalable=no">
    <title>Document</title>
    <style type="text/css">
        #box{
            width: 200px;
            height: 200px;
            background-color: red;
        }
    </style>
</head>
<body>
    <div id="box"></div> 
    <script type="text/javascript">
        var box = document.getElementById("box");
        box.onclick = function(){
            box.innerHTML += "div\n"
        }
        document.body.onclick = function(){
            box.innerHTML += "body\n"
        } 
        document.documentElement.onclick = function(){
            box.innerHTML += "html\n"
        }
        document.onclick = function(){
            box.innerHTML += "document\n"
        }
        window.onclick = function(){
            box.innerHTML += "window\n"
        }
    </script>
</body>
</html>

事件处理程序

事件处理程序又叫事件侦听器,实际上就是事件的绑定函数。事件发生时会执行函数中相应代码。

事件处理程序分为四种:

  • HTML事件处理程序
  • DOM 0级事件处理程序
  • DOM 2 级事件处理程序
  • IE 事件处理程序

HTML事件处理程序

直接在元素上绑定事件,不常用

在事件处理程序函数内部,this指向事件的目标元素。

<div id="box" onclick="this.innerHTML+='1'"></div>
这里的this就是当前对象(<div id="box" onclick="this.innerHTML+='1'"></div>)

等价于

<div id="box" onclick="test()"></div> 
<script type="text/javascript">
    var box = document.querySelector("#box");
    function test(){
        console.log(this);//此处的this指向window,函数独立调用,内部this指向window
        box.innerHTML +='1';
    }
</script>

缺点

html+js混合在一起,不易维护。

DOM 0级事件处理程序

将一个函数赋值给一个事件的处理程序的属性, 应用非常多(简单,跨浏览器)

注意

以DOM 0级方式添加的事件处理程序会在事件流的冒泡阶段被处理,不存在捕获阶段

<div id="box"></div> 
<script type="text/javascript">
    var box = document.querySelector("#box");
    box.onclick = function(){
        this.innerHTML +='1';
    }
    //置空,删除事件的处理程序
    box.onclick = null;
</script>

缺点

不能给同一个元素绑定相同的事件处理程序,如果绑定了,前者会被覆盖

DOM 2级事件处理程序

处理程序存在两种方法

  • addEventListener()
  • removeEventListener()

addEventListener()

事件监听,addEventListener("事件名字符串",function(){},布尔值),其中布尔值默认为false,可以不写,false表示处于冒泡阶段,为true表示处于捕获阶段。

<div id="box"></div> 
<script type="text/javascript">
    var box = document.querySelector("#box");
    box.addEventListener('click', function(){
        this.innerHTML +='1';
    },false);
</script>

DOM 2级事件处理程序,能给同一个元素绑定相同的事件处理程序,同时调用。

注意

ie8浏览器不支持DOM 2级事件处理程序

监听函数传参,可以用匿名函数包装一个监听函数。

<div id="box"></div> 
<script type="text/javascript">
    var box = document.querySelector("#box");
    box.addEventListener('click', function(){
        test(111);
    },false);
    function test(x){
        alert(x);
    }
</script>

removeEventListener()

移除事件

<div id="box"></div> 
<script type="text/javascript">
    var box = document.querySelector("#box");
    box.addEventListener('click',handler,false);
    function handler(){
        this.innerHTML += 1;
    }
    box.removeEventListener('click',handler,false);
</script>

IE的事件处理程序

只能在IE浏览器中使用,处理程序存在两种方法。

在ie中此this指向window

  • attachEvent()
  • detachEvent()

attachEvent()

添加事件

<div id="box"></div> 
<script type="text/javascript">
    var box = document.querySelector("#box");
    box.attachEvent('onclick',function(){
        //this.innerHTML += '1';
        //在ie中此this指向window
        box.innerHTML += '1';
    });
</script>

detachEvent()

移除事件

<div id="box"></div> 
<script type="text/javascript">
    var box = document.querySelector("#box");
    box.attachEvent('onclick',handler);
    function handler(){
        box.innerHTML += '1';
    }
    box.detachEvent('onclick',handler);
</script>

事件绑定兼容写法

代码如下

<body>
    <button type="button">haha</button>
    <script type="text/javascript">
        var btn = document.querySelector("[type=button]");
        // btn.addEventListener('click',fn,false);
        // btn.attachEvent('onclick',fn);
        addEvent(btn,'click',function(){
            console.log(this.innerHTML);
        });
        // 全浏览器事件处理程序的兼容性代码
        function addEvent(target,eventType,handler){
            if(target.addEventListener){
                target.addEventListener(eventType,handler,false);
            }
            else{
                target.attachEvent('on'+eventType,function(){
                    handler.call(target);
                });
            }
        }
    </script>

</body>

事件调用顺序总结

相同点

如果同时出现html事件处理程序和dom0级事件处理程序,后者会覆盖前者

不同点

1.chrome,safari,火狐以及IE11浏览器结果:dom0级 dom2级
2.IE9、10结果为:dom0级 dom2级 IE
3.IE8结果为:dom0级 IE

事件对象

在触发dom上的某个事件时,会产生一个事件对象event,这个对象中包含着所有与事件有关的信息

如何获取事件对象

1.event对象是事件程序的第一个参数,ie8不支持

<body>
    <div id="box"></div>
    <script type="text/javascript">
        window.onload = function(){
            var box = document.getElementById("box");
            box.onclick = function(e){
                box.innerHTML = e;
            }
        }
    </script>
</body>

2.直接使用event变量,火狐浏览器不支持

<body>
    <div id="box"></div>
    <script type="text/javascript">
        window.onload = function(){
            var box = document.getElementById("box");
            box.onclick = function(){
                box.innerHTML = event;
            }
        }
    </script>
</body>

3.兼容写法

<body>
    <div id="box"></div>
    <script type="text/javascript">
        window.onload = function(){
            var box = document.getElementById("box");
            box.onclick = function(e){
                e = e ||window.event;
               box.innerHTML = e;
            }
        }
    </script>
</body>

事件目标

有三个属性

  • currentTarget
  • target
  • srcElement

currentTarget

返回事件当前所在的节点,正在执行的监听函数所绑定的节点

<body>
    <ul id="box">
        <li class="item">1</li>
        <li class="item">2</li>
    </ul>
    <script type="text/javascript">
        var box = document.getElementById("box");
        box.onclick = function(e){
            e = e || event;
            console.log(e.currentTarget);
            var items = document.querySelectorAll("[class]");
            items[0].innerHTML = e.currentTarget;//[object HTMLUListElement]
        }
    </script>
</body>

target

返回的是事件的实际目标对象

this对象跟e.currentTarget属性是一样的,但 不支持ie8

<body>
    <ul id="box">
        <li class="item">1</li>
        <li class="item">2</li>
    </ul>
    <script type="text/javascript">
        var box = document.getElementById("box");
        box.onclick = function(e){
            e = e || event;
            console.log(e.target);
            console.log(e.target===this);
            // this对象跟e.currentTarget属性是一样的
            console.log(e.currentTarget===this);
            var items = document.querySelectorAll("[class]");
            items[0].innerHTML = e.target;//[object HTMLUListElement]
        }
    </script>
</body>

srcElement

与target属性一样,但target不支持ie8,srcElement属性在低版本的火狐上不支持

兼容

var box = document.getElementById("box");
        box.onclick = function(e){
            e = e || event;
            var target = e.target || e.srcElement;

        }

事件代理

由于事件会在冒泡阶段向上传递到父节点,因此可以把子节点的监听函数定义在父节点上,由父节点的监听函数统一处理多个子元素的事件,这种方法叫做事件的代理,又叫事件委托

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0, minimum-scale=1,maximum=1,user-scalable=no">
    <title>Document</title>
    <style type="text/css">
        *{
            padding: 0;
            margin: 0;
        }
        ul{
            list-style: none;
            overflow: hidden;
            margin-top: 80px;
        }
        li{
            width: 100px;
            float: left;
            height: 30px;
            text-align: center;
            line-height: 30px;
            background-color: red;
            margin: 0px 10px;
            color: white;
            }
    </style>
</head>
<body>
    <ul id="box">
        <li>1</li>
        <li>2</li>
        <li>3</li>
        <li>4</li>
        <li>5</li>
    </ul>
    <script type="text/javascript">
        window.onload = function(){
            // 常规方法
            var lis = document.getElementsByTagName("li");
            for (var i = 0;i<lis.length;i++){
                lis[i].onmouseover =  function(){
                    this.style.backgroundColor = 'blue';
                }
                lis[i].onmouseout = function(){
                    this.style.backgroundColor = 'red'
                }
            }

            //事件代理方式的实现,要结合事件目标对象来实现
            var box = document.getElementById('box');
            box.onmouseover = function(e){
                e = e ||event;
                var target = e.target || e.srcElement;
                target.style.backgroundColor = 'blue'
            }
            box.onmouseout = function(e){
                e = e ||event;
                var target = e.target || e.srcElement;
                target.style.backgroundColor = 'red'
            }
        }
    </script>
</body>
</html>

优点

提高性能、减少代码

事件冒泡

事件冒泡是事件流的第三个阶段,通过事件冒泡可以在这个阶段对事件做出事件响应。

关于冒泡,事件对象中包含四个相关的属性和方法

  • bubbles
  • cancelBubble
  • stopPropagation()
  • stopImmediatePropagation()

bubbles

返回一个布尔值,表示当前事件是否会冒泡。该属性为只读属性。

注意

发生在文档上的大部分事件都会冒泡,但focus、blur、scroll事件不会冒泡
<body>
    <button>按钮</button>
    <input type="text" name="" id="" value="" />
    <script type="text/javascript">
        var btn = document.getElementsByTagName('button')[0];
        var inP = document.querySelector('[type=text]');
        btn.onclick = function(e){
            e = e || window.event;
            console.log(e.bubbles);//true
        }
        inP.onfocus = function(e){
            e = e || window.event;
            console.log(e.bubbles);//false
        }
    </script>
</body>

stopPropagation()

表示取消事件的进一步捕获或冒泡,无返回,ie8不支持

<body>
    <button>按钮</button>
    <script type="text/javascript">
        var btn = document.getElementsByTagName('button')[0];
        btn.onclick = function(e){
            e = e || window.event;
            // 阻止冒泡
            e.stopPropagation();
            this.innerHTML = '阻止冒泡';
        }
        document.body.onclick = function(e){
            e = e || window.event;
            console.log('body');
        }
    </script>
</body>

缺点

无法阻止同一事件的其他监听函数被调用

<body>
    <button>按钮</button>
    <script type="text/javascript">
        var btn = document.getElementsByTagName('button')[0];
        btn.addEventListener('click',function(e){
            e = e || window.event;
            e.stopPropagation();
            this.style.backgroundColor = 'blue';

        },false);
        btn.addEventListener('click',function(e){
            e = e || window.event;
            // e.stopPropagation();
            this.innerHTML = '阻止了';

        },false);
        document.body.onclick = function(e){
            e = e || window.event;
            console.log('body');
        }
    </script>
</body>

stopImmediatePropagation()

既可以阻止冒泡,又可以阻止同一事件的其他监听函数被调用

<body>
    <button>按钮</button>
    <script type="text/javascript">
        var btn = document.getElementsByTagName('button')[0];
        btn.addEventListener('click',function(e){
            e = e || window.event;
            e.stopImmediatePropagation();
            this.style.backgroundColor = 'blue';

        },false);
        btn.addEventListener('click',function(e){
            e = e || window.event;
            // e.stopPropagation();
            this.innerHTML = '阻止了';

        },false);
        document.body.onclick = function(e){
            e = e || window.event;
            console.log('body');
        }
    </script>
</body>

cancelBubble

只能用于阻止冒泡,无法阻止捕获阶段,该值可读写,默认为false,设置为true,即取消冒泡

<body>
    <button>按钮</button>
    <script type="text/javascript">
        var btn = document.getElementsByTagName('button')[0];
        btn.onclick = function(e){
            e = e || window.event;
            e.cancelBubble = true;
            console.log(e.bubbles);
        }
        document.body.onclick = function(e){
            e = e || window.event;
            console.log('body');
        }
    </script>
</body>

兼容

stopPropagation()和stopImmediatePropagation()ie8不支持
e.cancelBubble = true;全浏览器支持,不是标准写法
<body>
    <button>按钮</button>
    <script type="text/javascript">
        var btn = document.getElementsByTagName('button')[0];
        btn.onclick = function(e){
            e = e || window.event;
            if(e.stopPropagation){
                e.stopPropagation();
            }
            else{
                e.cancelBubble = true;
            }
            this.innerHTML = '修改了'
        }
        document.body.onclick = function(e){
            e = e || window.event;
            console.log('body');
        }
    </script>
</body>

事件流阶段(了解)

eventPhase

返回一个整数值,表示事件目前所处的事件流阶段

0表示事件没有发生,1表示捕获阶段,2表示目标阶段,3表示冒泡阶段,ie8浏览器不支持

<body>
    <button type="button">事件流</button>
    <script type="text/javascript">
        var btn = document.getElementsByTagName('button')[0];
        //2 目标阶段    
        btn.onclick = function(e){
            e = e || event;
            console.log(e.eventPhase);
        }

        //1 捕获阶段
        document.body.addEventListener('click',function(e){
            e = e || event;
            console.log(e.eventPhase);
        },true)
        //3冒泡阶段
        document.body.addEventListener('click',function(e){
            e = e || event;
            console.log(e.eventPhase);
        },false)
    </script>
</body>

取消默认事件

平时的方法

<a href="javascript:void(0);">百度</a>
<a href="javascript:;">百度</a>

事件对象中的两个方法,阻止默认事件:

  • preventDefault()
  • returnValue
  • return false

preventDefault()

ie8以下不支持

returnValue

火狐、ie8以上不支持

return false

小技巧,兼容所有浏览器

<body>
    <a href="#">百度</a>
    <a href="javascript:;">百度</a>
    <script type="text/javascript">
        var item = document.getElementsByTagName('a')[0];
        item.onclick = function(e){
            e = e||event;


            /* // preventDefault()
            e.preventDefault();
            this.innerHTML = 'john'; */


            /* //returnValue
            e.returnValue = false; */

            //兼容ie8以上
            if(e.preventDefault){
                e.preventDefault();
            }else{
                //兼容ie8以下
                e.returnValue = false;
            }

            /* //小技巧
            return false; */
        }
    </script>
</body>

事件对象属性

鼠标坐标位置

关于坐标位置,事件对象提供了clientX/YpageX/YscreenX/Yx/yoffsetX/YlayerX/Y

clientX/Y & x/y

相对于浏览器(浏览器的有效区域)的x轴和y轴的距离。

<body>
    <div id="box"></div>
    <script type="text/javascript">
        var box = document.getElementsByTagName('div')[0];
        box.onmousemove = function(e){
            e = e || window.event;
            console.log(e);

            this.innerHTML = `clientX:${e.clientX};clientY:${e.clientY};x:${e.x};y:${e.y}`

        }
    </script>
</body>

screenX/Y

相对于显示器屏幕的x轴和y轴的距离。

pageX/Y

相对于页面x轴和y轴的距离,会随滚动条的变化而变化

offsetX/Y

相对于事件源的x轴和y轴的距离。

声明:本文内容由互联网用户自发贡献自行上传,本网站不拥有所有权,未作人工编辑处理,也不承担相关法律责任。如果您发现有涉嫌版权的内容,欢迎进行举报,并提供相关证据,工作人员会在5个工作日内联系你,一经查实,本站将立刻删除涉嫌侵权内容。