Js高级程序设计第三版学习(十三章)

                             Js高级程序设计第三版学习(十三章)

 

 第十三章 事件

事件就是文档或者浏览器窗口中发生的特定的交互的瞬间

  1.事件流:  

事件流描述的是页面中接收事件的顺序

  • 事件冒泡  

事件开始由最具体的元素(目标元素) 直至不具体的节点(文档), 事件会依次传播,例如点击一个div,click事件会传递到他的父级直到document或window,所有浏览器都支持事件冒泡

    <ul id="uu" style="height:1800px;margin-top: 0;position: relative">
      <li id="hehe" class="ppap">
        <div id="divClick">1</div>
        <div>2</div>
        <div>3</div>
        <div>4</div>
      </li>
      <li class="ppap" id="pppp">2</li>
      <li class="ppap"><input type="text" id="text" /></li>
      <li class="ppap"><a href="https://www.baidu.com">adhlasdhl</a></li>
    </ul>
    <script>
      var hehe = document.getElementById('hehe');
      var divClick = document.getElementById('divClick');
      hehe.onclick = function() {
        console.log('hehe');
      };
      divClick.onclick = function() {
        console.log('divClick');
      };
      window.onclick = function(){
        console.log('window')
      }
      /* 
        页面会依次打印 hehe,divClick,document,window
       */
    </script>
  • 事件捕获

事件捕获与冒泡相反,不具体节点先接收事件,具体节点在最后接收事件,它的寓意在于事件在到达预定目标之前捕获他

  • DOM事件流

DOM2级规定了事件流包括三个阶段 事件捕获, 处于目标阶段, 事件冒泡阶段,

   2.事件处理程序:  

事件就是用户或者浏览器自身执行的动作, 而事件处理程序就是响应某个事件的函数,

  • HTML事件处理程序

 元素支持的每种事件,都可以使用相应的事件处理程序同名的HTML特性绑定,这个值应该是可以执行的js代码,

      <li class="ppap"><a href="https://www.baidu.com" onclick="console.log('AClick')">adhlasdhl</a></li>
      <li class="ppap"><a href="javascript:void(0)" onclick="handleClick()">adhlasdhl</a></li>

HTML事件处理程序可能存在几个缺点, 1: 用户可能在页面刚加载就触发事件, 而此时事件处理程序没有条件执行 2: 代码与HTML紧密耦合, 试想一下有100个li 每个li都需要一个click事件,突然想改变事件改怎么办?

  • DOM0级事件处理程序 

通过js指定事件处理程序, 将一个函数赋值给一个事件处理程序的属性,删除事件可以给事件处理程序设置为null

 hehe.onclick = function() {
        console.log('hehe');
        hehe.onclick = null;
      };
  • DOM2级事件处理程序

DOM2级定义了两个方法用来 添加或删除事件处理程序,addEventListener 添加 和removeEventListener 移除, 他们都接收3个参数, 参数1: 事件名, 参数2: 作为事件处理程序的函数, 参数3: 捕获阶段(true) or 冒泡阶段(false or 空)

     hehe.addEventListener('click',function(){
       console.log('hehe')
     })

addEventListener 添加事件的主要好处是可以添加多个事件,但只能通过removeEventListener函数移除, 并且被移除的函数只能是外部函数, 不能是匿名函数, 另外说明下 addEventListener 的函数无法传参 hehe.addEventListener('click',fn('xxx')),像这种形式 fn会立即执行, 在不许要移除事件处理程序的情况下可以通过bind方式, 但我们需要移除的情况下,可以使用函数表达式的形式结合bind的方式

      var hehe = document.getElementById('hehe');
      var divClick = document.getElementById('divClick');

      function fn(name) {
        console.log(name);
      }

      var fff = fn.bind(hehe, 'lmxxxxx');
      console.log(fff == fn);// false
      console.log(typeof fff);// function

      /* 
        如果仅仅需要传递参数在并不需要移除的情况下 那么可以使用bind的形式
       */
      hehe.addEventListener('click', fn.bind(hehe,'lmx'));//lmx
      divClick.onclick = function(){
        hehe.removeEventListener('click',fn.bind(hehe,'lmx')); // 无效
      }


      /* 
        如果需要移除 可以使用函数表达式的形式 将绑定fff 并移除fff
       */
       hehe.addEventListener('click', fff);//lmx lmxxxxx
      divClick.onclick = function(){
        hehe.removeEventListener('click',fff); // 移除成功
      }
  • IE事件处理程序

