美文网首页
模拟实现jQuery的$().on()和$().trigger(

模拟实现jQuery的$().on()和$().trigger(

作者: 小进进不将就 | 来源:发表于2019-06-19 13:50 被阅读0次

    前言:
    仅仅是简单模拟了$().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>
    

    根据上篇的流程图写出即可。

    思路请看:


    (完)

    相关文章

      网友评论

          本文标题:模拟实现jQuery的$().on()和$().trigger(

          本文链接:https://www.haomeiwen.com/subject/gizdfctx.html