進(jìn)階9.事件(學(xué)習(xí)筆記)

事件

JavaScript和HTML的交互是通過(guò)事件實(shí)現(xiàn)的。JavaScript采用異步事件驅(qū)動(dòng)編程模型,當(dāng)文檔、瀏覽器、元素或與之相關(guān)對(duì)象發(fā)生特定事情時(shí),瀏覽器會(huì)產(chǎn)生事件。如果JavaScript關(guān)注特定類型事件,那么它可以注冊(cè)當(dāng)這類事件發(fā)生時(shí)要調(diào)用的句柄

  • 事件是某個(gè)行為或者觸發(fā),比如點(diǎn)擊、鼠標(biāo)移動(dòng)
  • 當(dāng)用戶點(diǎn)擊鼠標(biāo)時(shí)
  • 當(dāng)網(wǎng)頁(yè)已加載時(shí)
  • 當(dāng)圖像已加載時(shí)
  • 當(dāng)鼠標(biāo)移動(dòng)到元素上時(shí)
  • 當(dāng)用戶觸發(fā)按鍵時(shí)...

事件無(wú)處不在,在javascript中,我們?nèi)绾稳ビ^察事件呢?

事件流

事件流描述的是從頁(yè)面中接收事件的順序,比如有兩個(gè)嵌套的div,點(diǎn)擊了內(nèi)層的div,這時(shí)候是內(nèi)層的div先觸發(fā)click事件還是外層先觸發(fā)?


舉例

說(shuō)明: 例如這里的button,我點(diǎn)擊的時(shí)候,是先觸發(fā)'wrap',還是先觸發(fā)button

目前主要有三種模型

  1. IE的事件冒泡:事件開始時(shí)由最具體的元素接收,然后逐級(jí)向上傳播到較為不具體的元素
冒泡實(shí)例
  1. 事件捕獲:不太具體的節(jié)點(diǎn)更早接收事件,而最具體的元素最后接收事件,和事件冒泡相反

  2. DOM事件流:DOM2級(jí)事件規(guī)定事件流包括三個(gè)階段,事件捕獲階段,處于目標(biāo)階段(到達(dá)目標(biāo)的那個(gè)事件),事件冒泡階段,首先發(fā)生的是事件捕獲,為截取事件提供機(jī)會(huì),然后是實(shí)際目標(biāo)接收事件,最后是冒泡階段

這種分歧在日常生活中也很常見,舉個(gè)例子,某個(gè)地方出了搶劫事件,我們有多種處理方式

  1. 村里先發(fā)現(xiàn),報(bào)告給鄉(xiāng)里,鄉(xiāng)里報(bào)告到縣城,縣城報(bào)告給市里。。。。
  2. 市里先知道這事兒,然后交代給縣城怎么處理,縣城交給到鄉(xiāng)里處理,鄉(xiāng)里交給村里處理

Opera、Firefox、Chrome、Safari都支持DOM事件流,IE不支持事件流,只支持事件冒泡

如有以下html

<!DOCTYPE html >
<html>
<head>
    <meta http-equiv="Content-type" content="text/html; charset=utf-8" />
    <title>Test Page</title>
</head>
<body>
    <div>·Click Here</div>
</body>
</html>

點(diǎn)擊div區(qū)域

事件冒泡模型 事件捕獲模型 DOM事件流

事件處理程序

我們也稱之為事件偵聽器(listener),事件就是用戶或?yàn)g覽器自身執(zhí)行的某種動(dòng)作。比如click、load、mouseover等,都是事件類型(俗稱事件名稱),而響應(yīng)某個(gè)事件的方法就叫做事件處理程序或者事件監(jiān)聽器

也就是我們需要提前定義好某些事件發(fā)生了該怎么處理,這個(gè)過(guò)程叫做綁定事件處理程序,了解了這些,我們看看如何給元素添加事件處理程序

HTML內(nèi)聯(lián)方式

元素支持的每個(gè)事件都可以使用一個(gè)相應(yīng)事件處理程序同名的HTML屬性指定。這個(gè)屬性的值應(yīng)該是可以執(zhí)行的JavaScript代碼,我們可以為一個(gè)button添加click事件處理程序(這種方式在早期使用,因?yàn)檫€沒有樣式與操作分離的概念)

<input type="button" value="Click Here" onclick="alert('Clicked!');" />

內(nèi)聯(lián)寫法舉例

內(nèi)聯(lián)寫法舉例

在HTML事件處理程序中可以包含要執(zhí)行的具體動(dòng)作,也可以調(diào)用在頁(yè)面其它地方定義的腳本,剛才的例子可以寫成這樣

<input type="button" value="Click Here" onclick="showMessage();" />

