1函喉、請(qǐng)簡(jiǎn)述DOM事件模型
- 什么是DOM事件模型:每一個(gè)事件都會(huì)先經(jīng)歷從上到下的捕獲階段捐下,再經(jīng)歷從下到上的冒泡階段啤握。
- 如何選擇捕獲or冒泡:添加事件監(jiān)聽時(shí)候addEventListener(’click’,fn,true/false) 第三個(gè)參數(shù)可以選擇階段。
true表示把它放到捕獲階段,false或者不傳把它放到冒泡階段。 - 在這兩個(gè)階段希望停止傳播(捕獲/冒泡到一個(gè)div就不要往下走了)
可以使用 event.stopPropagation() 來阻止捕獲或冒泡乞娄。
2、手寫事件委托
BUG版(正確答案)
思路:
當(dāng)用戶點(diǎn)擊列表時(shí),他點(diǎn)擊的目標(biāo)e.target,的標(biāo)簽名tagName,小寫之后是li(默認(rèn)大寫)
如果是li那就說明它點(diǎn)擊列表中的某一項(xiàng)契沫,就執(zhí)行某個(gè)函數(shù)口予。
事件委托就是木张,我不監(jiān)聽li我監(jiān)聽li的爸爸。只要點(diǎn)擊li就會(huì)觸發(fā)函數(shù)。
我們?cè)谑褂胻arget的時(shí)候是用e.target 還是 e.currentTarge剧浸?
兩者區(qū)別:
currentTarge是我監(jiān)聽的對(duì)象腾啥,比如說我監(jiān)聽ul,那就是ul
target是用戶觸發(fā)的對(duì)象,它點(diǎn)span那就是span它點(diǎn)li就是li
ul.addEventListener('click', function(e){
if(e.target.tagName.toLowerCase() === 'li'){
fn()// 執(zhí)行某個(gè)函數(shù)
}
})
bug 在于,如果用戶點(diǎn)擊的是 li 里面的 span仪吧,就沒法觸發(fā) fn吭从,這顯然不對(duì)。
bug就bug吧工作中不用自己寫,Vue/React中自動(dòng)幫你事件委托了。
高級(jí)無BUG版本
思路:當(dāng)你點(diǎn)擊span后,遞歸遍歷span的祖先元素找li 最多看到ul.
function delegate(elemet,eventType,selector,fn){
element.addEventListener(eventType,e=>{
let el = e.target
while(!el.matches(selector)){//el.matches(selector)判斷你點(diǎn)擊的元素是不是li
if(element === el){ //如果我找到的元素等于ul了 移袍,那說明沒找到li那就置為空
el = null
break
}
el = el.parentNode //讓你等于你爸爸,再循環(huán)看看你是不是li
}
//跳出循環(huán)后如果el空那就什么都不做涂籽,否則執(zhí)行fn此時(shí)fn的this是el
el && fn.call(el,e)
})
return element
}
delegate(ul,'click',li,f1)
只要你點(diǎn)擊了ul中的li(無論是li自身還是li后代)執(zhí)行fl.
事件委托的好處與壞處
好處:
1砂轻、節(jié)省監(jiān)聽器
2、動(dòng)態(tài)監(jiān)聽
壞處:
調(diào)試比較復(fù)雜文兑,不容易確定當(dāng)前元素有哪些事件監(jiān)聽∶夷可能點(diǎn)擊一個(gè)div觸發(fā)莫名其妙的事件甸怕,因?yàn)辄c(diǎn)擊的div可能有n多父元素,不可能一層一層的找。
http://www.reibang.com/p/d94dc9be547e
3释液、手寫可拖拽div
- mousedown 事件在指針設(shè)備按鈕按下時(shí)觸發(fā)。
- 當(dāng)指針在元素中時(shí)躺盛, mouseup事件在指針設(shè)備(如鼠標(biāo)或觸摸板)按鈕放開時(shí)觸發(fā)。
- 當(dāng)指針設(shè)備 ( 通常指鼠標(biāo) ) 在元素上移動(dòng)時(shí)仿耽,mousemove 事件被觸發(fā)俺泣。
- clientX 事件屬性返回當(dāng)事件被觸發(fā)時(shí)鼠標(biāo)指針相對(duì)于瀏覽器頁(yè)面(或客戶區(qū))的水平坐標(biāo)。
- parseInt 解析一個(gè)字符串返回一個(gè)整數(shù)鹏秋。
- 代碼
JS Bin - 手寫拖拽div - 思路:我鼠標(biāo)按下div的時(shí)候記錄初始坐標(biāo)尊蚁,當(dāng)我移動(dòng)的時(shí)候做差然后對(duì)div進(jìn)行移動(dòng)。移動(dòng)完了記錄基準(zhǔn)點(diǎn)侣夷。
- 要點(diǎn)
1横朋、注意監(jiān)聽范圍,不能只監(jiān)聽div
mousedown是監(jiān)聽div其他放在document上
因?yàn)槿绻挤旁赿iv上大幅度移動(dòng)容易掉百拓,超出div且只監(jiān)聽div
2琴锭、使用transfrom 比top/left性能更好避免reflow和repaint