js事件类型

Web浏览器中可以发生很多事件,所发生的事件类型决定了事件对象中会保存什么信息。

DOM3 EventsDOM2 Events基础上重新定义了事件,并增加了新的事件类型。所有主流浏览器都支持这两种。DOM3 Events定义了如下事件类型:用户界面事件,焦点事件,鼠标事件,滚轮事件,输入事件,键盘事件,合成事件

HTML5还定义了另一组事件,而浏览器通常在DOMBOM上实现专有事件,这些专有事件基本上都是根据开发需求而不是规范新增中,因此不同浏览器的实现可能不同。

17.4.1用户界面事件

UIEvent 涉及与BOM交互的通用浏览器事件

1. load事件
  1. window对象上,load事件会在整个页面(图片,js文件,css文件)加载完成后触发,可通过两种方式指定load事件处理程序:

    • JavaScript方式(推荐)
     <script>
        window.addEventListener("load",(event)=>{
          console.log("页面加载完成");
        })
        // 页面加载完成
      </script>
    
    • <body>元素添加onload属性
    <body onload="console.log('页面加载完成')">
    
  2. 图片上也会触发load事件,可直接给<img>元素的onload属性指定事件处理程序。在通过JavaScript创建<img>元素时,也可以给这个元素指定一个加载完成后执行的事件处理程序,关键是要在赋值src属性前指定事件处理程序

     <script>
        window.addEventListener("load",()=>{
          let image = document.createElement("img");
          image.addEventListener("load",(event)=>{
            console.log(event.target.src);
          });
          document.body.appendChild(image);
          image.src="1.gif"
        });
       // http://127.0.0.1:5500/html/1.gif
      </script>
    

    这个例子首先为window指定了一个load事件处理程序,因为涉及向DOM中添加新元素,所以必须确保页面已经加载完成,如果在页面加载完成之前操作document.body,则会导致错误。然后,代码创建了一个新的<img>元素,并为这个元素设置了load事件处理程序,最后,才把这个元素添加到文档中并指定了其src属性。下载图片不一定要把<img>元素添加到文档中,只要给它设置了src属性就会立即开始下载。

  3. <script>元素会在js文件加载完成后触发load事件,从而可以动态检测。与图片不同,下载js文件必须同时指定src属性,并把<script>元素添加到文档中。IE8及更早版本不支持<script>元素触发load事件。

     <script>
        window.addEventListener("load",()=>{
          let script = document.createElement("script");
          script.addEventListener("load",(event)=>{
            console.log("loaded");
          });
          script.src = "example.js"
          document.body.appendChild(script);
        })
       // i am example.js
        // loaded
      </script>
    
2.unload事件
  1. unload事件会在文档卸载完成后触发,一般是在从一个页面导航到另一个页面时触发,最常用于清理引用,以避免内存泄漏。两种按指定方式:

    • js方式
    <script>
        window.addEventListener("unload",(event)=>{
          console.log("unloaded!")
        })
      </script>
    
    • <body>元素添加onload属性
    <body onunload="console.log('unloaded!')">
    

    无论使用何种方式,都要注意事件处理程序中的代码,因为unload事件是在页面卸载完成后触发的,所以不能使用页面加载后才有的对象,此时要访问DOM或修改外观都会导致错误。

3.resize事件
  1. 当浏览器窗口被缩放到新高度或宽度时,会触发resize事件,这个事件在window上触发,因此可以通过jswindow上或者为<body>元素添加onresize属性来指定事件处理程序。优先使用js方式。

    <script>
        window.addEventListener("resize",(event)=>{
          console.log("resized");
        })
      </script>
    
  2. 不同浏览器在决定何时触发resize事件上存在重要差异,IE Safari Chrome Opera会在窗口缩放超过1像素时触发resize事件,然后随着用户缩放窗口不断触发。Firefox早期版本则只在用户停止缩放浏览器窗口时触发resize事件,无论如何,都应该避免这个事件处理程序中执行过多计算,否则可能由于执行过于频繁而导致浏览器响应变慢。