在HTML中指定事件處理程序書寫很方便,但是有兩個(gè)缺點(diǎn)。

  1. 存在加載順序問題,如果事件處理程序在html代碼之后加載,用戶可能在事件處理程序還未加載完成時(shí)就點(diǎn)擊按鈕之類的觸發(fā)事件,存在時(shí)間差問題

  2. 這樣書寫html代碼和JavaScript代碼緊密耦合,維護(hù)不方便

JavaScript指定事件處理程序

通過(guò)JavaScript指定事件處理程序就是把一個(gè)方法賦值給一個(gè)元素的事件處理程序?qū)傩浴?/p>

每個(gè)元素都有自己的事件處理程序?qū)傩?,這些屬性名稱通常為小寫,如onclick等,將這些屬性的值設(shè)置為一個(gè)函數(shù),就可以指定事件處理程序,如下

<input id="btnClick" type="button" value="Click Here" />

<script type="text/javascript">
    var btnClick = document.getElementById('btnClick');
    btnClick.onclick = function showMessage() {
        alert(this.id);
    };
</script>

javascript指定事件處理程序

這樣處理,事件處理程序被認(rèn)為是元素的方法,事件處理程序在元素的作用域下運(yùn)行,this就是當(dāng)前元素,所以點(diǎn)擊button結(jié)果是:btnClick

這樣還有一個(gè)好處,我們可以刪除事件處理程序,只需把元素的onclick屬性賦為null即可

DOM2事件處理程序

DOM2級(jí)事件定義了兩個(gè)方法用于處理指定和刪除事件處理程序的操作:

  1. addEventListener
  2. removeEventListener

所有的DOM節(jié)點(diǎn)都包含這兩個(gè)方法,并且它們都接受三個(gè)參數(shù):

  1. 事件類型
  2. 事件處理方法
  3. 布爾參數(shù),如果是true表示在捕獲階段調(diào)用事件處理程序,如果是false,則是在事件冒泡階段處理

剛才的例子我們可以這樣寫

<input id="btnClick" type="button" value="Click Here" />

<script type="text/javascript">
    var btnClick = document.getElementById('btnClick');
    btnClick.addEventListener('click', function() {
        alert(this.id);
    }, false);
</script>

兩種事件綁定方法對(duì)比

上面代碼為button添加了click事件的處理程序,在冒泡階段觸發(fā),與上一種方法一樣,這個(gè)程序也是在元素的作用域下運(yùn)行,不過(guò)有一個(gè)好處,我們可以為click事件添加多個(gè)處理程序

<input id="btnClick" type="button" value="Click Here" />

<script type="text/javascript">
    var btnClick = document.getElementById('btnClick');

    btnClick.addEventListener('click', function() {
        alert(this.id);
    }, false);

    btnClick.addEventListener('click', function() {
        alert('Hello!');
    }, false);
</script>

這樣兩個(gè)事件處理程序會(huì)在用戶點(diǎn)擊button后按照添加順序依次執(zhí)行。

通過(guò)addEventListener添加的事件處理程序只能通過(guò)removeEventListener移除,移除時(shí)參數(shù)與添加的時(shí)候相同,這就意味著剛才我們添加的匿名函數(shù)無(wú)法移除,因?yàn)槟涿瘮?shù)雖然方法體一樣,但是句柄卻不相同,所以當(dāng)我們有移除事件處理程序的時(shí)候可以這樣寫

<input id="btnClick" type="button" value="Click Here" />

<script type="text/javascript">
    var btnClick = document.getElementById('btnClick');

    var handler=function() {
        alert(this.id);
    }

    btnClick.addEventListener('click', handler, false);
    btnClick.removeEventListener('click', handler, false);
</script>

事件冒泡

<style>
    .container,
    .box,
    .target{
      border: 1px solid;
      padding: 10px;
    }  
  </style>
  <button id="btn">click</button>

  <div class="container">
    container
    <div class="box">
      box
      <div class="target">target</div>
    </div>
  </div>

  <script>

  function $(selector){
    return document.querySelector(selector)
  }

  var btn = $('#btn')
  btn.onclick = function (e){
   console.log(e) 
  }
  btn.addEventListener('click', function(evt){
    console.log(this)
    console.log(btn)
    console.log(evt.target)
  })

  $('.container').addEventListener('click', function(e){
    console.log('contianer click.. in 捕獲階段')
  }, true)
  $('.box').addEventListener('click', function(e){
    //e.stopPropagation()
    console.log('box click.. in 捕獲階段')
  }, true)
  $('.target').addEventListener('click', function(e){
    console.log('target click.. in 捕獲階段')
  }, true)

  $('.container').addEventListener('click', function(e){
    console.log('contianer click.. in 冒泡階段')
  }, false)
  $('.box').addEventListener('click', function(e){
    //e.stopPropagation()
    console.log('box click.. in 冒泡階段')
  }, false)
  $('.target').addEventListener('click', function(e){
    console.log('target click.. in 冒泡階段')
  }, false)    

  </script>

