事件及相关知识

Posted davina123

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了事件及相关知识相关的知识,希望对你有一定的参考价值。

  什么是事件?事件是元素天生自带的一种行为,当我们操作元素的时候,也会把对应的事件触发。而事件绑定是给元素的某个行为绑定一个方法,目的是当事件行为触发时,可以处理一些操作。

  常用的事件行为有以下几种:鼠标事件 ,键盘事件,资源事件,焦点事件,触摸事件等等,在了解一些常用的事件前我们要先了解事件的传播机制。 

  一、事件传播机制

  事件流又称为事件传播,DOM2级事件规定的事件流包括三个阶段:捕获阶段(capture phase)、目标阶段(target phase)冒泡阶段(bubbling phase)。

  捕获阶段:在事件触发时,会先执行一个阶段叫做“捕获阶段”,从最外层向最里层事件源依次进行查找(从外到内)。可以看出捕获阶段的目的是:为冒泡阶段事先计算好传播的层级路径。

  目标阶段:当前元素的相关事件行为触发

  冒泡阶段:触发当前元素的某一个事件行为,不仅仅它的这个行为被触发,而且它所有的的祖先元素相关的事件行为都会被依次的触发(从内到外的顺序)

  首先发生的是事件捕获,为获取事件提供机会。然后是实际的目标接收到事件,最后一个阶段是冒泡阶段,可以在这个阶段对事件做出响应。

  不论是捕获阶段还是冒泡阶段,在寻找目标元素的过程和向外返回的过程中,所遇到每一个元素身上如果有相同事件的事件处理函数都会被调用。

<!DOCTYPE html>
<head>
    <title>Document</title>
</head>
<body>
    <div class="outer">
        <div class="inner">
            <div class="center">执行</div>
        </div>
    </div>
</body>
</html>

  由上面的结构,可以出事件捕获是从:window ->document->html->body->outer_div->inner_div->center_div

  目标阶段:center_div

  冒泡阶段:center_div->inner_div_outer_div->body->html->document->window

  用下图来作为说明:

技术图片

  二、事件的分类

  1、鼠标事件

   鼠标事件共11类,包括click,dbclick,contextmenu,mousedown,mouseup,mousemove,mouseover,mouseenter,mouseout,mouseenter,mouseleave,mousewheel。

    /* 
     *  事件名称            详情
     *  click               点击事件
     *  dbclick             双击事件
     *  mousedown           鼠标按下
     *  mouseup             鼠标抬起
     *  mousemove           鼠标移动(指针在元素内移动时持续触发)
     *  mouseover           鼠标经过
     *  mouseenter          鼠标进入(指针移到有事件监听的元素内)
     *  mouseout            鼠标离开(指针移出元素,或者移到它的子元素上)
     *  mouseenter          鼠标进入,类似于mouseover
     *  mouseleave          鼠标离开(指针移出元素范围外,不冒泡)
     *  wheel         滚轮向任意方向滚动
     *  contextmenu         鼠标右键点击
    */

  二、键盘事件

   /*
    * keydown               键盘按下
    * keypress              键盘长按(keypress当用户按下键盘上的字符键时触发,按下功能键(ctrl,shift等)时不触发)
    * keyup                 键盘抬起
    */