由于ie8及一下,不支持事件捕获, 但有类似于addEventListener的两个方法, attachEvent(增加), detachEvent(删除), 但需要注意的是 attachEvent 参数1 是事件处理程序而不是事件 (onclick 而不是 click) ,而且 参数2 使用匿名函数时 this指向的时window而addEventListener 匿名函数this指向触发事件的元素,另外后添加的事件处理程序先执行(addEventListener 也是)

      var hehe = document.getElementById('hehe');
      var divClick = document.getElementById('divClick');

      function fn(name) {
        console.log('name');
      }

      hehe.attachEvent('onclick',fn)
      divClick.onclick = function(){
        hehe.detachEvent('onclick',fn)
      }

      hehe.attachEvent('onclick',function(){
        console.log(this === window) //true
      })

   3.事件对象:  

在触发DOM上的某个事件的时候,会产生event对象,这个对象包含着所有与事件有关的信息,虽然所有浏览器都支持,但方式不同, 如火狐的事件方法的参数必须传入event ,而chrome 直接在函数体中使用event就可以了

  • DOM的事件对象

无论指定事件的是什么方法, DOM浏览器都会把event对象传入事件处理器中,在事件结束后event对象被销毁,event对象会根据触发事件类型的不同,属性和方法也不同,不过所有事件都会有一些固定属性,和方法

      var divClick = document.getElementById('divClick');
      var uu = document.getElementById('uu');

      divClick.onclick = function(event) {
        //是否冒泡
        console.log(event.bubbles);
        //是否可以取消默认行为
        console.log(event.cancelable);
        //表示是否调用了event.preventDefault()
        console.log(event.defaultPrevented);
        //事件阶段 1捕获 2 目标阶段 3冒泡阶段
        console.log(event.eventPhase);
        //事件的类型
        console.log(event.type); //click
        //正在执行事件的元素
        console.log(event.currentTarget); //divClick
        //触发事件的目标元素
        console.log(event.target); //divClick
        //阻止当前元素的默认事件 如a标签的跳转
        event.preventDefault();
        console.log(event.defaultPrevented); //true
        //阻止事件冒泡 点击divClick后 uu的click不会执行
        event.stopPropagation();
      };

      uu.onclick = function(event) {
        /* 
          当点击uu元素本身的时候触发click时 currentTarget = target 为uu
          但当点击uu内部元素divClick 触发click时 click方法冒泡到了uu
          此时uu执行click事件,event的currentTarget为 uu 而target 为divClick
         */
        console.log(event.currentTarget); //uu
        console.log(event.target); //divClick
      };

      /* 
         event.stopImmediatePropagation();
         不单单会阻止事件冒泡,还会阻止事件分发(在绑定多个click处理器的情况下)
         当执行 event.stopPropagation() 会打印 12 13 14
         当执行 event.stopImmediatePropagation() 会打印 12
       */

      divClick.addEventListener('click', function(event) {
        // event.stopPropagation()
         event.stopImmediatePropagation();
        console.log('12');
      });
      divClick.addEventListener('click', function(event) {
       
        console.log('13');
      });
      divClick.addEventListener('click', function(event) {
        console.log('14');
      });
  •  IE中的事件对象

ie8及一下不支持通过传参的形式,只能通过window.event,event函数稍有不用

      divClick.onclick = function(event){
        var e = event || window.event;
        console.log(e);
        //srcElement 类似target
        console.log(e.srcElement === this);
        // 类似于 preventDefault()
        e.returnValue = false;
        //类似于 stopPropagation()
        e.cancelBubble = true
      }

   4.事件类型:  