冒泡階段執(zhí)行事件程序
捕獲階段執(zhí)行事件程序

通過(guò)this得知監(jiān)聽的元素

this

阻止默認(rèn)事件

<a >baidu</a>
<script>
  document.querySelector('a').onclick= function(e){
    e.preventDefault()
    console.log(this.href)
    if(/baidu.com/.test(this.href)){
      location.href = this.href
    }
  }
</script>

<form action="/login">
    <input type="text" name="username">
    <input type="submit">
</form>
<script>
    document.querySelector('form').addEventListener('submit', function(evt){
        evt.preventDefault()
        if(document.querySelector('input[name=username]').value === 'jirengu'){
            this.submit()
        }
    })
</script>

事件代理

  <div class="container">
    <div class="box">box1</div>
    <div class="box">box2</div>
    <div class="box">box3</div>
  </div>
  <button id="add">add</button>

<script>
function $(selector){
  return document.querySelector(selector)
}
function $$(selector){
  return document.querySelectorAll(selector)
}

// $$('.box').forEach(function(node){
//   node.onclick = function(){
//     console.log(this.innerText)
//   }
// })

$('.container').onclick = function(e){
  console.log(this)  
  console.log(e.target)
  if(e.target.classList.contains('box')){
    console.log(e.target.innerText)
  }
}

var i = 4
$('#add').onclick = function(){
  var box = document.createElement('div')
  box.classList.add('box')
  box.innerText = 'box' + (i++)
  $('.container').appendChild(box)
}

事件代理實(shí)例

具體需求

具體需求:
1.點(diǎn)擊列表時(shí),在div中展示點(diǎn)擊的欄目的內(nèi)容
2.輸入框輸入信息后,點(diǎn)擊添加,新生成一個(gè)li添加到列表中
3.點(diǎn)擊新添加的li,也能在下方div中展示其中的內(nèi)容

1.點(diǎn)擊li,展示內(nèi)容

第一步

2.添加li
第二步

但此時(shí)點(diǎn)擊新增的li,并不會(huì)展示在下面的div中。因?yàn)榇a自上而下執(zhí)行,前面我們通過(guò)forEach對(duì)已有的元素進(jìn)行了事件綁定,但新增的元素并沒有進(jìn)行事件綁定,所以點(diǎn)擊新增元素?zé)o法展示內(nèi)容。
對(duì)新增元素再次進(jìn)行綁定

雖然實(shí)現(xiàn)了需求,但這里有不合理的地方,有時(shí)我們需要從數(shù)據(jù)庫(kù)獲取許多內(nèi)容,然后將這些內(nèi)容拼接成html,作為新欄目放置在頁(yè)面上,這時(shí),對(duì)于這些新增的元素,如果要實(shí)現(xiàn)一些功能,但上面的寫法就要一一對(duì)元素進(jìn)行事件綁定,這樣很麻煩。這時(shí),我們可以使用事件代理實(shí)現(xiàn)功能。
3.可顯示新增li內(nèi)容
第三步

事件代理,將事件綁定到父元素后,代碼量少了許多
bug
存在問題

這樣還是有一個(gè)問題,當(dāng)li較小時(shí),我們點(diǎn)擊到了ul,但這里還是會(huì)打印出所有的內(nèi)容,這是需要對(duì)點(diǎn)擊的地方做一個(gè)判斷
改進(jìn)

IE兼容性


說(shuō)明:對(duì)于attachEvent,在它的回調(diào)函數(shù)中想要知道監(jiān)聽的事件,可通過(guò)window.event獲取



跨瀏覽器的事件處理程序

前面內(nèi)容我們可以看到,在不同的瀏覽器下,添加和移除事件處理程序方式不相同,要想寫出跨瀏覽器的事件處理程序,首先我們要了解不同的瀏覽器下處理事件處理程序的區(qū)別