4.scroll事件
  1. 虽然scroll事件发生在window上,但实际反应的是页面中相应元素的变化,在混杂模式下,可以通过<body>元素检测scrollLeft 和 scrollTop属性的变化。在标准模式下,这些变化在除早期版的Safari之外的浏览器中都发生在<html>元素上。(早期版的Safari<body>上跟踪滚动位置)。

        <script>
              window.addEventListener("scroll",(event)=>{
                // 标准模式下
                if(document.compatMode == "CSS1Compat"){
                  console.log(document.documentElement.scrollTop);
                  console.log(event);
                  // 混杂模式下
                }else{
                  console.log(document.body.scrollTop);
                }
              })
      </script>
    

17.4.2焦点事件

  1. 焦点事件在页面元素获得或失去焦点时触发,这些事件可以与document.hasFocus() 和 document.activeElement一起为开发者提供用户在页面中导航的信息。
  2. 分类:
    • focus:当元素获得焦点时触发,不冒泡,所有浏览器都支持。
    • blur:当元素失去焦点时触发,不冒泡,所有浏览器都支持。
    • focusin:当元素获得焦点时触发,冒泡
    • focusout:当元素失去焦点进触发,冒泡

17.4.3鼠标和滚轮事件

鼠标是用户的主要定位设备,DOM3 Events定义了9种鼠标事件:

  • click:在用户单击鼠标主键(通常是左键)或按键盘回车键时触发,这主要是基于无障碍的考虑,让键盘和鼠标都可以触发onclick事件处理程序。
  • dblclick:在用户双击鼠标左键时触发。
  • mousedown:在用户按下任意鼠标键时触发。
  • mouseenter:在用户把鼠标光标从元素外部移到元素内部时触发,不冒泡。
  • mouseleave:在用户把鼠标光标从元素内部移到元素外部时触发,不冒泡。
  • mousemove:在鼠标光标在元素上移动时反复触发。
  • mouseout:在用户把鼠标光标从一个元素移到另一个元素时触发,移到的元素可以是原始元素的外部元素,也可以是原始元素的子元素
  • mouseover:在用户把鼠标光标从元素外部移到元素内部时触发。
  • mouseup:在用户释放鼠标键时触发。
  • mousewheel:鼠标滚轮事件

页面中所有的元素都支持鼠标事件,除了mouseentermouseleave外,所有鼠标事件都会冒泡,都可以被取消,而这会影响浏览器的默认行为。

比如:click事件触发的前提是mousedown事件触发后,紧接着又在同一个元素上触发了mouseup事件,如果mousedownmouseup中的任意一个事件被取消,那么click事件就不会触发了。

1.客户端坐标

鼠标事件都是在浏览器视口中的某个位置上发生的。这些信息被保存在event对象的clientX 、clienY属性中。这两个属性表示事件发生时鼠标光标在视口中的坐标,所有浏览器都支持。

  <div id="myDiv">获取鼠标事件的客户端坐标</div>  <script>    let div = document.getElementById("myDiv");    div.addEventListener("click",(event)=>{      console.log(`client coordinates:${event.clientX},${event.clientY}`);    })  </script>
2.页面坐标

页面坐标是事件发生时鼠标光标在页面上的坐标,通过event对象的pageX、 pageY可以获取,这两个属性表示鼠标光标在页面上的位置,因此反映的是光标到页面而非视口左边与上边的距离。

  <div id="myDiv">获取鼠标事件的页面坐标</div>  <script>    let div = document.getElementById("myDiv");    div.addEventListener("click",(event)=>{      console.log(event.pageX,event.pageY);    })  </script>

在页面没有滚动时,pageX 和pageYclientX 和clientY的值相同。

IE8及更早版本没有在event对象上暴露出页面坐标,不过可以通过客户端坐标和滚动信息计算出页面坐标。滚动信息可以从document.body(混杂模式)document.documentElement(标准模式)scrollLeftscrollTop属性获取。

  <div id="div">获取页面坐标</div>  <script>    let mydiv = document.getElementById("div");    mydiv.addEventListener("click",(event)=>{      let pageX = event.pageX;      let pageY = event.pageY;      if(pageX == undefined){        pageX = clientX + (document.body.scrollLeft || document.documentElement.scrollLeft);      }      if(pageY == undefined){        pageY = clientY + (document.body.scrollTop || document.documentElement.scrollTop);      }      console.log(pageX,pageY);    })  </script>