浏览器中可能发生的类型有很多种,不同类型具有不同的信息

  • UI事件

UI事件指不一定与用户操作有关,如 load (当页面加载完毕,或者img加载完毕触发) unload(页面卸载,关闭或刷新) abort(页面停止下载) .... 等等

      var divClick = document.getElementById('divClick');
      var uu = document.getElementById('uu');
      //页面加载完成后执行的方法
      window.onload = function(){
        var img = document.createElement('img')
        //图片加载完成
        img.onload = function(){
          console.log(1);
        }
        img.src = './loading.png';
        divClick.appendChild(img);
      }

      //调整浏览器大小后触发
      window.onresize = function(event){
        console.log('resize')
      }

      /* 
        滚动滚动条时触发, 如果存在<!DOCTYPE html> 用documentElement
        如果不存在用body
       */
      window.onscroll = function(event){
        console.log(event.target.body.scrollTop);//0
        console.log(event.target.documentElement.scrollTop);//滚动值
      }
  • 焦点事件

在页面获得焦点或者失去焦点时触发, 也可以通过手动调用 element.focus()触发

      var input = document.getElementById('fouces');

      /* 
       focus与blur不冒泡
       */
      
      input.onfocus = function(){
        console.log('获得焦点')
      }

      input.onblur = function(){
        console.log('失去焦点')
      }

      /* 
        这种方式 浏览器无效
       */
      // input.onfocusin = function(){
      //   console.log('获得焦点')
      // }

      // input.onfocusout = function(){
      //   console.log('失去焦点')
      // }

      /* 
        这种方式可以, 但ie8 不支持需要用兼容写法
       */
      input.addEventListener('focusout',function(){
        console.log('失去焦点')
      })
  • 鼠标与滚轮事件

DOM3级定义了9个鼠标事件,在鼠标事件的event对象中保存了一些关于鼠标的信息

      var hehe = document.getElementById('hehe');
      var divClick = document.getElementById('divClick');
      var uu = document.getElementById('uu');
      var input = document.getElementById('fouces');

      /* 
        鼠标按下
       */
      window.onmousedown = function(event){
        /* 
          clientX 鼠标在视口中位于X轴的坐标 clientY鼠标在视口中位于Y轴的坐标
         */
        console.log(event.clientX);
        console.log(event.clientY);
        /* 
           pageX 鼠标在页面中位于X轴的坐标 pageY鼠标在页面中位于Y轴的坐标
         */
         console.log(event.pageX);
         console.log(event.pageY);

         /* 
          screenX 鼠标在屏幕中位于X轴的坐标 screenY鼠标在屏幕中位于Y轴的坐标
         */
         console.log(event.screenX);
         console.log(event.screenY);
         /* 
          offsetX鼠标在触发元素内部的X轴坐标 offsetY鼠标在触发元素内部的Y轴坐标
          新版火狐已经支持
         */
         console.log(event.offsetX);
         console.log(event.offsetY);

        console.log('鼠标按下')
      }

      /* 
        鼠标抬起
       */
      window.onmouseup = function(){
        console.log('鼠标抬起')
      }

      /* 
        单击事件,
         一次click事件 先触发onmousedown然后onmouseup
         最后onclick
       */
      window.onclick = function(){
        console.log('单击')
      }

      /* 
        双击事件
        一次dbclick 触发两次onmousedown,onmouseup,onclick
        顺序onmousedown,onmouseup,onclick,onmousedown,onmouseup,onclick,ondbclick
       */
      window.ondblclick = function(){
        console.log('双击')
      }

      /* 
        鼠标进入元素触发 不冒泡
       */
       hehe.onmouseenter = function(){
        console.log('鼠标进入元素')
      }
      /* 
        鼠标离开元素触发 不冒泡
       */
       hehe.onmouseleave = function(){
         console.log('鼠标离开一个元素')
       }

       /* 
        鼠标在一个元素上, 在进入另一个元素时触发(包括包含元素),此方法冒泡 
        在鼠标经过后代元素上会频繁触发
       */
       hehe.onmouseover = function(){
         console.log('鼠标在一个元素上')
       }
       /* 
        鼠标在一个元素上, 在离开这个元素时触发(包括包含元素),此方法冒泡 
        在鼠标经过后代元素上会频繁触发
       */
       hehe.onmouseout = function(){
        console.log('鼠标离开一个元素')
       }

       hehe.onmousemove = function(){
         console.log('鼠标在元素上移动')
       }

