JavaSciipt之DOM(二):事件组成与执行过程·事件进行注册和删除

一、事件的组成与执行过程

1、事件的组成
事件是JS检测到的一种行为,触发响应的机制。事件的组成三部分组成:
事件源:事件被触发的对象,如按钮,标签;
事件类型:如何触发,什么事件,鼠标点击触发,经过触发,滚动触发……,onclick()
事件处理程序:通过函数赋值的方式执行;
<body>
  <button id="btn">点击看看</button>
<script>
  var btn = document.getElementById('btn')//1.事件源
  btn.onclick = function() {//2.事件类型
    alert('点击会弹出一个框');//3.处理事件的程序
  }
</script>
</body>
2、执行过程
点击一次就打印一次,再如关闭广告的功能,我的理解是给某个元素一个事件,在这个事件中点击的时候,让元素隐藏,就实现了关闭广告的功能。
<script>
  var div = document.querySelector('div');
  div.onclick = function() {
    console.log('点击看看效果');
  }
</script>

二、事件的注册与删除

1、注册事件
(1)传统的注册事件可以出现在<script></script>、元素、JS文件中,其特点是唯一性。同一个元素同一个事件只能设置一个处理函数,并且后面的函数会覆盖前面注册的函数。
<body>
  <button>按钮1</button>
  <button>按钮2</button>
  <script>
    //all,是选择所有元素,返回结果是个数组,因此,他与btn[i]对应
    var btn = document.querySelectorAll('button')
    btn[0].onclick = function() {
      alert('abcde');
    }
    btn[0].onclick =function() {
      alert('hao a u');
    }
   </script>
</body>
(2)addEventListener()方法,可以实现同一个元素同一个事件可以注册多个监听器,并且按照注册的先后顺序执行。
<body>
  <button>按钮1</button>
  <button>按钮2</button>
  <script>
    //all,是选择所有元素,返回结果是个数组,因此,他与btn[i]对应
    var btn = document.querySelectorAll('button')
    //addEventListen('',function(){})方法,存在兼容性问题,要求IE9以上;第一个参数是事件类型,以字符串的方式存在,不要带on,第二个参数是侦听器(事件处理函数);同一个元素同一个事件,可以注册多个侦听器,并且按照注册的先后顺序执行。
    btn[1].addEventListener('click',function() {
      alert('22');
    });
    btn[1].addEventListener('click',function() {
      alert('33');
    });
    btn[1].addEventListener('click',function() {
      alert('44');
    });
   </script>
</body>
 
<body>
  <button>按钮1</button>
  <button>按钮2</button>
  <button>按钮3</button>
  <script>
    var btn = document.querySelectorAll('button')
    //IE9以下浏览器才支持,第一个参数是事件类型,以字符串的形式存在,必须要加on;第二个参数是侦听器
    btn[2].attachEvent('onclick',function() {
      alert('abc')
    })
   </script>
</body>
兼容性解决方案,先判断是否支持addEventListener(),再判断是否支持attachEvent(),如果上述两种方式都不支持,则使用传统注册方式:onlclick。
2、删除事件
根据添加事件的3种方法,衍生出删除事件的3种方法。删除事件配合添加事件,可以实现让事件在一个元素上实现一次。
<body>
  <div>删除事件1</div>
  <div>删除事件2</div>
  <div>删除事件3</div>
  <script>
      var divs = document.querySelectorAll('div');
      divs[0].onclick = function() {
        alert(11);
        //1.删除传统事件的方法,直接让其值=null即可
        divs[0].onclick = null;
      }
      divs[1].addEventListener('click',fn);
      function fn() {
        alert(22);
        //2.删除addEventListen()方法的事件,不用在匿名函数中删除;要在添加事件之前就考虑到后期的删除事件可能,单独定义函数;同时要注意,调用函数时用函数名即可,不用加小括号。
        divs[1].removeEventListener('click',fn);
      }
      divs[2].attachEvent('onclick',fn1);
      function fn1() {
        alert(33);
        //3.老版本浏览器才兼容
        divs[2].detachEvent('onclick',fn1);
      }
   </script>