3.屏幕坐标

通过event对象的screenXscreenY属性获取鼠标光标在屏幕上的坐标。

 <div id="d1">获取屏幕坐标</div>  <script>    let d1 =document.getElementById("d1");    d1.addEventListener("click",(event)=>{      console.log(event.screenX,event.screenY);    })  </script>
4.修饰键
  1. 虽然鼠标事件主要是通过鼠标触发的,但有时候要确定用户想实现的操作,还要考虑键盘按键的状态。键盘上的修饰键shift 、 Ctrl 、 Alt 、 Meta经常用于修改鼠标事件的行为。DOM中规定了4个属性来表示这几个修改键的状态:shiftKey 、ctrlKey、 altKey、 metaKey。这几个会在各自对应的修改键被按下时包含布尔值true,没有被按下时包含布尔值false。在鼠标事件发生时可以通过这几个属性来检测修改键是否被按下。

     <div id="d2">测试修饰键</div>  <script>    let d2 =document.getElementById("d2");    d2.addEventListener("click",(event)=>{      let keys = [];      if(event.shiftKey){        keys.push("shift");      }      if(event.ctrlKey){        keys.push("ctrl");      }      if(event.altKey){        keys.push("alt");      }      if(event.metaKey){        keys.push("meta");      }      console.log(keys.join());    })  </script>
    

    注:

    在 Mac 系统键盘上,meta 对应command 键 (⌘)。

    在 Windows 系统键盘 meta 对应 Windows 徽标键 (⊞)。

    在 Sun 操作系统键盘上,meta 对应实心宝石键 (◆)。

5.相关元素

mouseovermouseout事件而言,还存在与事件相关的其它元素。这两个事件都涉及从一个元素的边界之内把光标移到另一个元素的边界之内。DOM通过event对象的relatedTarget属性提供了相关元素的信息。若是除mouseovermouseout外的其它事件,这个属性的值都是null

  <div id="blue" style="background-color: blue;width: 200px; height: 200px; position: relative;">    <div id="red" style="background-color: red;  margin-top: -50px; margin-left: -50px; width: 100px; height: 100px; left: 50%; top:50%; position: absolute;"></div>  </div>  <script>    let blueDiv = document.getElementById("blue");    blueDiv.addEventListener("mouseover",(event)=>{      console.log(111);      console.log(event.relatedTarget);      console.log(222);    })  </script>
6.鼠标按键

mousedownmouseup事件来说,event对象上会有一个button属性,表示按下或释放的是哪个按键。DOM为这个button属性定义了3个值:0代表鼠标主键,1表示鼠标中键(通常也是滚轮键),2表示鼠标副键。

 <div id="d3">鼠标按键</div>  <script>    let d3 = document.getElementById("d3");    d3.addEventListener("mousedown",(event)=>{      console.log(event.button);    })  </script>
7.额外事件信息

DOM2 Events规范在event对象上提供了detail属性,以给出关于事件的更多信息。对鼠标事件来说,detail包含一个数值,表示在给定位置上发生了多少次点击。单击相当于在同一个像素上发生一次mousedown紧跟一次mouseup。detail的值从1开始,每次单击会加1,如果鼠标在mousedownmouseup之间移动了,则detail会重置为0

  <div id="d4">额外事件信息</div>  <div id="d5">额外事件信息2</div>  <script>    // 鼠标按下并抬起之后才会打印出event.detail    let d4 = document.getElementById("d4");    d4.addEventListener("click",(event)=>{      console.log(event.detail);    });    // 鼠标按下之后即打印出event.detail    let d5 = document.getElementById("d5");    d5.addEventListener("mousedown",(event)=>{      console.log(event.detail);    })  </script>
8.mousewheel事件

mousewheel事件会在用户使用鼠标滚轮时触发,包括在垂直方向上任意滚动。这个事件会在任何元素上触发,并冒泡到window上,mousewheel事件的event对象包含鼠标事件的所有标准信息,此外还有一个名为wheelDelta的新属性。当鼠标滚轮向前时,wheelDelta每次都是+120;当鼠标滚轮向后时,wheelDelta每次都是-120

