1. 程式人生 > 實用技巧 >JS 事件基礎

JS 事件基礎

事件基礎

1.什麼是事件

事件分為兩部分:

  • 行為本身: 瀏覽器天生就賦予其的行為, onclick、onmouseover(onmouseenter)、onmouseout(onmouseleave)、onmousemove、onmousedown、onmouseup、onmousewheel(滑鼠滾輪滾動行為)、onscroll(滾動條滾動行為)、onresize(window.onresize瀏覽器視窗大小改變事件)、onload、onunload(瀏覽器關閉)、onfocus(文字框獲取焦點行為)、onblur(文字框失去焦點)、onkeydown、onkeyup, 哪怕沒有給上述的行為繫結方法, 事件也是存在的,當點選盒子的時候,同樣會觸發它的onclick行為,只是什麼事情都沒做而已。
  • 事件繫結:給元素的某一個行為繫結方法, 當我們觸發事件行為時,會把繫結的函式執行。
element.event = ()=>{}

DOM0級事件繫結

addEventListener

DOM2級事件繫結

element.addEventListener這個屬性是定義在當前元素所屬EventTarget這個類的原型上的

事件物件及相容處理

onclick的e

e: MouseEvent,滑鼠事件物件:
它是一個物件資料型別值,裡面包含了很多的屬性名和屬性值,這些都是用來記錄當前滑鼠的相關資訊的。

原型鏈:
MouseEvnet -> UIEvent -> Event -> Object

MouseEvent記錄的是頁面中唯一一個滑鼠每一次觸發時候的相關資訊,和到底是在那個元素上觸發的沒有關係

屬性值

e.type: 儲存的是當前滑鼠觸發的行為型別“click”

e.clientX / e.clientY: 當前滑鼠觸發點距離當前螢幕左上角的距離

e.taget: 事件源,當前滑鼠觸發的是那個元素,那麼它儲存的就是那個元素,但是在IE6~8中不存在這個屬性(e.tager的值是undefined),我們使用e.srcElement來獲取事件源
e.clientX/clinetY:

e.pageX/pageY:當前滑鼠觸發點距離body左上角(頁面第一螢幕最左上端)的x/y軸的座標,但是在IE6~8中沒有這個屬性,我們通過使用clientY+滾動條捲去的高度來獲取也可以

e.preventDefault: 組織瀏覽器的預設行為

e.currentTarget獲取的是繫結事件的元素, 雖然點選的是ul的子元素li, 但是currentTarget獲取的是ul

關於事件物件MouseEvent的相容問題

事件物件本身的獲取存在相容問題:標準瀏覽器中是瀏覽器給方法傳遞的引數,我們只需要定義形參e就可以獲取到;在IE6-8中瀏覽器不會給方法傳遞引數,我們如果需要的話,需要到window.evnet中查詢

e = e || window.event;

e.target = e.target || e.srcElement;

e.pageX = e.pageX || (e.clientX + (document.documentElement.scrollLeft || document.body.scrollLeft))

e.pageY = e.pageY || (e.clientY + (document.documentElement.scrollTop || document.body.scrollTop))

onkeyup

keyboardEvent:

e.keyCode: 按下的鍵值,當前鍵盤上每一個鍵對應的值

事件的傳播機制

事件的預設傳播機制:

  • 捕獲階段:從外向內依次查詢元素
  • 目標階段:當前事件源本身的操作
  • 冒泡階段:從內到外依次觸發相關的行為

DOM0級事件繫結:
使用DOM0級事件繫結給元素的某一個行為繫結的方法, 都是在冒泡階段執行的

addEventListener繫結:
第一個引數是行為型別,第二個引數是給當前的行為繫結方法,第三個引數是是否在捕獲階段傳送,false在冒泡階段發生

每個瀏覽器傳播的最頂層是不一樣的,谷歌中可以傳播到document,但是在IE中只能傳播到html

事件委託/事件代理

利用事件的冒泡傳播機制,觸發當前元素的某個行為,它父級所有元素的相關行為都會被觸發,如果一個容器中有很多元素都要繫結點選事件,我們沒有必要一個個的繫結,只需要給最外層容器繫結一個點選事件即可,在這個方法執行的時候,通過事件源的區分來進行不同的操作。

document.body.onclick = function (e) {
      e = e || window.event;
      var target = e.target || e.srcElement;
      console.log(target.id);
      if ((target.id = "box")) {
        // ...
      } else if ((target.id = "mark")) {
        // ...
      } else {
        // ...
      }
    };
實現下拉輸入框
<!--
 * @Author: lemon
 * @Date: 2020-09-17 12:45:53
 * @LastEditTime: 2020-09-17 13:27:23
 * @LastEditors: Please set LastEditors
 * @Description: In User Settings Edit
 * @FilePath: \React前端準備\事件\百度搜索框.html
-->
<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Document</title>
    <style type="text/css">
      * {
        margin: 0;
        padding: 0;
        font-family: "微軟雅黑";
      }
      input {
        display: block;
        outline: none;
      }
      a {
        display: block;
        text-decoration: none;
        color: #000;
      }
      a:hover,
      a:active,
      a:target {
        text-decoration: none;
        color: #000;
      }
      ul,
      li {
        list-style: none;
      }
      #box {
        position: absolute;
        top: 20px;
        left: 50%;
        margin-left: -250px;
        width: 500px;
      }
      #box input {
        padding: 0 10px;
        height: 35px;
        border: 1px solid #008000;
      }
      #box ul {
        display: none;
        position: relative;
        top: -1px;
        border: 1px solid #008000;
      }
      #box ul li,
      #box ul li a {
        height: 30px;
        line-height: 30px;
      }
      #box ul li a {
        padding: 0 10px;
      }
      #box ul li a:hover {
        background: #ccc;
      }
    </style>
  </head>
  <body>
    <div id="box">
      <input id="searchInput" type="text" />
      <ul id="searchList">
        <li><a href="javascript:;">lemon</a></li>
        <li><a href="javascript:;">Lemon</a></li>
        <li><a href="javascript:;">檸檬</a></li>
        <li><a href="javascript:;">lemon-Xu</a></li>
        <li><a href="javascript:;">Lemon-Xu</a></li>
      </ul>
    </div>
    <script type="text/javascript">
      var searchInput = document.getElementById("searchInput");
      var searchList = document.getElementById("searchList");
      searchInput.onfocus = searchInput.onkeyup = function (e) {
        var val = this.value.replace(/(^ + | +$)/g, ""); // 獲取文字框的內容並且去除他的首位空格
        searchList.style.display = val.length > 0 ? "block" : "none";
      };
      var box = document.getElementById("box");
      document.onclick = function (e) {
        e = e || window.event;
        e.target = e.target || e.srcElement;
        console.log(searchList.style.display);
        // 如果事件源是#searchList下的a標籤, 我們讓searchList隱藏, 並且把當前點選這個a中的內容放到文字框中
        if (
          e.target.tagName.toLowerCase() === "a" &&
          e.target.parentNode.parentNode.id === "searchList"
        ) {
          searchList.style.display = "none";
          searchInput.value = e.target.innerHTML;
          console.log(searchList.style.display);
          return;
        }
        searchList.style.display = "none";
        console.log(searchList.style.display);
      };
      //   我們可以阻止一個容器中某些特殊性元素, 讓其不在委託的範圍內, 只需要把這些不需要委託的阻止冒泡傳播即可
      searchInput.onclick = function (e) {
        e == e || window.event;
        e.stopPropagation ? e.stopPropagation() : (e.cancelBubble = true);
      };
    </script>
  </body>
</html>