技术图片

  3、移动端触摸事件

  /* 
   * touchstart        手指触摸到一个DOM元素时触发   
   * touchmove         手指在一个DOM元素上滑动时触发
   * touchhead         手指从一个DOM元素上移开时触发
* touchcancel     操作取消
*/

  4、其它事件

   /* 
    * 其它事件
    *  error         资源加载失败时
    *  load          资源加载完
    *  focus         元素获得焦点
    *  blur          元素失去焦点
    *  reset         点击重置按键
    *  submit        点击提交按钮
    *  change        内容改变
    *  scroll        滚动条
    *  resize        大小改变
* gesturestart
* gesturechange/gestureupdate
   * canplay
   * canplaythrough
* readystatechange AJAX 请求状态改变事件
   * ......
*/

  二、事件绑定

  事件绑定:给元素的某个事件行为绑定方法,这样事件行为触发的时候,对应绑定的方法会执行,完成一些需要完成的功能

  1、DOM0级事件绑定

    元素.on事件行为 = function(){};

    原理:事件绑定的原理就是给当前元素对象的某些私有属性赋值一个函数,当事件行为触发,浏览器会帮助把绑定的方法执行。

    注意:on只能给元素添加一个事件,如果说有多个on,那后面的会把前面的进行覆盖。

    不足:如果元素私有属性中不具备某个事件的私有属性则无法给这些事件绑定方法

    事件移除:元素.on事件行为 = null;

  2.DOM2级事件绑定

   【标准浏览器】

    元素.addEventListener(事件行为,function(){},true/false);

    参数解析:参数1:事件行为,不加on,它是一个字符串;

         参数2:事件绑定,这个事件绑定函数可以是匿名也可以是命名(真实项目中最好命名);

         参数3:布尔值:true代表事件是在捕获阶段发生,falses代表事件在冒泡阶段发生。

    原理:基于元素的原型链找到EventTarget.prototype,使用内置的方法进行事件绑定和移除。它是基于浏览器内置的事件池机制完成事件监听和方法的绑定。

    注意:可以给当前元素的某个事件类型绑定多个不同的方法,事件触发会按照绑定的顺序把方法依次执行。 

         基于addEventListener向事件池增加方法,存在去重的机制“同一个元素,同一个事件类型,在事件池中中只能存储一遍这个方法,不能重复的存储”。

    事件移除:元素.removeEventListener(事件行为,function(){},true/false);需要注意的是不能移除addEventListener添加的匿名函数。只能称除同一阶段的绑定函数(布尔值相同)。

   【IE6-8】

    元素.attachEvent(’onxxxx‘,function(){});

    事件移除:detachEvent(event,function(){});

  三、事件对象及常用属性

  在触发DOM上的某个事件时,会产生一个事件对象event,这个对象中包含着所有与事件有关的信息。所有浏览器都支持event对象。

  事件对象和函数以及给谁绑定的事件没有必然的关系,它存储的是当前本次操作的相关信息,操作一次只能有一份信息,第二次存储的信息会把上一次操作存储的信息替换。

  普通事件对象:事件对象包含与创建它的特定事件有关的属性和方法。触发的事件类型不一样,可用的属性和方法也不一样。不过,所有事件都有些共有的属性和方法。常用的有type(事件类型),target(事件源),path, stopPropagation, srcElement,which......。

  鼠标事件对象:如果是鼠标操作,获取的是MouseEvent类的实例,我们把其叫做鼠标事件对象。鼠标事件对象-> MouseEvent.prototype->UIEvent.prototype->Event.prototype->Object.prototype

  常用的属性和方法有:

    clientX/clientY: 当前鼠标触发点距离当前窗口左上角的x/y轴坐标;

    pageX/pageY:当前鼠标触发点距离当前页面左上角x/y轴坐标,它与clientX/clientY的区别是它们不随滚动条的位置变化;

    screenX/screenY:表示鼠标指针相对于屏幕的水平和垂直坐标;

    offsetX/offsetY: 表示相对于定位父级的水平和垂直坐标当页面无定位元素时,body是元素的定位父级。由于body的默认margin是8px,所以offsetX/Y与clientX/Y差(8,8)。

  在鼠标事件中,除了mouseenter和mouseleave事件外,所有的鼠标都是会冒泡的。(也可理解为mouseenter/mouseleave不会把事件传递给子元素)

  当鼠标移入时,会依次的触发mousemove事件和mouseenter事件,再触发mousemove事件。

  当鼠标移出时,触发mousemove,mouseout,mouseleave事件.

  双击鼠标时触发mousedown,mouseup,click,mousedown,mouseup,click,dbclick事件

  点击鼠标右键触发mousedown,mouseup,contextmenu事件

  嵌套元素的移入移出时:   

    从父级元素进入子级元素时,顺序为:父级元素的mouseout、子级元素的mouseover、父级元素的mouseover、子级元素的mouseenter

    从子级元素进入父级元素时,顺序为:子级元素的mouseout、父级元素的mouseout、子级元素的mouseleave、父级元素的mouseover

    <div>点击</div>
    <script>
        let div = document.querySelector(div);
        div.onclick=function(ev){
            console.log(ev);
        }
    </script>

  示例:鼠标点击出现小圆圈效果

  html&css部分

 <style>
    div {
      width: 10px;
      height: 10px;
      border-radius: 50%;
      border: 2px solid rgb(146, 145, 145);
      position: absolute;
      left: 0;
      top: 0;
      display: none;
    }
  </style>
<body>
  <div></div>
  <div></div>
  <div></div>
</body>

  js部分

