事件
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
目前主要有三種模型
- IE的事件冒泡:事件開(kāi)始時(shí)由最具體的元素接收寥枝,然后逐級(jí)向上傳播到較為不具體的元素
事件捕獲:不太具體的節(jié)點(diǎn)更早接收事件,而最具體的元素最后接收事件磁奖,和事件冒泡相反
DOM事件流:DOM2級(jí)事件規(guī)定事件流包括三個(gè)階段,事件捕獲階段某筐,處于目標(biāo)階段(到達(dá)目標(biāo)的那個(gè)事件)比搭,事件冒泡階段,首先發(fā)生的是事件捕獲南誊,為截取事件提供機(jī)會(huì)身诺,然后是實(shí)際目標(biāo)接收事件,最后是冒泡階段
這種分歧在日常生活中也很常見(jiàn)抄囚,舉個(gè)例子霉赡,某個(gè)地方出了搶劫事件,我們有多種處理方式
- 村里先發(fā)現(xiàn)幔托,報(bào)告給鄉(xiāng)里穴亏,鄉(xiāng)里報(bào)告到縣城蜂挪,縣城報(bào)告給市里。嗓化。棠涮。。
- 市里先知道這事兒刺覆,然后交代給縣城怎么處理严肪,縣城交給到鄉(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事件流 |
事件處理程序
我們也稱之為事件偵聽(tīng)器(listener),事件就是用戶或?yàn)g覽器自身執(zhí)行的某種動(dòng)作充蓝。比如click隧枫、load、mouseover等谓苟,都是事件類型(俗稱事件名稱)官脓,而響應(yīng)某個(gè)事件的方法就叫做事件處理程序或者事件監(jiān)聽(tīng)器
也就是我們需要提前定義好某些事件發(fā)生了該怎么處理,這個(gè)過(guò)程叫做綁定事件處理程序涝焙,了解了這些卑笨,我們看看如何給元素添加事件處理程序
HTML內(nèi)聯(lián)方式
元素支持的每個(gè)事件都可以使用一個(gè)相應(yīng)事件處理程序同名的HTML屬性指定。這個(gè)屬性的值應(yīng)該是可以執(zhí)行的JavaScript代碼仑撞,我們可以為一個(gè)button添加click
事件處理程序(這種方式在早期使用赤兴,因?yàn)檫€沒(méi)有樣式與操作分離的概念)
<input type="button" value="Click Here" onclick="alert('Clicked!');" />
在HTML事件處理程序中可以包含要執(zhí)行的具體動(dòng)作,也可以調(diào)用在頁(yè)面其它地方定義的腳本,剛才的例子可以寫成這樣
<input type="button" value="Click Here" onclick="showMessage();" />
在HTML中指定事件處理程序書寫很方便隧哮,但是有兩個(gè)缺點(diǎn)桶良。
存在加載順序問(wèn)題沮翔,如果事件處理程序在html代碼之后加載陨帆,用戶可能在事件處理程序還未加載完成時(shí)就點(diǎn)擊按鈕之類的觸發(fā)事件,存在時(shí)間差問(wèn)題
這樣書寫html代碼和JavaScript代碼緊密耦合采蚀,維護(hù)不方便
JavaScript指定事件處理程序
通過(guò)JavaScript指定事件處理程序就是把一個(gè)方法賦值給一個(gè)元素的事件處理程序?qū)傩浴?/p>
每個(gè)元素都有自己的事件處理程序?qū)傩云G#@些屬性名稱通常為小寫,如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>
這樣處理妆够,事件處理程序被認(rèn)為是元素的方法识啦,事件處理程序在元素的作用域下運(yùn)行负蚊,this就是當(dāng)前元素,所以點(diǎn)擊button結(jié)果是:btnClick
這樣還有一個(gè)好處袁滥,我們可以刪除事件處理程序盖桥,只需把元素的onclick屬性賦為null即可
DOM2事件處理程序
DOM2級(jí)事件定義了兩個(gè)方法用于處理指定和刪除事件處理程序的操作:
- addEventListener
- removeEventListener
所有的DOM節(jié)點(diǎn)都包含這兩個(gè)方法,并且它們都接受三個(gè)參數(shù):
- 事件類型
- 事件處理方法
- 布爾參數(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>
上面代碼為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>
通過(guò)this得知監(jiān)聽(tīng)的元素
阻止默認(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)行了事件綁定塞淹,但新增的元素并沒(méi)有進(jìn)行事件綁定,所以點(diǎn)擊新增元素?zé)o法展示內(nèi)容罪裹。
雖然實(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è)問(wèn)題裤翩,當(dāng)li較小時(shí)资盅,我們點(diǎn)擊到了ul,但這里還是會(huì)打印出所有的內(nèi)容踊赠,這是需要對(duì)點(diǎn)擊的地方做一個(gè)判斷
IE兼容性
說(shuō)明:對(duì)于attachEvent呵扛,在它的回調(diào)函數(shù)中想要知道監(jiān)聽(tīng)的事件,可通過(guò)window.event獲取
跨瀏覽器的事件處理程序
前面內(nèi)容我們可以看到筐带,在不同的瀏覽器下今穿,添加和移除事件處理程序方式不相同,要想寫出跨瀏覽器的事件處理程序伦籍,首先我們要了解不同的瀏覽器下處理事件處理程序的區(qū)別
在添加事件處理程序事addEventListener和attachEvent主要有幾個(gè)區(qū)別
參數(shù)個(gè)數(shù)不相同蓝晒,這個(gè)最直觀,addEventListener有三個(gè)參數(shù)帖鸦,attachEvent只有兩個(gè)芝薇,attachEvent添加的事件處理程序只能發(fā)生在冒泡階段富蓄,addEventListener第三個(gè)參數(shù)可以決定添加的事件處理程序是在捕獲階段還是冒泡階段處理(我們一般為了瀏覽器兼容性都設(shè)置為冒泡階段)
第一個(gè)參數(shù)意義不同,addEventListener第一個(gè)參數(shù)是事件類型(比如click灭红,load)娇斑,而attachEvent第一個(gè)參數(shù)指明的是事件處理函數(shù)名稱(onclick毫缆,onload)
-
事件處理程序的作用域不相同,addEventListener的作用域是元素本身乐导,this是指的觸發(fā)元素苦丁,而attachEvent事件處理程序會(huì)在全局變量?jī)?nèi)運(yùn)行,this是window物臂,所以剛才例子才會(huì)返回undefined旺拉,而不是元素id
說(shuō)明:也就是說(shuō)产上,當(dāng)我們?cè)贗E中寫的時(shí)候,這里的this是window蛾狗,而不是box
- 為一個(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è)問(wèn)題參數(shù)個(gè)數(shù)不同,現(xiàn)在三個(gè)參數(shù)遵倦,采用事件冒泡階段觸發(fā)
第二個(gè)問(wèn)題也得以解決尽超,如果是IE,我們給type添加上on
第四個(gè)問(wèn)題目前還沒(méi)有解決方案梧躺,需要用戶自己注意似谁,一般情況下,大家也不會(huì)添加很多事件處理程序
試試這個(gè)方法感覺(jué)很不錯(cuò)掠哥,但是我們沒(méi)有解決第三個(gè)問(wèn)題巩踏,由于處理程序作用域不同,如果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的問(wèn)題了派近,但是新的問(wèn)題又來(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ì)象 |
在事件處理程序內(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)框就沒(méi)了區(qū)別。
要阻止事件的默認(rèn)行為酒繁,可以使用preventDefault()
方法滓彰,前提是cancelable值為true,比如我們可以阻止鏈接導(dǎo)航這一默認(rèn)行為
document.querySelector('#btn').onclick = function (e) {
e.preventDefault();
}
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ì)象
訪問(wèn)IE中的event對(duì)象有幾種不同的方式,取決于指定事件處理程序的方法邦蜜。直接為DOM元素添加事件處理程序時(shí)依鸥,event對(duì)象作為window對(duì)象的一個(gè)屬性存在。(在DOM2中悼沈,回調(diào)函數(shù)傳入的參數(shù)直接就是監(jiān)聽(tīng)的事件贱迟,直接就能拿來(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ì)象訪問(wèn)event,方便起見(jiàn)壤靶,我們一般會(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)化寫法
跨瀏覽器的事件對(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屬性
-
獲取元素的真實(shí)樣式
說(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è)全局屬性
-
樣式與行為分離
說(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狀態(tài)下輸出1
blur狀態(tài)下輸出2 -
展現(xiàn)輸入框內(nèi)容并且轉(zhuǎn)換為大寫
-
通過(guò)keyboardEvent查看用戶所按按鍵
-
change 當(dāng)輸入框內(nèi)容發(fā)生變化時(shí)
輸入內(nèi)容時(shí),內(nèi)容在改變姑尺,但并未執(zhí)行函數(shù)
輸入完竟终,點(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事件
load事件(圖片加載完成)
對(duì)于一些圖片拗秘,我們不知道它的尺寸,只有在圖片加載完成時(shí)祈惶,才能通過(guò)js去訪問(wèn)到雕旨,所以這時(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)容選擇將開(kā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ì)象離開(kāi)其容器范圍內(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', '你好')