DOM规定了4个属性, 当某个鼠标事件发生时,用来检测确定用户同时按下了其中某几个键

      hehe.onclick = function(event){
        //是否按下了shift键
        console.log(event.shiftKey)
        //是否按下了ctrl键
        console.log(event.ctrlKey)
        //是否按下了alt
        console.log(event.altKey)
        //是否按下了meta键 window下是windows键
        console.log(event.metaKey)
      }

 触发click事件时event.button 记录了点击的鼠标按钮 0 代表左键 1中间键 2代表又键(最新版都相同), event.detail记录鼠标单击的次数 但各个浏览器都不相同 chrome pc端 会累计相加 模拟phone 恒等于1  ff pc与手机端相同 数字不超过3  ie11 恒等于0

针对onmouseout 与 onmouseover 的event对象中的 relatedTarget属性 , 这个属性 在onmouseout表示 移动到的元素(包括子元素), 在onmouseover表示被离开的元素

      hehe.onmouseover = function(){
         /* 
          onmouseover的relateTarget 表示被离开的元素
         */
        console.log('onmouseover')
        console.log(event.relatedTarget);
      }
      hehe.onmouseout = function(){
        /* 
          onmouseout的relateTarget 表示移动到的元素
         */
        console.log('onmouseout')
        console.log(event.relatedTarget)
      }
  •  键盘与文本事件

用户使用键盘时会触发键盘事件,所有元素都支持三个事件,keydown,keyup,keypress和一个文本事件textInput(ie11,ff不支持),keydown与keypress都是在文本框变化之前触发,keyup在文本框变化之后触发, keydown,keyup,在用户按下键时就触发, 而keypress在用户按下字符键触发包括退格按钮,textInput仅仅在字符键按下触发

keydown,keyup 键码keyCode键码相同 但要是汉字的化 ff, chrome都显示299,ie 按下299 抬起时英文编码, keypress的keyCode, 与keydown,keyup 键码不同, ff中文和英文都恒等于0, ie,chrome中文不显示,英文相同, 而keypress的charCode 与keyCode字符编码相同.

keydown,keyup,keypress的 key属性 否返回按键的字符串如 按下shift 返回''shift.

DOM3级事件中添加了 location属性, 返回1-5数字 0:默认键盘 1:左侧 2右侧 3小键盘 4移动设备 5手柄

  •  变动事件 

在改变DOM结构时 我们可以为元素添加事件 但是兼容性太好 只列出绝大部分浏览器兼容的事件,DOMSubtreeModified(DOM结构改变就触发),DOMNodeInserted(插入节点触发),DOMNodeRemoved(移除或替换触发),可冒泡

      var hehe = document.getElementById('hehe');
      var divClick = document.getElementById('divClick');
      var uu = document.getElementById('uu');
      var input = document.getElementById('fouces');

      uu.addEventListener('DOMSubtreeModified', function() {
        console.log('DOM结构改变了');
      });

      uu.removeChild(uu.children[0])

      uu.addEventListener('DOMNodeInserted',function(){
        console.log('节点插入了')
      })

      hehe.appendChild(input);//未触发

      uu.addEventListener('DOMNodeRemoved',function(){
        console.log('节点移除了')
      })

      hehe.removeChild(input);//未触发
  • H5事件