在添加事件處理程序事addEventListener和attachEvent主要有幾個(gè)區(qū)別

  1. 參數(shù)個(gè)數(shù)不相同,這個(gè)最直觀,addEventListener有三個(gè)參數(shù),attachEvent只有兩個(gè),attachEvent添加的事件處理程序只能發(fā)生在冒泡階段,addEventListener第三個(gè)參數(shù)可以決定添加的事件處理程序是在捕獲階段還是冒泡階段處理(我們一般為了瀏覽器兼容性都設(shè)置為冒泡階段)

  2. 第一個(gè)參數(shù)意義不同,addEventListener第一個(gè)參數(shù)是事件類型(比如click,load),而attachEvent第一個(gè)參數(shù)指明的是事件處理函數(shù)名稱(onclick,onload)

  3. 事件處理程序的作用域不相同,addEventListener的作用域是元素本身,this是指的觸發(fā)元素,而attachEvent事件處理程序會(huì)在全局變量?jī)?nèi)運(yùn)行,this是window,所以剛才例子才會(huì)返回undefined,而不是元素id

    IE中舉例

    說(shuō)明:也就是說(shuō),當(dāng)我們?cè)贗E中寫的時(shí)候,這里的this是window,而不是box

  1. 為一個(gè)事件添加多個(gè)事件處理程序時(shí),執(zhí)行順序不同,addEventListener添加會(huì)按照添加順序執(zhí)行,而attachEvent添加多個(gè)事件處理程序時(shí)順序無(wú)規(guī)律(添加的方法少的時(shí)候大多是按添加順序的反順序執(zhí)行的,但是添加的多了就無(wú)規(guī)律了),所以添加多個(gè)的時(shí)候,不依賴執(zhí)行順序的還好,若是依賴于函數(shù)執(zhí)行順序,最好自己處理,不要指望瀏覽器

了解了這四點(diǎn)區(qū)別后我們可以嘗試寫一個(gè)瀏覽器兼容性比較好的添加事件處理程序方法(也就是說(shuō),我們要對(duì)事件進(jìn)行封裝)

//將兩種寫法融合到一個(gè)函數(shù)里面,也就是實(shí)現(xiàn)封裝
function addEvent(node, type, handler) {
    if (!node) return false;
    if (node.addEventListener) {
        node.addEventListener(type, handler, false);
        return true;
    }
    else if (node.attachEvent) {
        node.attachEvent('on' + type, handler, ); //在IE中,事件要加上on
        return true;
    }
    return false;
}

這樣,首先我們解決了第一個(gè)問題參數(shù)個(gè)數(shù)不同,現(xiàn)在三個(gè)參數(shù),采用事件冒泡階段觸發(fā)

第二個(gè)問題也得以解決,如果是IE,我們給type添加上on

第四個(gè)問題目前還沒有解決方案,需要用戶自己注意,一般情況下,大家也不會(huì)添加很多事件處理程序

試試這個(gè)方法感覺很不錯(cuò),但是我們沒有解決第三個(gè)問題,由于處理程序作用域不同,如果handler內(nèi)有this之類操作,那么就會(huì)出錯(cuò)。在IE下,實(shí)際上大多數(shù)函數(shù)都會(huì)有this操作

function addEvent(node, type, handler) {
    if (!node) return false;
    if (node.addEventListener) {  //此處實(shí)際是在進(jìn)行能力檢測(cè),也就是說(shuō),我不看
                                  //你到底是哪個(gè)瀏覽器,能不能用這個(gè)功能,我直接看你是否具有這項(xiàng)能力    
        node.addEventListener(type, handler, false);
        return true;
    }
    else if (node.attachEvent) {
        node.attachEvent('on' + type, function() { handler.apply(node); });
        return true;
    }
    return false;
}

這樣處理就可以解決this的問題了,但是新的問題又來(lái)了,我們這樣等于添加了一個(gè)匿名的事件處理程序,無(wú)法用detachEvent取消事件處理程序,有很多解決方案,我們可以借鑒大師的處理方式,jQuery創(chuàng)始人John Resig是這樣做的

function addEvent(node, type, handler) {
    if (!node) return false;
    if (node.addEventListener) {
        node.addEventListener(type, handler, false);
        return true;
    }
    else if (node.attachEvent) {
        node['e' + type + handler] = handler;
        node[type + handler] = function() {
            node['e' + type + handler](window.event);
        };
        node.attachEvent('on' + type, node[type + handler]);
        return true;
    }
    return false;
}

理解上述代碼

說(shuō)明:這里相對(duì)上面添加的代碼,功能上就是為了實(shí)現(xiàn)在console.log(this)的時(shí)候,打印出來(lái)的還是響應(yīng)時(shí)間的節(jié)點(diǎn)

在取消事件處理程序的時(shí)候

function removeEvent(node, type, handler) {
    if (!node) return false;
    if (node.removeEventListener) {
        node.removeEventListener(type, handler, false);
        return true;
    }
    else if (node.detachEvent) {
        node.detachEvent('on' + type, node[type + handler]);
        node[type + handler] = null;
    }
    return false;
}

John Resig很巧妙地利用了閉包,看起來(lái)很不錯(cuò)。

事件對(duì)象

