1. 详述 DOM 该事件数学模型
捕捉该事件:该事件从最内层父原素到最里层子原素的次序促发,叫作捕捉该事件,果document > html > body > div > p > button
altered该事件:刚好和捕捉该事件恰好相反,该事件从最里层子原素到最内层父原素的次序促发,叫作altered该事件,如:button > p > div > body > html > document
先历经由上而下的捕捉期,再历经节兰的altered期
target.addEventListener(type, listener, useCapture);
// addEventListener(click,fn,true/false)
第二个模块能选择期,true 为捕捉期,false 或不误为altered期
能采用 event.stopPropagation() 来制止捕捉或是altered
2. 记事本该事件委派
窃听父原素:比如说有位条目,窃听 ul ,在推论e.target 点选的呢 li,若是 li 则继续执行某一表达式
e.target:采用者促发的第一类 等效为 li
e.currentTarget:窃听的第一类 等效为 ul
ul.addEventListener(click,function(e){
if(e.target.tagName.toLowerCase() === li){
fn() //继续执行某一表达式
}
})
这样是有 bug 的,如果采用者点选的是 li 里面的 span,就没法促发 fn,这显然不对
该事件委派的好处:① 节省窃听器 ② 实现动态窃听
坏处:调试比较复杂,不容易确定窃听者
解决坏处:解决不了
接着说上面的「如果采用者点选的是 li 里面的 span,就没法促发 fn」的问题,能 点选 span 后,递归遍历 span 的祖先原素看其中有没有 ul 里面的 li,实现一个 delegate 委派表达式,模块分别为 窃听原素element、该事件类型eventType、窃听器窃听的子原素selector、继续执行的表达式 fn
function delegate(element,eventType,selector,fn){
element.addEventListener((eventType,e)=>{
let el = e.target
while(!el.matches(selector)){
if(element === el){ // 遍历至窃听的原素仍找不到监听器窃听的子原素,说明不在其窃听范围内 el = null
break
}
el = el.parentNode
}
el && fn.call(el,e,el)
})
return element
}
采用:
delegate(ul,click,li,f1)
3. 记事本可拖拽 div
代码示例及效果预览
<!DOCTYPE html>
<html>
<head>
<meta charset=“utf-8”>
<meta name=“viewport” content=“width=device-width”>
<title>JS Bin</title>
<style>
div{
border: 1px solid red;
position: absolute;
top: 0;
left: 0;
width: 100px;
height: 100px;
}
*{margin:0; padding: 0;}
</style>
</head>
<body>
<div id=“xxx”></div>
<script>
var dragging = false
var position = null
xxx.addEventListener(mousedown,function(e){
dragging = true //正在移动 position = [e.clientX,e.clientY]
})
document.addEventListener(mousemove,function(e){
if(dragging === false){return} // 没有移动就别拖
const x = e.clientX
const y = e.clientY
const deltaX = x – position[0]
const deltaY = y – position[1]
const left = parseInt(xxx.style.left || 0)
const top = parseInt(xxx.style.top || 0)
xxx.style.left = left + deltaX + px
xxx.style.top = top + deltaY + px
position = [x,y]
})
document.addEventListener(mouseup,function(e){
dragging = false
})
</script>
</body>
</html>
要点:
注意窃听范围,不能只窃听 div不要采用 drag该事件,很难用采用 transform 会比 top / left 性能更好,因为能避免 reflow 和 repaint