注册事件

前面学习到注册事件方法如下

  • <button onclick="alert("hi")">注册事件</button>
  • btn.onclick=fuction(){}

但是这样注册事件有一个缺点,同一个元素不能注册两个事件,前面的事件会被后面的事件覆盖掉。

监听注册事件 addEventListener

evenTarget.addEventListener(type,listener[,useCapture])

  • type :事件类型的字符串 'click', 'mouseover' ,注意不带 on
  • listener 事件处理函数
  • useCapture,可选值 默认为false

实例:

        var btn=document.querySelector('button');
        btn.addEventListener('click',function(){
            alert('监听注册事件');
        });

使用这个方法,一个元素就可以加入不同事件了。IE9之前不支持。

删除事件 removeEventListener

如果我们采用btn.onclick=fuction(){}的方法,那么我们想要删除,其实只需要,btn.onclick=null就好了。

如果采用后面的方法

target.removeEventListener(type, listener[, options]);

  • type,一个字符串,表示需要移除的事件类型,如 "click"
  • listener: 需要移除的函数名

当然如果前面你写的是匿名函数,就无法通过这个方法解绑了。

        var btn=document.querySelector('button');
        btn.addEventListener('click',fn);
		function fn(){
            alert('监听注册事件');
            //移除事件
		btn.removeEventListener('click',fn)
        }
		

dom 事件流

事件流就是 从页面接受事件的顺序

事件发生时会在元素节点之间,按照特定的顺序传播,这个传播的过程就叫做事件流

事件流

如上图我们给div注册了个事件,当事件触发的时候并不是div直接执行事件函数的,而是经历如上图流程。

  1. 捕获阶段:事件由页面元素接收,逐级向下,到具体的元素
  2. 目标阶段: 目标元素执行阶段
  3. 冒泡阶段:跟捕获相反,具体元素本身,逐级向上,到页面元素

比如div注册了个click事件,先从 document一步步捕获,找到谁是click的目标,看到document没有click事件就去找他的子元素html,发现html也没有,在一步一步找到div。这就好像事件click在被传播,所以才叫事件流。

另外,如果捕获,冒泡,同时存在,如图那么先走捕获,在走冒泡

开始论证

evenTarget.addEventListener(type,listener[,useCapture]),我前面对这个 第三个参数没有过多的介绍,其实放在这里才能说的清楚。

useCapture,可选值 默认为false

  • 如果true,表示在走捕获阶段调用处理事件函数
  • 默认,false,那么就表示冒泡了。
image-20210128210739709

捕获阶段

根据前面粗略的讲解,我们可以大胆猜测,捕获阶段,父元素如果和子元素有相同的条件触发,那么父元素会比子元素先执行。

        var  son=document.querySelector('.son');
        var father= son.parentNode;
        son.addEventListener('click',function(){
            alert('子元素后执行');
        },true);
        father.addEventListener('click', function () {
                alert('父元素元素先执行');
            }, true);

事实的确如此。

捕获阶段.gif

冒泡阶段

那么就和前面的相反即可。父元素如果和子元素有相同的条件触发,那么子元素会比父元素先执行。

捕获冒泡同时存在

同时存在的话,那么先捕获后冒泡。

        var  son=document.querySelector('.son');
        var father= son.parentNode;
        son.addEventListener('click',function(){
            alert('子元素 ');
        },true);
        
        father.addEventListener('click', function () {
                alert('父元素 冒泡');
            }, false);
        father.addEventListener('click', function () {
                alert('父元素 捕获');
            }, true);
同时存在.gif

事件对象 event

我们的事件处理函数,也是有参数的,

btn.onclick=fuction(event){},我们可以从event获取很多关于事件的信息,鼠标的坐标,按键的asc码等等。

当然只要事件处理函数,有了参数,我们就可以从中获取信息,不一定要event才可以,写作 e也可以。

万恶的ie 6 7 8版本是通过 只能写window.event,为了兼容性我们可以这样写

btn.onclick=fuction(e){ e=e||window.event;}通过逻辑短路来处理。

e.target

返回触发事件对象。

我们在这里要分开,this和target

this返回的是绑定事件的对象。

target 返回的触发对象。

比如如下情况

    <div>target
        <span>this</span>
    </div>
    <script>
        var div =document.querySelector('div');
        div.addEventListener('click',fn);
        function fn(e){
            console.log(e.target);
            console.log(this);
        }
    </script>

span是 div的子元素,当我们点击,span里的target 文字,

e.target返回的是span, this返回的是 div。

e.type

返回事件类型

比如 click,mouseover; 不带on!

preventDefault()

阻止默认的行为

我们可以通过这个方法,实现让链接不跳转

<a href="https://yingwiki.top">点我不会跳转</a>
var a=document.querySelector('a');
        a.addEventListener('click',function(e){
            e.preventDefault();
        })

这个函数在老ie是没有的,还有一个方法也可以实现一样的效果。

使用 btn.onclick=fuction(event){} 注册事件

rerurn false; 也可以实现不跳转,但是return 后面的代码就不会执行。

如何阻止冒泡

我们常用的冒泡来触发事件,为了保证父元素和子元素有一样的触发事件的时候,我们不想要的画面。阻止冒泡是必不可少的。

e.stopPropagation();

我们给事件处理函数加上这一句就可以了。

当然为了兼容ie,我们可以这样写

if(e&&e.stopPropagation)
    {
        e.stopPropagation();
    }else{
        //ie支持这样子的
        window.event.cancelBubble=true;
    }

事件委托

当然事件冒泡不一定只有坏处,灵活执行还有不少的好处。

    <ul>
        <li>事件委托</li>
        <li>事件委托</li>
        <li>事件委托</li>
        <li>事件委托</li>
        <li>事件委托</li>
    </ul>

如果我们想每个li 都有点击事件,我们可以使用循环去注册事件,但是这样也会有坏处,访问do次数太多,效率不高。

想这个情况,我们就可以给父元素ul注册点击事件,利用target获取每个li,我们这里改变我们点击li的背景颜色

        var ul=document.querySelector('ul');
        ul.addEventListener('click',function(e){
            for(var i=0;i< ul.children.length;i++)
            {
                //还原其他li的背景颜色
                ul.children[i].style.backgroundColor='#fff';
            }
            e.target.style.backgroundColor='#999';
        });

鼠标事件对象 MoseEvent

常用属性说明

e.clentX,e.clentX

相对可视区的坐标。

image-20210128223044087

这个坐标是不随着页面的滚动而随意改变的。

pageX ,pageY

相对于整个文档的坐标,滚动条往下滚坐标也会改变。

screenX screenY

相对于电脑屏幕的坐标

键盘事件

  • keyup 按键弹起的时候触发

  • keydown 按键按下

  • keypress 某个按键按下时触发 ,不识别功能按键 ctrl shift 等

按键被按下,执行顺序四 down --> press --> up

e.key

返回按下键的值

e.keyCode

返回按下键的ASCII值

常用事件 补充

contextmenu 上下文菜单,当用户右击元素时将显示上下文菜单

如何禁止有鼠标右键复制

document.addEventListener('contextmenu',function(e){
            e.preventDefault();
        });

鼠标选择文字 selectstart

阻止用户鼠标选中文字

document.addEventListener('selectstart', function (e) {
                e.preventDefault();
            });

努力成长的程序员