在觸發(fā)DOM上的某個(gè)事件的時(shí)候會(huì)產(chǎn)生一個(gè)事件對(duì)象event,這個(gè)對(duì)象包含著所有與事件有關(guān)的信息,包括產(chǎn)生事件的元素、事件類型等相關(guān)信息。所有瀏覽器都支持event對(duì)象,但支持方式不同。

DOM中的事件對(duì)象

兼容DOM的瀏覽器會(huì)產(chǎn)生一個(gè)event對(duì)象傳入事件處理程序中。應(yīng)用一下剛才我們寫的addEvent方法

var btnClick = document.getElementById('btnClick');
  addEvent(btnClick, 'click', handler);

點(diǎn)擊button的時(shí)候我們可以看到彈出內(nèi)容是click的彈窗

event對(duì)象包含與創(chuàng)建它的特定事件有關(guān)的屬性和方法,觸發(fā)事件的類型不同,可用的屬性和方法也不同,但是所有事件都會(huì)包含

屬性/方法 類型 讀/寫 說(shuō)明
bubbles Boolean 只讀 事件是否冒泡
cancelable Boolean 只讀 是否可以取消事件的默認(rèn)行為
currentTarget Element 只讀 事件處理程序當(dāng)前處理元素
detail Integer 只讀 與事件相關(guān)細(xì)節(jié)信息
eventPhase Integer 只讀 事件處理程序階段:1 捕獲階段,2 處于目標(biāo)階段,3 冒泡階段
preventDefault() Function 只讀 取消事件默認(rèn)行為
stopPropagation() Function 只讀 取消事件進(jìn)一步捕獲或冒泡
target Element 只讀 事件的目標(biāo)元素
type String 只讀 被觸發(fā)的事件類型
view AbstractView 只讀 與事件關(guān)聯(lián)的抽象視圖,等同于發(fā)生事件的window對(duì)象
事件對(duì)象屬性

在事件處理程序內(nèi)部,this始終等同于currentTarget,而target是事件的實(shí)際目標(biāo)。

重要概念,取消事件冒泡,取消默認(rèn)事件

取消事件冒泡

說(shuō)明:這樣做有什么意義呢?當(dāng)我們做一個(gè)模態(tài)框的效果時(shí),點(diǎn)擊模態(tài)框本身,框不消失,點(diǎn)擊頁(yè)面其他地方,框消失,需要用到這個(gè)方法。如果我們不對(duì)這個(gè)click的時(shí)間進(jìn)行阻止,那么我們點(diǎn)擊任何位置都會(huì)將這個(gè)事件傳播到body上,點(diǎn)擊頁(yè)面和點(diǎn)擊模態(tài)框就沒了區(qū)別。

要阻止事件的默認(rèn)行為,可以使用preventDefault()方法,前提是cancelable值為true,比如我們可以阻止鏈接導(dǎo)航這一默認(rèn)行為

document.querySelector('#btn').onclick = function (e) {
    e.preventDefault();
}

阻止默認(rèn)事件實(shí)例

stopPropagation()方法可以停止事件在DOM層次的傳播,即取消進(jìn)一步的事件捕獲或冒泡。我們可以在button的事件處理程序中調(diào)用stopPropagation()從而避免注冊(cè)在body上的事件發(fā)生

var handler = function (e) {
    alert(e.type);
    e.stopPropagation();
}

addEvent(document.body, 'click', function () { alert('Clicked body')});
var btnClick = document.getElementById('btnClick');
addEvent(btnClick, 'click', handler);

若是注釋掉e.stopPropagation(); 在點(diǎn)擊button的時(shí)候,由于事件冒泡,body的click事件也會(huì)觸發(fā),但是調(diào)用這句后,事件會(huì)停止傳播

IE中的事件對(duì)象

訪問IE中的event對(duì)象有幾種不同的方式,取決于指定事件處理程序的方法。直接為DOM元素添加事件處理程序時(shí),event對(duì)象作為window對(duì)象的一個(gè)屬性存在。(在DOM2中,回調(diào)函數(shù)傳入的參數(shù)直接就是監(jiān)聽的事件,直接就能拿來(lái)用)

var handler = function () {
    var e = window.event;
    alert(e.type);
}
var btnClick = document.getElementById('btnClick');
btnClick.onclick = handler;

我們通過(guò)window.event取得了event對(duì)象,并檢測(cè)到了其類型,可是如果事件處理程序是通過(guò)attachEvent添加的,那么就會(huì)有一個(gè)event對(duì)象被傳入事件處理程序中

var handler = function (e) {
    alert(e.type);
}
var btnClick = document.getElementById('btnClick');
attachEvent(btnClick, handler);

當(dāng)然這時(shí)候也可以通過(guò)window對(duì)象訪問event,方便起見,我們一般會(huì)傳入event對(duì)象,IE中所有的事件都包含以下屬性方法

