Event::dispatchEvent

今天有仔細看了一遍webkit中event的dispatch機制,整理如下(WebKit-r60688,最新版本中總體流程沒變)


bool Node::dispatchGenericEvent(PassRefPtr<Event> prpEvent)
{
    ......
    Vector<RefPtr<ContainerNode> > ancestors;
    eventAncestors(ancestors); // 1. 獲取該Node的所有祖先節點


    DOMWindow* targetForWindowEvents = 0;
    if (event->type() != eventNames().loadEvent) {        // 2. 非loadEvent,獲取DOMWindow對象,即對應JS的window對象
        Node* topLevelContainer = ancestors.isEmpty() ? this : ancestors.last().get();
        if (topLevelContainer->isDocumentNode())
            targetForWindowEvents = static_cast<Document*>(topLevelContainer)->domWindow();
    }


    void* data = preDispatchEventHandler(event.get());  // 3. event預處理preDispatch
    if (event->propagationStopped())        goto doneDispatching;


    event->setEventPhase(Event::CAPTURING_PHASE); // 4. event的caputre階段處理。從DOMWindow,到Document, ... ,直到target node
    if (targetForWindowEvents) {
        event->setCurrentTarget(targetForWindowEvents);
        targetForWindowEvents->fireEventListeners(event.get());
        if (event->propagationStopped())
            goto doneDispatching;
    }
    for (size_t i = ancestors.size(); i; --i) {
        ContainerNode* ancestor = ancestors[i - 1].get();
        event->setCurrentTarget(eventTargetRespectingSVGTargetRules(ancestor));
        ancestor->handleLocalEvents(event.get());
        if (event->propagationStopped())
            goto doneDispatching;
    }


    event->setEventPhase(Event::AT_TARGET);               // 5. event的target階段處理
    event->setCurrentTarget(eventTargetRespectingSVGTargetRules(this));
    handleLocalEvents(event.get());
    if (event->propagationStopped())    goto doneDispatching;


    if (event->bubbles() && !event->cancelBubble()) {
        // Trigger bubbling event handlers, starting at the bottom and working our way up.
        event->setEventPhase(Event::BUBBLING_PHASE);  // 6. 如果event允許bubble,且cancelbubble爲false(即不允許設置取消bubble),

                                                                              //進入event的bubble階段處理方向與capture相反,從target node ... Document,DOMWindow
        size_t size = ancestors.size();    
        for (size_t i = 0; i < size; ++i) {
            ContainerNode* ancestor = ancestors[i].get();
            event->setCurrentTarget(eventTargetRespectingSVGTargetRules(ancestor));
            ancestor->handleLocalEvents(event.get());
            if (event->propagationStopped() || event->cancelBubble())
                goto doneDispatching;
        }
        if (targetForWindowEvents) {
            event->setCurrentTarget(targetForWindowEvents);
            targetForWindowEvents->fireEventListeners(event.get());
            if (event->propagationStopped() || event->cancelBubble())
                goto doneDispatching;
        }
    }


doneDispatching:
    postDispatchEventHandler(event.get(), data);  // 7. 三階段處理結束後,event後處理postDispatch


    if (!event->defaultPrevented() && !event->defaultHandled()) {
        defaultEventHandler(event.get());  // 8. 如果3階段處理完畢,event的defaultPrevented仍然爲false且defaultHandled也爲false,即事件的默認處理不被阻止且還沒有

                                                             // 被處理,則調用target node的默認event處理函數defaultEventHandler

                                                      //  event的defaultPrevented表示js的listener阻止event的進一步處理。event的defaultHandled表示3階段處理過程中event

                                                      //  是否被處理了
        if (event->defaultHandled())                 
            goto doneWithDefault;


        if (event->bubbles()) { // 9. 如果此時event還沒有被處理掉(即node的defaultEventHandler也沒有處理該事件)且event能bubble(可以查看eventhandler,

                                          // 哪些event創建時bubble時true,默認Event的bubble是false,UIEvent的bubble爲true),

                                        // 則以bubble方式調用defaultEventHandler
            size_t size = ancestors.size();
            for (size_t i = 0; i < size; ++i) {
                ContainerNode* ancestor = ancestors[i].get();
                ancestor->defaultEventHandler(event.get());
                ASSERT(!event->defaultPrevented());
                if (event->defaultHandled())
                    goto doneWithDefault;
            }
        }
    }


doneWithDefault:
    return !event->defaultPrevented();  // 10. 最後返回event的defaultPrevented,決定該event是否被處理掉了
}


總結一下:

  處理event的event target有,從頂到低: DOMWindow,Document, ... , targetNode

  首先capture, target, bubble(event允許bubble時) 三階段處理(主要是user通過js addEventListerner註冊的函數)

  如果事件還沒有被處理,則調用target node的defaultEentHandler處理(WebKit內核中事件默認處理函數)

  如果事件還沒有被處理,則以bubble方式調用defaultEentHandler(前提是event允許bubble)


capture, target, bubble三階段事件處理函數是handleLocalEvents,該函數主要在Node.cpp中實現(chromium39中在HTMLFormElement中重載實現了,其他element沒有),主要作用就是觸發fireEventListeners,即交給js處理

JS調用addEventListener的第三個參數capture,意義是“是否capture”,即是否在capture過程處理,如果爲true,則在capture階段就處理,否則在bubble階段處理。如果javascript某一個處理函數將event的cancelBubble屬性設置爲true,則target之後的bubble處理過程就會被取消,即通過addEventListener且設置了capture爲false的js函數就不在被執行。上述代碼中的event->cancelBubble()即爲event的cancelBubble的屬性值。


event->bubbles()表示該event是否能夠bubble,在該event創建時已經確定了。所以說並不是所有的event都能bubble處理的。UIEvent一般是不能bubble的,也有些特殊的(chromium39中搜索UIEvent::create查看,例如EventTypeNames::DOMActivate是可以bubble的)

event->cancelable()表示該event是否能被取消。

event->defaultPrevented()表示該event是否被阻止了

event->defaultHandled()表示該event已經被處理過了且不需要繼續傳遞。event.setDefaultHandled()很常見,我們在修改內核或應用時都能經常用到。





發佈了66 篇原創文章 · 獲贊 16 · 訪問量 25萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章