</body>
3、DOM事件流
DOM事件流,是事件的传播过程,分为自上而下的捕获阶段、自下而上的冒泡阶段以及当前的目标阶段。冒泡比较常用。
<body>
  <style>
    .father {
      width: 100px;
      height: 100px;
      background-color: red;
    }
    .son{
      width: 50px;
      height: 50px;
      background-color: blue;
    }
  </style>
  <div class="father">
    <div class="son"></div>
  </div>
  <script>
    //1.addEventListen()第三个参数如果为true,则按捕获阶段执行,即从document->html->body->father->son
     var div1 = document.querySelector('.son');
     div1.addEventListener('click',function(){
      alert('son');
     },true) 
     var div2 =document.querySelector('.father');
     div2.addEventListener('click',function(){
      alert('father');
     },true)
    //2.addEventListen()第三个参数如果为false或者省略,则按冒泡阶段执行,即从son->father->body->html->document;这两个阶段,其实就是从外到内,从内到外的执行过程。
     var div1 = document.querySelector('.son');
     div1.addEventListener('click',function(){
      alert('son');
     },false) 
     var div2 =document.querySelector('.father');
     div2.addEventListener('click',function(){
      alert('father');
     },false)
   </script>
</body>
4、事件对象
(1)什么是事件对象?
<body>
  <style>
    .father {
      width: 100px;
      height: 100px;
      background-color: red;
    }
    .son{
      width: 50px;
      height: 50px;
      background-color: blue;
    }
  </style>
  <div class="father">
    <div class="son"></div>
  </div>
  <script>
    var son = document.querySelector('.son');
    //1.event就是一个事件对象,写侦听器的小括号里,当形参来看,名子任意写,如e,evt等;
    //2.事件对象只要有了事件只要有了事件就会出现,不需要额外再传递实参;
    //3.事件对象是一系列相关数据的集合,例如,如果是鼠标事件,就是鼠标鼠标相关数据的集合,例如鼠标的坐标;如果是键盘事件,那就是键盘数据的相关集合,例如按了哪个键;
    //4.事件对象也有兼容性问题,IE6/7/8,使用window.event
    son.onclick = function(event) {
      console.log(event);
    }
    var father = document.querySelector('.father');
    father.addEventListener('click',function(e){
      console.log(e);
    })
   </script>
</body>
 
(2)事件对象与this的区别
<body>
  <style>
    .father {
      width: 100px;
      height: 100px;
      background-color: red;
    }
    .son{
      width: 50px;
      height: 50px;
      background-color: blue;
    }
  </style>
  <div class="father">
    <div class="son"></div>
  </div>
  <script>
    var father = document.querySelector('.father');
    father.onclick = function(event) {
      //this,绑定了哪个元素,他就指代哪个元素
      console.log(this);
      //事件对象event.target,谁触发了事件,它就指代哪个事件对象
      console.log(event.target);
    }
   </script>
</body>
5、阻止事件冒泡
事件对象常见的属性和方法有很多,阻止事件的默认行为、阻止冒泡,比较常用。
<body>
  <style>
    .father {
      width: 200px;
      height: 200px;
      background-color:red;
    }
    .son {
      position: relative;
      left: 50%;
      top: 50%;
      transform: translate(-50%,-50%);
      width: 100px;
      height: 100px;
      background-color: orange;
    }
  </style>
  <div class="father">
    <div class="son">SEO</div>
    <a href="www.bailong.org.cn">白龙网</a>
  </div>
  <script>
    var father = document.querySelector('.father');
    father.addEventListener('click',function(e){
      //1-1返回触发事件的对象,标准
      alert('father');
      //4.阻止冒泡的两种方法,第一种高版本浏览器,第二种低版本浏览器
      e.stopPropagation();
      console.log(e.target);
    })
    var son = document.querySelector('.son');
    son.addEventListener('click',function(e) {
      //1-2返回触发事件的对象,非标准,IE6/7/8等低版本浏览器使用
      alert('son');
      e.stopPropagation();
      e.cancelBubble;
      console.log(e.srcElement);
      //2.返回事件的类型,不带on,如click,mouse
      console.log(e.type);
    })
    var a = document.querySelector('a');
    a.addEventListener('click',function(e) {
      //3-1.阻止事件的默认行为,如不让链接跳转,标准写法
      // e.preventDefault();
      //3-2阻止事件默认行为,IE6/7/8使用
      // e.returnValue;
      //3-3他也可以阻止事件的默认行为,但是,后面的程序会停止运行,但是该方式只限于传统的注册方式
      // return false;
    })
   </script>
</body>
 
6、事件委托
不是把每个子节点都设置一个监听器,而是把监听器设置把父节点上,然后利用冒泡原理,影响每个子节点。
<body>
<ul>
  <li>白龙网</li>
  <li>白龙网</li>
  <li>白龙网</li>
  <li>白龙网</li>
  <li>白龙网</li>
  <li>白龙网</li>
</ul>
  <script>
    var ul = document.querySelector('ul');
    ul.addEventListener('click',function(e) {
      e.target.style.backgroundColor = '#999';
    })
   </script>