屬性/方法 類型 讀/寫 說(shuō)明
cancelBubble Boolean 讀/寫 默認(rèn)為false,設(shè)置為true后可以取消事件冒泡
returnValue Boolean 讀/寫 默認(rèn)為true,設(shè)為false可以取消事件默認(rèn)行為
srcElement Element 只讀 事件的目標(biāo)元素
type String 只讀 被觸發(fā)的事件類型

封裝實(shí)現(xiàn)選擇器

封裝選擇器

通過(guò)封裝簡(jiǎn)化寫法
簡(jiǎn)化querySelector

跨瀏覽器的事件對(duì)象

雖然DOM和IE的event對(duì)象不同,但基于它們的相似性,我們還是可以寫出跨瀏覽器的事件對(duì)象方案

function getEvent(e) {
    return e || window.event;
}

function getTarget(e) {
    return e.target || e.scrElement;
}

function preventDefault(e) {
    if (e.preventDefault)
        e.preventDefault();
    else
        e.returnValue = false;
}

function stopPropagation(e) {
    if (e.stopPropagation)
        e.stopPropagation();
    else
        e.cancelBubble = true;
}

常用HTML事件


  <button id="btn">點(diǎn)我</button>
  <button id="btn1">點(diǎn)我1</button>
  <div class="ct" style="font-size: 20px">
    <div class="box">hello</div>
  </div>    

  <div class="ct1">
    <div class="box1"></div>
  </div>  
  <input id="input-name" type="text">

  <form id="form" action="/upload">
    <input  id="username" name="username" type="text">
    <p class="msg"></p>
    <input id="btn-submit" type="submit" value="注冊(cè)">
  </form>

    <img src="https://jirengu.com/data/upload/2017/0118/17/587f39fba695a.png" alt="">

  <script>

  function $(selector){
    return document.querySelector(selector);
  }

  $('#btn').addEventListener('click', function(){
    console.log('click')
    console.log(this)
  })
  $('#btn1').addEventListener('dblclick', function(){
    console.log('dblclick')
    console.log(this)
  })

  $('.ct').addEventListener('mouseover', function(){
    console.log('mouseover')
    console.log(this)
    // this.style.borderColor = 'blue'

    this.classList.add('hover')
  })
  $('.ct').addEventListener('mouseout', function(){
    console.log('mouseout...')
    // this.style.borderColor = 'red'
    this.classList.remove('hover')
  })

  $('.ct1').addEventListener('mouseenter', function(){
    console.log('mouseenter...')
    //this.style.borderColor = 'blue'
    this.classList.add('hover')
  })
  $('.ct1').addEventListener('mouseleave', function(){
    console.log('mouseleave...')
    //this.style.borderColor = 'blue'
    this.classList.remove('hover')
  })

   $('#input-name').addEventListener('focus', function(){
     console.log('focus...')
     console.log(this.value)
   })
   $('#input-name').addEventListener('blur', function(){
     console.log('blur...')
     console.log(this.value)
   })

   $('#input-name').addEventListener('keyup', function(e){
     console.log('keyup...')
     console.log(this.value)
     console.log(e)
     this.value = this.value.toUpperCase()
   })

   $('#input-name').addEventListener('change', function(e){
     console.log('change...')
     console.log(this.value)
     console.log(e)
     this.value = this.value.toUpperCase()
   })

  $('#form').addEventListener('submit', function(e){
    e.preventDefault();
    if(/^\w{6,12}$/.test($('#username').value)){
      $('#form').submit();
    }else{
      $('#form .msg').innerText = '出錯(cuò)了'
      $('#form .msg').style.display = 'block'
      console.log(' no submit...');
    } 
  })

  window.addEventListener('scroll', function(e){
    console.log('scroll..')
  })
  window.addEventListener('resize', function(e){
    console.log('resize..')
  })

  //頁(yè)面所有資源加載完成
  window.onload = function(){
    console.log('window loaded')
  }

  //DOM 結(jié)構(gòu)解析完成
  document.addEventListener('DOMContentLoaded', function(){
    console.log('DOMContentLoaded ')
  })

    console.log($('img').width) //0
    $('img').onload = function(){
        console.log(this.width)   //此時(shí)才能得到圖片的真實(shí)大小
    }

  </script>
  <style>
  body{
    color: blue;
  }
  .ct,.ct1{
    width: 100px;
    height: 100px;
    border: 1px solid red;
    background-color: yellow;
    margin: 20px;
  }
  .box,.box1{
    width: 50px;
    height: 50px;
    background-color: blue;
  }
  .ct.hover, .ct1.hover{
    border-color: blue;
    background-color: pink;
  }

  .box3{
    list-style: none;
    background: yellow;
    margin: 0;
    padding: 0;
  }
  .box3>li{
    background: pink;
    margin: 5px;
    padding: 10px;
  }
  .box3>li.hover{
    background-color: blue;
  }
  .msg{
    display: none;
  }

  </style>