H5列出了浏览器应该支持的所有事件

contextmenu事件(右键菜单)

      window.oncontextmenu = function(event){
        console.log(1);
        //可以阻止右键弹出菜单
        event.preventDefault()
      }

beforeunload 页面刷新或者关闭页面触发, 此事件内alert confrim等无效,

    /* 
        离开页面或刷新触发 alert等弹窗无效
        返回值 为弹窗显示的值 询问客户的字符串
       */
      window.onbeforeunload = function(event){
        var msg = "确定要离开么";
        return msg;
      }

DOMContentLoaded 事件 不必等到页面完全加载就可以执行,他在DOM树完成后就可以触发,这跟jq $(document).ready()效果是一样的, js标签之所以放在body的结束标签之前 是因为浏览器解析js时会阻断代码 浏览器执行完js后再接着构建html, 所以书中建议css放在头部, 而js代码放在body结束标签之前

      window,addEventListener('DOMContentLoaded',function(){
        console.log('1')
      })

onreadystatechange事件, 早readyState状态改变时 触发事件,readyState有5个状态, uninitialized(未初始化),loading(正在加载) loaded(加载完毕) interactive(可以操作,但是未加载完全) complete(完成)

如果往返缓存中取得页面, 页面时不会再次执行onload事件的, 所以我们可以使用 pageshow(ie11已支持) 和pagehide, pageshow在onload执行之后执行, 只要页面重新恢复或者页面重新加载时就会触发,.pagehide同理但是在unload之前触发,两个事件都有persisted属性, 在pageshow中 如果时从缓存触发的persisted为true 否则false, pagehide 中, 如果页面进入缓存为true 否则false, (pc端测试ff chrome 都是重新加载, 手机端 测试 是从往返缓存)

haschange事件, 只要URL的参数列表变化 就会触发

  • 触摸与手势事件

触摸事件会在手机放在屏幕上面,移动,等触发, touchstart 手指触摸屏幕时触发, touchmove手指在频幕上滑动时触发,会频繁触发, touchend 手指离开屏幕触发, 在移动端touch与click区别, 先触发touchstart -->touchend-->click,click只有在短时间内切并未滑动时触发.

触摸event对象 有额外三个属性 touches(当前屏幕触摸点集合)  targetTouches(绑定事件元素上的触摸点集合) changedTouches(触摸事件改变的元素集合)

手势事件电脑不太方便测 先略

 5.内存和性能:   

在js中事件处理程序的数量, 影响着 页面的整体性能, 每个函数都是对象, 内存中对象越多,性能就越差.

  •  事件委托

针对事件处理程序过多, 可以采用事件委托, 实质就是利用事件冒泡. 用一个事件处理程序,管理某一类所有的事件

      /* 
        可以给父元素绑定事件
        当子元素触发相同事件时 冒泡到父元素
        父元素根据子元素类型 来判断如何执行
       */
      uu.onclick =function(event){
        console.log(event.target)
      }
  • 移除事件处理程序

在删除dom元素后, 事件处理程序极有可能不会被释放 , 可以在删除元素之前, 删除方法

  6.模拟事件:   

  • DOM中的事件模拟

 document.createEvent(),用来创建event对象并返回 ,   这个方法接收一个参数MouseEvent鼠标事件,UIEvent一般ui事件,MutationEvent DOM变动事件 单数为DOM3级事件 复数为DOM2级事件, 模拟事件一般需要三个步骤 创建 --> 注册-->触发,

      document.addEventListener("click",function(){
        console.log(11);
      })


      // 创建事件 参数 为要注册的事件类型
      var msTest = document.createEvent("MutationEvent")
      // 初始化事件  不同类型的事件需要的具体参数也不同 不过前4个参数 基本都需要
      // 事件类型, 是否冒泡, 事件是否可以取消, 视图
      msTest.initMouseEvent('click',true,true,document.defaultView)
      // 触发事件
      document.dispatchEvent(msTest) // 11

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值