Event::dispatchEvent

来源:互联网 发布:unity3d吃金币 编辑:程序博客网 时间:2024/06/03 14:07

今天有仔细看了一遍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()很常见,我们在修改内核或应用时都能经常用到。





0 0