鼠標(biāo)事件

onmousedown, onmouseup, onclick, ondbclick, onmousewheel, onmousemove, onmouseover, onmouseout

相關(guān)細(xì)節(jié)

  • 對(duì)象上的style屬性


    style屬性
  • 獲取元素的真實(shí)樣式


    真實(shí)樣式

    style為空

    說(shuō)明:style屬性只能獲取到html標(biāo)簽的內(nèi)聯(lián)樣式,但在這里,文字顏色為藍(lán)色,這個(gè)樣式被寫進(jìn)了style標(biāo)簽內(nèi),style熟悉無(wú)法獲取到元素的真實(shí)樣式,所以,需要通過(guò)getComputedStyle來(lái)獲取真實(shí)的樣式,這是一個(gè)全局屬性

  • 樣式與行為分離


    寫法對(duì)比

    說(shuō)明:對(duì)于圖片中的1寫法,如果我們需要在事件發(fā)生時(shí),對(duì)一個(gè)元素添加多個(gè)樣式,那就意味著我們要寫許多個(gè)style屬性進(jìn)去,這樣代碼太復(fù)雜;前面提過(guò),樣式與行為分離,這樣一來(lái),我們可以先將對(duì)應(yīng)的樣式寫好并添加一個(gè)class,然后通過(guò)js往這個(gè)元素上加一個(gè)class,就可以實(shí)現(xiàn)效果

  • mouseover、mouseout、mouseenter、mouseleave

input相關(guān)事件

  • 輸入框focus、blur


    focus

    focus狀態(tài)下輸出1


    blur

    blur狀態(tài)下輸出2
  • 展現(xiàn)輸入框內(nèi)容并且轉(zhuǎn)換為大寫


    image.png
  • 通過(guò)keyboardEvent查看用戶所按按鍵


    image.png
  • change 當(dāng)輸入框內(nèi)容發(fā)生變化時(shí)


    image.png

    輸入內(nèi)容時(shí),內(nèi)容在改變,但并未執(zhí)行函數(shù)


    image.png

    輸入完,點(diǎn)擊頁(yè)面,執(zhí)行函數(shù),控制臺(tái)輸出內(nèi)容。那么change和blur有什么區(qū)別呢?對(duì)于blur,只要輸入框失焦了,都會(huì)去執(zhí)行函數(shù);而對(duì)于change,可以理解為兩個(gè)過(guò)程,首先輸入框失焦,然后判斷輸入框的內(nèi)容和之前是否發(fā)生了改變,只有發(fā)生了改變,才會(huì)執(zhí)行函數(shù)。
  • form表單的提交時(shí)間
    需求:例如,做一個(gè)登錄或注冊(cè)的頁(yè)面,填完表單后,提交并進(jìn)行數(shù)據(jù)的驗(yàn)證

    提交失敗

  • scroll事件


    scroll事件
  • load事件(圖片加載完成)
    對(duì)于一些圖片,我們不知道它的尺寸,只有在圖片加載完成時(shí),才能通過(guò)js去訪問到,所以這時(shí)可以使用load事件

觸摸事件

ontouchstart, ontouchend, ontouchmove

鍵盤事件:

onkeydown, onkeyup, onkeypress

頁(yè)面相關(guān)事件:

onload, onmove(瀏覽器窗口被移動(dòng)時(shí)觸發(fā)), onresize(瀏覽器的窗口大小被改變時(shí)觸發(fā)), onscroll(滾動(dòng)條位置發(fā)生變化時(shí)觸發(fā))

表單相關(guān)事件

onblur(元素失去焦點(diǎn)時(shí)觸發(fā)), onchange(元素失去焦點(diǎn)且元素內(nèi)容發(fā)生改變時(shí)觸發(fā)), onfocus(元素獲得焦點(diǎn)時(shí)觸發(fā)), onreset(表單中reset屬性被激活時(shí)觸發(fā)), onsubmit(表單被提交時(shí)觸發(fā));oninput(在input元素內(nèi)容修改后立即被觸發(fā),兼容IE9+)

編輯事件

onbeforecopy:當(dāng)頁(yè)面當(dāng)前的被選擇內(nèi)容將要復(fù)制到瀏覽者系統(tǒng)的剪貼板前觸發(fā)此事件;

onbeforecut:當(dāng)頁(yè)面中的一部分或者全部的內(nèi)容將被移離當(dāng)前頁(yè)面[剪貼]并移動(dòng)到瀏覽者的系統(tǒng)剪貼板時(shí)觸發(fā)此事件;

