事件和事件对象

作者: icessun | 来源:发表于2017-07-13 22:47 被阅读48次
事件流.png

事件

就是和浏览器产生交互效果的,事件触发和函数一起使用,当触发事件的时候,调用相应的事件去处理接下来的事情。

DOM0级事件

直接在dom对象上注册事件名称,所有浏览器都支持。

document.getElementById('div1').onclick=function(e){ // 触发事件之后的操作}

事件触发会默认传入一个参数e事件对象;通过这个事件对象,可以获取到触发这个事件的dom元素,点击的坐标值,等一些主要的信息。当然事件的触发也可以这样写:

document.getElementById('div1')['onclick']=function(e){// 触发事件后的操作}

这上面的两种事件的触发,其实也就是js对象身上属性的两种访问方式,也就是说:

  • DOM0级事件是元素对象的私有属性;
  • 同一个元素对象,同一个事件行为,只能绑定一次,多次绑定,后面的会覆盖前面的;
  • DOM0级事件发生在事件流的冒泡阶段

DOM0级事件中的this

一般下面这种写法的时候,当事件触发的时候,事件中的this就是指向触发该事件的dom元素对象

 <script>
var oDiv=document.getElementById('div1');

oDiv.onclick=function(e){ 
// 触发事件之后的操作
alert(this.id); // div1
}

// 要想解除div身上的点击事件,直接在后面注册点击事件并且设置为null
oDiv.onclick=null;
 </script>

当把事件写在html代码里面的时候,虽然也遵守事件覆盖的原则,但不会传入event事件对象,相当于动态调用函数,this指向的是window,而不是事件触发者:dom元素

<div id='div1' class='div1' onclick='exec();'></div>

DOM2级事件

支持元素绑定多个事件

  • addEventListener()
    • 注册事件
    • this指向被绑定事件的这个元素
    • 三个参数:事件行为(去掉前边的on),处理函数回调(默认传入event对象,this指向触发的元素节点),捕获/冒泡(true/false)
    • 给同一个元素,同一个行为绑定多次同一个方法,实际上只执行一次
    • 对应同一个元素来说,是按照事件绑定的先后顺序执行的
var btn=document.getElementById('div');
btn.addEventListener('click',function(e){
     console.log(this); // btn
  },false)
  • removeEventListener()

    • 移除事件
  • IE8及其以下版本浏览器,

    • attachEvent(事件处理程序名称与事件处理程序函数)
      • 对于同一个元素,绑定多个事件,事件执行的顺序不是按照绑定的顺序执行
      • 事件中的this默认指向window,即事件处理程序会在全局作用域内执行,与DOM0级事件相比,事件作用域在其所属元素内运行
      • 给同一个元素,同一个行为绑定多次同一个方法,执行是多次的
    • detachEvent()
  • 阻止冒泡

    • e.stopPropagation() 标准浏览器
    • e.cancelBubble=true 低级IE浏览器
    • 兼容性写法
     通过e.stopPropagation来判断是标准浏览器还是低级IE浏览器
    
      e.stopPropagation? e.stopPropagation(): e.cancelBubble=true;
    
  • 阻止默认事件

原先点击的事件,事件应该发生本来的事件效果,但是可以去阻止默认的事件

  • e.preventDefault 标准浏览器
  • e.returnValue=false 低级IE浏览器
通过e.preventDefault来判断是标准浏览器还是低级IE浏览器

 e.preventDefault?e.preventDefault():e.returnValue=false;

只能输入和编辑数字

<input type="text" placeholder="只能输入和编辑数字" id="txt"/>
<script>
     var oText=doucment.getElementById('txt');
     oText.onkeydown=function(e){
       e=e||window.event;
       // console.log(e.keyCode)
// 阻止默认事件
     if((e.keyCode<48||e.keyCode>57)&&e.keyCode!==8){
              e.preventDefault?e.preventDefault():e.returnValue=false;
    }
 }

事件流

定义

文档对象模型DOM的结构是一个树状,当一个元素产生一个事件时,该事件会在元素节点与跟节点按特定的顺序传播,路径所经过的节点都会收到该事件,这个过程称为事件流

类型

  • 事件捕获
    • 从上往下
    • 由最顶层的元素到下面最精确的元素(事件产生的元素)
  • 事件冒泡
    • 从下往上
    • 事件从子节点(事件产生的元素)一直向上传递到根节点
    • 事件发生的元素传递到与元素有确定从属关系的其他元素上面,直到传递找不到确定的元素上面结束
    • 冒泡的好处:事件委托

DOM标准同时支持上述两种事件类型,但是捕获事件先发生。两种事件流都会触发DOM中的所有对象,在document对象开始,也在其中结束。但也有标准的浏览器会将事件延续到window对象

  • 捕获事件要比冒泡事件先触发
<div id='div1'>
    <div id='div2'></div>
</div>

var btn=document.getElementById('div1');
            
            // 冒泡
            btn.addEventListener('click',function(e){
                console.log('冒泡')
            },false);
            
            // 捕获事件
            btn.addEventListener('click',function(e){
                console.log('捕获')
            },true);

当我们点击里面的div的时候,是先打印捕获,在打印冒泡;但是当我们先点击外面的div的时候,是先打印的冒泡,在打印的是捕获;为什么?

根据事件流触发的顺序图,可以知道,当我们点击里面的div的时候,根据下面的事件流传递的过程原理知道,是先发生捕获事件在发生冒泡事件;当点击的是外面的div,并且事件绑定在点击元素上面,其触发的顺序是按照绑定的顺序触发的

外层div和内层div同时注册了捕获事件,那么点击内层div时,外层div的事件一定是先触发的;外层div和内层div都是注册的冒泡事件,点击内层div时,一定是内层div事件先执行,原理相同。

事件流触发顺序
首先是捕获事件传递,接着是冒泡事件传递;要是一个事件处理函数同时注册了捕获和冒泡事件,则会在dom事件模型中调用两次。标准的DOM事件模型(特有):文本节点也会触发事件,但是IE不会

事件流传递过程

如果为一个超链接添加了click事件监听器,那么当该链接被点击时该事件监听器就会被执行。但如果把该事件监听器指派给了包含该链接的p元素或者位于DOM树顶端的document节点,那么点击该链接也同样会触发该事件监听器。这是因为事件不仅仅对触发的目标元素产生影响,它们还会对沿着DOM结构的所有元素产生影响。

W3C事件模型标准

W3C事件模型中明确地指出了事件流转送的原理。可以分为3个阶段。

  • 事件捕捉(Capturing)阶段
    • 事件将沿着DOM树向下转送,目标节点的每一个祖先节点,直至目标节点。
    • 例如,若用户单击了一个超链接,则该单击事件将从document节点转送到html元素,body元素以及包含该链接的p元素。
    • 在此过程中,浏览器都会检测针对该事件的捕捉事件监听器,并且运行这件事件监听器。
    • 实际事件发生的目标元素在捕获阶段是不会接收事件的。
  • 目标(target)阶段
    • 浏览器在查找到已经指定给目标事件的事件监听器之后,就会运行该事件监听器。目标节点就是触发事件的DOM节点。
    • 例如,如果用户单击一个超链接,那么该链接就是目标节点(此时的目标节点实际上是超链接内的文本节点)。
    • 事件发生的目标元素发生事件并且处理事件。
  • 冒泡(Bubbling)阶段
    • 事件将沿着DOM树向上转送,再次逐个访问目标元素的祖先节点到document节点。
    • 该过程中的每一步,浏览器都将检测那些不是捕捉事件监听器的事件监听器,并执行它们。

并非所有的事件都会经过冒泡阶段的,所有的事件都要经过捕捉阶段和目标阶段,但是有些事件会跳过冒泡阶段。例如,让元素获得输入焦点的focus事件以及失去输入焦点的blur事件就都不会冒泡。

事件冒泡(代理\委托)

利用到事件的冒泡和目标元素,把事件处理器添加到父元素上,等待子元素事件冒泡,并且父元素能够通过target,IE为srcElement来判断是哪一个子元素,从而进行处理

<style>
        div{
            width: 100px;
            height: 100px;
            margin: 10px;
            font-size: 20px;
            float: left;
            background: #ff0000;
        }
    </style>
</head>
<body>
<script>
    for(var i=0; i<20; i++){
        var oDiv=document.createElement('div');
        oDiv.innerHTML='<a href="javascript:;">'+i+'删除我吧</a>';
        document.body.appendChild(oDiv);
    }
    //如果一个容器中,有很多个元素,都要触发某个行为,我们可以这个行为委托给他们共同的父级;然后通过事件源来做不同的区分;
    document.body.onclick=function(e){
        e=e||window.event;
        //通过事件源来做不同的区分
        e.target= e.target|| e.srcElement;
        if(e.target.tagName.toLowerCase()=='a'){
            this.removeChild(e.target.parentNode);
        }
    }
</script>
</body>

好处

  • 将多个事件处理器减少到一个,因为事件处理器要驻留内存,这样就提高了性能。想象如果有一个100行的表格,对比传统的为每个单元格绑定事件处理器的方式和事件代理(即table上添加一个事件处理器),不难得出结论,事件代理确实避免了一些潜在的风险,提高了性能。
  • DOM更新无需重新绑定事件处理器,因为事件代理对不同子元素可采用不同处理方法。如果新增其他子元素(a,span,div等),直接修改事件代理的事件处理函数即可,不需要重新绑定处理器,不需要再次循环遍历。

相关文章

  • 事件和事件对象

    事件 就是和浏览器产生交互效果的,事件触发和函数一起使用,当触发事件的时候,调用相应的事件去处理接下来的事情。 D...

  • JS中的事件机制(下)

    上文介绍了事件流和事件类型,本文介绍事件对象和事件代理 事件对象 在触发DOM上的某个事件时,会产生一个事件对象e...

  • 事件对象和事件委托

    事件对象事件发生的详细信息 在ie和chrome 事件详细信息保存到内置的 event对象中Event 对象代表事...

  • Js事件和事件对象

    一、事件概述 事件三要素:事件源:触发(被)事件的元素事件类型:事件的触发方式(例如鼠标点击或键盘点击)事件处理程...

  • JQ事件和事件对象

    bind() bind(type [,data],fn);第二个参数可选,传递给事件对象等额外数据对象 ?? 简写...

  • 事件委托和事件对象

    事件委托((原理是事件冒泡)) 事件对象 在上面我们给事件处理函数一个参数e,他代表的就是事件对象,当事件发生时,...

  • jQuery|event的属性和方法

    jQuery事件对象event的属性和方法 事件处理(事件对象、目标元素的获取,事件对象的属性、方法等)在不同浏览...

  • js的事件流

    一、JavaScript的事件对象 1.event:事件对象; 当一个事件发生时,和当前这个对象发生的事件有关的信...

  • VC++(十六)线程同步与异步套接字编程

    事件对象也属于内核对象,分为两种:人工重置的事件对象和自动重置的事件对象。 当人工重置的事件对象得到通知时,等待该...

  • 关于e.target.value

    每次触发DOM事件时会产生一个事件对象(也称event对象),此处的参数e接收事件对象。而事件对象也有很多属性和方...

网友评论

  • 张学峰_35c0:有个问题,实际操作发现在上面div1,div2举例捕获/冒泡的时候,是错误的。无论从外面点击还是里面点击都是先捕获后冒泡
    张学峰_35c0: @icessun get ,thanks .
    icessun:前提:当你绑定的事件在外面的div上面的时候,并且是先绑定冒泡在绑定捕获事件
    结果:点击外面的div是先冒泡在捕获的
    分析:因为按照事件传递的原则,在前提条件的假设情况下,你点击了外面的div1,按照原则,那么这个元素是捕获的终点,也是冒泡的起点,但是冒泡事件先注册,捕获事件后注册,所以冒泡事件先发生,捕获事件后发生

本文标题:事件和事件对象

本文链接:https://www.haomeiwen.com/subject/uoejhxtx.html