</body>
7、鼠标事件
(1)案例:禁止右键、禁止复制
event对象代表事件的状态,现阶段,事件对象主要是鼠标事件与键盘事件。
<body>
  白龙网-从建站到SEO的在线服务平台
  <script>
    document.addEventListener('contextmenu',function(e) {
      //1.禁止右键
      e.preventDefault();
    })
    document.addEventListener('selectstart',function(e) {
    //2.禁止复制
      e.preventDefault();
    })
   </script>
</body>
 
(2)案例:获取鼠标坐标位置
<body>
  <script>
    document.addEventListener('click',function(e) {
      //1.client,是相对于可视区浏览器的坐标位置,滚动浏览器,坐标位置不变
      console.log(e.clientX);
      console.log(e.clientY);
      console.log('-------------------------------');
      //2.page相对于文档页面的X/Y坐标
      console.log(e.pageX);
      console.log(e.pageY);
      console.log('-------------------------------');
      console.log(e.screenX);
      console.log(e.screenY);
    })
   </script>
</body>
(3)案例:移动的天使,跟随鼠标的文字
<body>
  <style>
    div {
      position: absolute;
      width: 50px;
      height: 25px;
    }
  </style>
  <div>白龙网</div>
  <script>
    var div = document.querySelector('div');
    //0.在整个文档区注册事件
    document.addEventListener('mousemove',function(e) {
      //1.获取鼠标相对页面的位置
      var x = e.pageX;
      var y = e.pageY;
      //2.把坐标的位置赋值给绝对定位的div的top/left
      div.style.left = x + 'px';
      div.style.top = y  + 'px';
    })
   </script>
</body>
 
8、键盘事件
键盘事件的执行顺序是onkeydown->onkeypress->onkeyup。
  <script>
    document.onkeydown = function() {
      //1.鼠标按下
      console.log('onkeydown');
      //2.鼠标按下,不能识别功能键如shift,alt,箭头等。
      console.log('onkeypress');
      //3.鼠标松开
      console.log('onkeyup');
    }
  </script>
案例1:判断用户按下了哪个键
    <script>
    document.addEventListener('keydown',function(e) {
      //1.keyup、keydown可以识别功能键,但是无法区别大小写
      console.log(e.keyCode);
    })
    document.addEventListener('keypress',function(e) {
      //2.keypress可以区分大小写,但是无法识别功能键
      console.log(e.keyCode);
    })
    document.addEventListener('keyup',function(e) {
      //3.使用e.keyCode属性值、借助ASCII码判断按下了哪个键
      if (e.keyCode == 65) {
        console.log('你按住了:A');
      } else {
        console.log('按错了,没有按:A');
      }
    })
  </script>
 
案例2: 模拟京东按钮输入s,搜索框自动获取焦点输入
<body>
  <input type="text">
  <script>
   var search = document.querySelector('input')
   document.addEventListener('keyup',function(e) {
    // console.log(e.keyCode);使用事件对象获取按键的ASCII的值,确定按了哪个键
    if (e.keyCode === 83) {
      //如果按了s键,就把焦点给到search对象
      search.focus();
    }
   })
  </script>
</body>
 
案例3:模拟京东快递单号查询(类似放大镜功能)
这里需要注意的是,为什么这里用keyup,遭遇不用keydown/keypress。涉及两个事件类型的区别了:
keydown/keypress,是当按键按下时,已经触发了事件,但是文字还没有输入,当然内容就会显示不全了;
而keyup,是按键松开前,文字已经完成了输入,所以内容都显示出来了。
<body>
  <style>
    .cron {
      display: none;
      height: 30px;
      width: 167px;
      border: 1px solid #999;
      font-size: 25px;
      line-height: 30px;
    }
  </style>
  <div class="search">
    <div class="cron"></div>
    <input type="text" placeholder="请输入关键词" class="bailong">
  </div>
  <script>
  var cron = document.querySelector('.cron');
  var bailong = document.querySelector('.bailong');
  bailong.addEventListener('keyup',function() {
    //判断如果没有输入内容,或者输入内容为空时,隐藏上面的盒子;有内容输入,则显示上面的盒子,并且把输入的内容赋值给上面盒子的对象
    if (this.value === '') {
      cron.style.display = 'none';
    } else {
      cron.style.display = 'block';
      cron.innerHTML = this.value;
    }
  });
  //加处加一个判断,当失去焦点的时候,隐藏上面的盒子;当获得焦点且输入内容非空时,显示上面的盒子
  bailong.addEventListener('blur',function() {
    cron.style.display = 'none';
  });
  bailong.addEventListener('focus',function() {
    if(this.value != '') {
      cron.style.display = 'block';
    }
  })
  </script>
</body>
  白龙网认为,对于JS事件,我们需要了解事件组成、执行;另外,对于事件注册、删除、对象、委托、流、冒泡、、类型也要熟练运用。