可以为页面上的任何元素可文档添加onmousewheel事件处理程序,以处理所有鼠标滚轮交互。

  <script>    // 书上说每次滚动±120,目前自测是±150    document.addEventListener("mousewheel",(event)=>{      console.log(event.wheelDelta);    })  </script>
9.触摸屏设备

在为IOSAndroid等触摸屏开发时需注意:

  1. 不支持dblclick事件,双击浏览器窗口可以放大,但没有办法覆盖这个行为。
  2. 单指点触屏幕上的可点击元素会触发mousemove事件,如果操作会导致内容变化,则不会再触发其它事件。如果屏幕上没有变化,则会相继触发mousedown、mouseup 、click事件,点触不可点击的元素不会触发事件。
  3. mousemove事件也会触发mouseovermouseout事件。
  4. 双指点触屏幕并滑动导致页面滚动时会触发mousewheelscroll事件。
10.无障碍问题
  1. 使用click事件执行代码。

17.4.4键盘与输入事件

键盘事件是用户操作键盘时触发的。包含3个事件:

  • keydown:用户按下键盘上某个键时触发,而且持续按住会重复触发
  • keypress:用户释放键盘上某个键时触发。
  • textInput:是对keypress事件的扩展,用于在文本显示给用户之前更方便的截获文本输入。textInput会在文本被插入到文本框之前触发。
1.键码

对于keydownkeyup事件,event对象的keyCode属性中保存一个键码,对应键盘上特定的一个键。对于 字母和数字键,keyCode的值与小写字母和数字的ASCII编码一致。而且跟是否按了shift键无关。

 <input type="text" name="" id="myText">  <script>    let textbox = document.getElementById("myText");    textbox.addEventListener("keyup",(event)=>{      console.log(event.keyCode);    })  </script>
2.textInput事件

DOM3 Events规范新增textInput事件,其在字符被输入到可编辑区域时触发。

keypress的区别:

  • keypress会在任何可以获得焦点的元素上触发,而textIput只在可编辑区域触发。
  • keypress对任何可能影响文本的键都会触发,而textInput只有在新字符被插入时才会触发。

因为textInput事件关注字符,所以在event对象上提供了一个data属性,包含要插入的字符。data的值始终是要被插入的字符,因此如果在按S键时没有按shiftdata的值就是s;如果按S键时按shiftdata的值就是S

  <input type="text" name="" id="text">  <script>    let text = document.getElementById("text");    text.addEventListener("textInput",(event)=>{      console.log(event.data);    })  </script>

17.4.5HTML5事件

DOM规范并未涵盖浏览器都支持的所有事件,很多浏览器根据特定的用户需求或使用场景实现了自定义事件,HTML5详尽的列出了浏览器支持的所有事件,以下只是得到浏览器较好支持的一些事件。