<script>
  let divs = document.querySelectorAll("div");
  //创建一个move函数,obj代表你要运动的哪个div,ev代表事件对象
  function move(obj, ev) {
    obj.style.display = block;
    var opc = 100;
    var timer = setInterval(function () {
      //宽高慢慢变大
      obj.style.width = obj.offsetWidth + 5 + px;
      obj.style.height = obj.offsetHeight + 5 + px;
      //每走一次透明度要变化
      obj.style.opacity = (opc -= 10) / 100;
      obj.style.left = ev.clientX - obj.offsetWidth / 2 + px;
      obj.style.top = ev.clientY - obj.offsetHeight / 2 + px;
      //清除定时器
      if (opc <= 0) {
        clearInterval(timer);
        //在定时器停的时候,把它们的值都回到最初的状态,为了下一次点击还从最初的状态开始运动
        obj.style.width = 10px;
        obj.style.height = 10px;
        obj.style.opacity = 0;
      }
    }, 17);
  }
  //调用move函数
  document.onclick = function (ev) {
    //走第一个圈
    move(divs[0], ev);
    //走第二个圈
    setTimeout(function () {
      move(divs[1], ev);
    }, 500);

    // 走第三个圈
    setTimeout(function () {
      move(divs[2], ev);
    }, 1000);
  }
</script>

  键盘事件对象:如果是键盘操作,获取的是keyboardEvent类的实例.。我们叫其键盘事件对象。键盘事件对象-> KeyboardEvent.prototype->UIEvent.prototype->Event.prototype->Object.prototype

  常用的键盘码:左 上 右 下:37 38 39 40 enter: 13 backspace: 8 del: 46 ctrl :17 shift:16 space:32

  常用的属性:event.keyCode、eventctrlKey、eventshiftKey......

  常用的事件:keydown、keypress、keyup

    keydown:当用户按下键盘上的任意键时触发,如果按住不放的话,会重复触发该事件

    keypress:当用户按下键盘上的字符键时触发,按下功能键时不触发。如果按住不放的话,会重复触发该事件

    keyup:当用户释放键盘上的键时触发

示例:身份证18位

 <input type="text" id="cardID">
    <script>
        let cardID = document.querySelector(input);
        cardID.onkeydown = cardID.onkeyup = function (ev) {
            // console.log(ev.keyCode);
            let val = this.value,
                reg = /[^0-9X]/g;
            this.value = val.replace(reg, ‘‘);
            //超过18位,禁止
            if (this.value.length >= 18) {
                let arr = [8, 13, 37, 38, 39, 40, 46]
                if (!arr.includes(ev.keyCode)) {
                    ev.preventDefault();
                }
            }
            //按enter弹出
            if (ev.keyCode === 13) {
                alert(this.value);
            }
        }
    </script>

  阻止默认行为: 阻止默认行为需要知道这些默认行为什么时候发生。普遍的有两种方式:return false、preventDefault().

    <a  id ="link" href="www.baidu.com">阻止跳转</a>
    <script>
        /*
        link.onclick=function(ev){
             //返回一个false,相当于结束后面即将执行的步骤
             return false;
         }
         */

        /*
        link.onclick = function(ev){
             ev.preventDefault();
         }
         */
    </script>

  四、mousseout与mouseover的区别

    <style>
        .outer{
            margin:200px auto;width: 400px;height: 400px;background-color: lightgreen;}
        .inner{
            margin:200px auto;width: 300px;height: 300px;background-color: lightblue;
        }
        .center{margin:200px auto;width: 200px;height: 200px;background-color: lightpink;
        }
    </style>
<body>
    <div class="outer">
        <div class="inner">
            <div class="center"></div>
        </div>
    </div>
</body>  

    如上代码所示,我们可以看到下面图片的分析,从分析中我们可以出:

  mouseover本身不是进入,而是看鼠标在哪个元素上面,从子元素进入父元素,触发父元素的mouseover,从父元素进入子元素触发父元素的mouseout

  mouseleave默认阻止了事件的冒泡传播,从父元素进入子元素,从子元素重新进入父元素,父元素的mouseenter和mouseleave都不针对触发。

  所以盒子中如果有后代元素,我们尽量用mouseenter,但是需要冒泡传播做的事情,还是需要用mouseover。

技术图片

  

 

以上是关于事件及相关知识的主要内容,如果未能解决你的问题,请参考以下文章

jQuery相关知识

JavaScript小技能:事件

js中BOM与DOM的相关知识基础

JavaScript DOM事件进阶及相关练习

PAT甲级考试题库1001 A+B Format 代码实现及相关知识学习

android小知识点代码片段