前言:
仅仅是简单模拟了 $().on() 和 $().trigger()
,仅支持 id 选择器,事件冒泡与事件委托。
代码:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title> 模拟 jQuery 的事件绑定到触发过程 </title>
</head>
<body>
<div id="A" style="background-color: deeppink">
这是 A
<div id="B" style="background-color: aqua">
这是 B
</div>
</div>
<script>
// 数据缓存
let events={}
function $(elemId){
// 只考虑理想情况
const element=document.querySelector(elemId)
// console.log(element,'element27')
function returnTrue(){return true}
function returnFalse(){return false}
$.event={
// 不考虑用户的自定义事件
add:function (elemId,type,selectorReal,callbackReal) {let elemData=events[elemId]
if(!elemData){events[elemId]=elemData={}}
elemData.handle=function(nativeEvent){
// 锁定 this
return $.event.dispatch.call(this,nativeEvent)
}
if(!elemData[type]){elemData[type]=[]
elemData[type].delegateCount=0
//addEventListener 只绑定一次
document.querySelector(elemId).addEventListener(type,elemData.handle)
}
let handlersCount=elemData[type].length
let handlerObj={
type:type,
handler:callbackReal,
guid:++handlersCount,
selector:selectorReal,
}
if (selectorReal) {
// 在下标为 handlers.delegateCount++ 的位置插入委托事件
elemData[type].splice(elemData[type].delegateCount++, 0, handlerObj);
} else {elemData[type].push(handlerObj)
}
},
dispatch:function (nativeEvent,) {let event=$.event.fix(nativeEvent)
let handlers=events['#'+this.id][event.type]
// 继续锁定 this
let handlerQueue=$.event.handlers.call(this, event, handlers)
// 为什么要用变量代替,因为循环的时候,需要保留该值
let matched,handleObj
let i=0
while((matched=handlerQueue[i++])&&!event.isPropagationStopped()){
let j=0
while((handleObj=matched.handlers[j++])){
event.handleObj=handleObj
handleObj.handler(event)
}
}
// return event
},
fix:function (nativeEvent,) {let $event={}
// 就是 MouseEvent
$event.originalEvent=nativeEvent
$event.target=nativeEvent.target
$event.type=nativeEvent.type
// delegateTarget: div#A,
// currentTarget: div#A,
$event.timeStamp=Date.now()
$event.stopPropagation=function() {
this.isPropagationStopped = returnTrue;
nativeEvent.stopPropagation()}
$event.isPropagationStopped=returnFalse
//fix 的标志
$event['chen'+(new Date()).valueOf()]=true
return $event
},
handlers:function (event,handlers) {
let delegateCount = handlers.delegateCount
let cur=event.target
let handlerQueue=[]
for(;cur!==this;cur=cur.parentNode||this){let matchedHandlers = []
for(let i=0;i<delegateCount;i++){let handleObj=handlers[i]
matchedHandlers.push(handleObj)
handlerQueue.push({ elem: cur, handlers: matchedHandlers} )
}
}
cur=this
if (delegateCount < handlers.length) {handlerQueue.push( { elem: cur, handlers: handlers.slice( delegateCount) } )
}
return handlerQueue
},
trigger:function (elemId,type) {let element=document.querySelector(elemId)
let eventPath=[]
let cur=element
let event={}
event.target=cur
event.type=type
for(;cur;cur=cur.parentNode){eventPath.push( cur);
}
let i=0
// 不考虑阻止冒泡的情况
while((cur=eventPath[i++])){let handle=events['#'+cur.id]&&events['#'+cur.id].handle
if(handle){handle.call(cur,event)
}
}
},
}
return {on:function (type,selector,callback) {
let callbackReal,selectorReal
if(!type){return}
// 如果 selector 是 funcion 的话,就没有委托元素了
if(typeof selector==='function'&&!callback){
selectorReal=undefined
callbackReal=selector
}else if(typeof selector==='string'&&callback){
selectorReal=selector
callbackReal=callback
}
return $.event.add(elemId,type,selectorReal,callbackReal)
},
trigger:function (type) {return $.event.trigger(elemId,type)
},
}
}
// 仅支持 id 选择器,事件冒泡与事件委托
//=========test1===============
$("#A").on("click" ,function (event) {console.log(event,"A 被点击了")
})
$("#A").on("click" ,function (event) {console.log(event,"A 又被点击了")
})
//=========test2===============
// $("#A").on("click" ,function (event) {// console.log(event,"A 被点击了")
// })
// $("#A").on("click" ,"#B",function (event) {// event.stopPropagation()
// console.log(event,"B 委托 A 被点击了")
// })
//=========test3===============
// $("#A").on("click" ,function (event) {// console.log(event,"A 被点击了")
// })
// $("#B").on("click",function (event) {// // event.stopPropagation()
// console.log(event,"B 被点击了")
// })
//==========test4==============
// $("#A").on("click" ,function (event) {// console.log(event,"A 被点击了")
// })
// $("#A").on("click" ,function (event) {// console.log(event,"A 又被点击了")
// })
// $("#A").trigger("click")
</script>
</body>
</html>
根据上篇的流程图写出即可。
思路请看:
(完)