1.contextmenu事件
  1. 专门用于表示何时该显示上下文菜单,从而允许开发者取消默认的上下菜单并提供自定义菜单。
  2. contextmenu事件冒泡,因此只要给document指定一个事件处理程序就可以处理页面上的所有同类事件。事件目标是触发操作的元素。这个事件在所有浏览器中都可以取消,在DOM合规的浏览器中使用event.preventDefault()
  3. contextmenu事件应该算是一种鼠标事件,因此event对象上的很多属性都与光标位置有关。通常,自定义的上下文菜单都是通过这个事件处理程序来触发的显示,并通过onclick事件处理程序触发隐藏的。
  <div id="myDiv">Right click</div>  <ul id="myMenu" style="position: absolute; visibility: hidden; background-color: antiquewhite;">    <li><a href="http://www.baidu.com">百度</a></li>    <li><a href="http://www.baidu.com">百度</a></li>    <li><a href="http://www.baidu.com">百度</a></li>  </ul>  <script>    window.addEventListener("load", (event) => {      let div = document.getElementById("myDiv");      div.addEventListener("contextmenu", (event) => {        // 阻止默认事件        event.preventDefault();        let menu = document.getElementById("myMenu");        menu.style.left = event.clientX + "px";        menu.style.top = event.clientY + "px";        menu.style.visibility = "visible";      })      document.addEventListener("click", (event) => {        document.getElementById("myMenu").style.visibility = "hidden";      })    })  </script>

这里在<div>元素上指定了一个contextmenu事件处理程序,这个事件处理程序先取消默认行为,确保不会显示浏览器默认的上下文菜单,接着基于event对象的clientX、clientY属性把<ul>元素放在适当的位置。最后一步,通过将visibility属性设置为visible让自定义上下文菜单显示出来。另外,又给document添加了一个onclick事件处理程序,以便在单击事件发生时隐藏上下文菜单。

2.beforeunload事件

beforeunload事件会在window上触发,用意是给开发者提供阻止页面被卸载的机会,这个事件会在页面即将从浏览器中卸载时触发,如果页面需要继续使用,则可以不被卸载。这个事件不能取消,否则就意味着可以把用户永久阻拦在一个页面上。相反,这个事件会向用户显示一个确认框,其中的消息表明浏览器即将卸载页面,并请用户确认是希望关闭页面,还是继续留在页面上。

  <script>    window.addEventListener("beforeunload",(event)=>{      let message = "I'm really going to miss you if you go.";      event.returnValue = message;      return message;    })  </script>
3.DOMContentLoaded事件
  1. 此事件会在DOM树构建完成后立即触发,而不用等待图片,js文件 、css文件或其它资源加载完成。相对于load事件,可以让开发者在外部资源下载的同时就能指定事件处理程序,从而让用户能够更快的与页面交互。

  2. 要处理DOMContentLoaded事件,需要给documentwindow添加事件处理程序。

  3. 对于不支持此事件的浏览器,可以使用超时为0的setTimeout()函数,通过其回调来设置事件处理程序。

     <script>    document.addEventListener("DOMContentLoaded",(event)=>{      console.log(event);      console.log("content loaded");    })  </script>
    

    不支持此事件时可以设置定时器。

    <script>    setTimeout(() => {      // 在此处添加事件处理程序      console.log(111);    }, 0);  </script>
    
4.readystatechange事件
  1. 此事件提供文档或元素加载状态的信息,但行为有时候并不稳定,支持此事件的每个对象都有一个readyState属性,该属性具有以下可能的字符串值:

    • uninitialized:对象存在尚未初始化
    • loading:对象正在加载数据
    • loaded:对象已经加载完数据
    • interactive:对象可以交互,但尚未加载完成
    • complete:对象加载完成

    但并非所有对象都会经历readystate阶段,文档中也并未说明哪些阶段适用于哪些对象,这意味着此事件经常触发不到4次,而且readystate未必会依次呈现上述值。

  2. document上使用时,值为interactivereadyState首先会触发此事件,时机类似于DOMContentLoaded,进入交互阶段,意味着DOM树已加载完成,因而可以安全的交互了。

     <script>    document.addEventListener("readystatechange",(event)=>{      if(document.readyState == "interactive"){        console.log("content loaded");      }    })  </script>
    
  3. 交互阶段与完成阶段的顺序也不是固定的。在外部资源较多的页面中,很可能交互阶段早于完成阶段,而在外部资源较少的页面,很可能完成阶段会早于交互阶段。因此实践中为了抢到较早的时机,需要同时检测交互阶段和完成阶段。

      <script>    document.addEventListener("readystatechange",(event)=>{      if(document.readyState == "interactive" || document.readyState == "complete"){        console.log("content loaded");      }    })  </script>
    
5.haschange事件
  1. 用于在url散列值(url最后#后面的部分)发生变化时通知开发者。这是因为开发者经常在AJAX应用程序中使用URL散列值存储状态信息或路由导航信息。

  2. onhaschange事件处理程序必须添加给window,每次URL散列值发生变化时会调用它。event对象有两个新属性:oldURL 和 newURL,这两个属性分别保存变化前后的URL,而且是包含散列值的完整的URL

     <script>    window.addEventListener("hashchange",(event)=>{      console.log(event.oldURL);      console.log(event.newURL);    })    window.addEventListener("hashchange",(event)=>{      console.log(location.hash);    })  </script>
    
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值