onbeforeeditfocus:當(dāng)前元素將要進(jìn)入編輯狀態(tài);

onbeforepaste:內(nèi)容將要從瀏覽者的系統(tǒng)剪貼板傳送[粘貼]到頁(yè)面中時(shí)觸發(fā)此事件;

onbeforeupdate:當(dāng)瀏覽者粘貼系統(tǒng)剪貼板中的內(nèi)容時(shí)通知目標(biāo)對(duì)象;

oncontextmenu:當(dāng)瀏覽者按下鼠標(biāo)右鍵出現(xiàn)菜單時(shí)或者通過(guò)鍵盤的按鍵觸發(fā)頁(yè)面菜單時(shí)觸發(fā)的事件;

oncopy:當(dāng)頁(yè)面當(dāng)前的被選擇內(nèi)容被復(fù)制后觸發(fā)此事件;

oncut:當(dāng)頁(yè)面當(dāng)前的被選擇內(nèi)容被剪切時(shí)觸發(fā)此事件;

onlosecapture:當(dāng)元素失去鼠標(biāo)移動(dòng)所形成的選擇焦點(diǎn)時(shí)觸發(fā)此事件;

onpaste:當(dāng)內(nèi)容被粘貼時(shí)觸發(fā)此事件;

onselect:當(dāng)文本內(nèi)容被選擇時(shí)的事件;

onselectstart:當(dāng)文本內(nèi)容選擇將開始發(fā)生時(shí)觸發(fā)的事件;

拖動(dòng)事件

ondrag:當(dāng)某個(gè)對(duì)象被拖動(dòng)時(shí)觸發(fā)此事件 [活動(dòng)事件];

ondragdrop:一個(gè)外部對(duì)象被鼠標(biāo)拖進(jìn)當(dāng)前窗口時(shí)觸發(fā);

ondragend:當(dāng)鼠標(biāo)拖動(dòng)結(jié)束時(shí)觸發(fā)此事件;

ondragenter:當(dāng)對(duì)象被鼠標(biāo)拖動(dòng)的對(duì)象進(jìn)入其容器范圍內(nèi)時(shí)觸發(fā)此事件;

ondragleave:當(dāng)對(duì)象被鼠標(biāo)拖動(dòng)的對(duì)象離開其容器范圍內(nèi)時(shí)觸發(fā)此事件;

ondragover:當(dāng)某被拖動(dòng)的對(duì)象在另一對(duì)象容器范圍內(nèi)拖動(dòng)時(shí)觸發(fā)此事件;

ondragstart:當(dāng)某對(duì)象將被拖動(dòng)時(shí)觸發(fā)此事件;

ondrop:在一個(gè)拖動(dòng)過(guò)程中,釋放鼠標(biāo)鍵時(shí)觸發(fā)此事件;

自定義事件

var EventCenter = {
  on: function(type, handler){
    document.addEventListener(type, handler)
  },
  fire: function(type, data){
    return document.dispatchEvent(new CustomEvent(type, {
      detail: data
    }))
  }
}

EventCenter.on('hello', function(e){
  console.log(e.detail)
})

EventCenter.fire('hello', '你好')

參考

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • ??JavaScript 與 HTML 之間的交互是通過(guò)事件實(shí)現(xiàn)的。 ??事件,就是文檔或?yàn)g覽器窗口中發(fā)生的一些特...
    霜天曉閱讀 3,715評(píng)論 1 11
  • JavaScript 程序采用了異步事件驅(qū)動(dòng)編程模型。在這種程序設(shè)計(jì)風(fēng)格下,當(dāng)文檔、瀏覽器、元素或與之相關(guān)的對(duì)象發(fā)...
    劼哥stone閱讀 1,334評(píng)論 3 11
  • 第3章 基本概念 3.1 語(yǔ)法 3.2 關(guān)鍵字和保留字 3.3 變量 3.4 數(shù)據(jù)類型 5種簡(jiǎn)單數(shù)據(jù)類型:Unde...
    RickCole閱讀 5,536評(píng)論 0 21
  • 潔白的房間 有一種淡淡的 讓你恐懼的味道 白衣天使的進(jìn)出 讓你的神經(jīng)緊繃 有種聲音告訴你 你是一個(gè)需要照顧的頑童 ...
    金紫緣閱讀 218評(píng)論 11 9
  • 家常便飯,溫飽尚可,不需味美佳肴。 酒入愁腸,千杯尚少,不消高朋滿座。 浮云似無(wú),良辰美景,涼風(fēng)有幸猖狂。 拾級(jí)而...
    Gunn閱讀 328評(píng)論 0 0

友情鏈接更多精彩內(nèi)容