webkit中hover的几个小知识

本文深入解析WebCore中节点的hover状态控制机制,包括如何使用hovered和setHover函数进行状态切换,以及如何在不同节点层级中更新界面。同时,介绍了如何在Document元素中保存当前的hover指针,以及重新设置hover节点的完整方法。最后,通过EventHandler类的fakeMouseMoveEvent展示了在窗口位置、状态变化后如何重新进行hover操作。

1。每个元素都有一个hover状态,通过hovered和setHover来控制,该函数在WebCore::Node上:

bool hovered() const { return getFlag(IsHoveredFlag); }
....
virtual void setHovered(bool f = true) { setFlag(f, IsHoveredFlag); }

 

2. setHover是个虚函数,WebCore::ContainerNode重载了它,并且能够更新界面

void ContainerNode::setHovered(bool over)
{
    if (over == hovered()) return;
    Node::setHovered(over);
    // note that we need to recalc the style
    // FIXME: Move to Element
    if (renderer()) {
        if (renderer()->style()->affectedByHoverRules())
            setNeedsStyleRecalc();
        if (renderer() && renderer()->style()->hasAppearance())
            renderer()->theme()->stateChanged(renderer(), HoverState);
    }
}

3. 参照上面的代码,判断一个节点是否有Hover的CSS关联方法:renderer()->style()->affectedByHoverRules()

 

4. WebCore::Document元素保存一个当前的hover指针:

void Document::setHoverNode(PassRefPtr<Node> newHoverNode)
{
    m_hoverNode = newHoverNode;
}

 

5. 重新设置一个hover节点完整的方法:

static RenderObject* commonAncestor(RenderObject* obj1, RenderObject* obj2)
{
    if (!obj1 || !obj2)
        return 0;
    for (RenderObject* currObj1 = obj1; currObj1; currObj1 = currObj1->hoverAncestor())
        for (RenderObject* currObj2 = obj2; currObj2; currObj2 = currObj2->hoverAncestor())
            if (currObj1 == currObj2)
                return currObj1;
    return 0;
}
static void switchHover(Document *document, Node* oldHoveredNode, Node* newHoveredNode)
{
    RenderObject *ancestor = commonAncestor(oldHoveredNode ? oldHoveredNode->renderer(): NULL, newHoveredNode ? newHoveredNode->renderer() : NULL);
    if(oldHoveredNode){
        oldHoveredNode->setHovered(false);
        for (RenderObject* curr = oldHoveredNode->renderer(); curr && curr != ancestor; curr = curr->hoverAncestor()) {
            if (curr->node() && !curr->isText() /*&& curr->node()->inActiveChain()*/)
                curr->node()->setHovered(false);
        }
    }
    document->setHoverNode(newHoveredNode);
    if(newHoveredNode)
    {
        for (RenderObject* curr = newHoveredNode->renderer(); curr; curr = curr->hoverAncestor()) {
            if (curr->node() && !curr->isText() /*&& curr->node()->inActiveChain()*/)
                curr->node()->setHovered(true);
        }
        newHoveredNode->setHovered(true);
    }
}

 

6. EventHandler的fakeMouseMoveEvent: 产生一个假的鼠标移动事件,在窗口位置、状态变化后重新hover,但实际上用户并没有移动鼠标:

  1) 定义

class EventHandler {
....
Timer<EventHandler> m_fakeMouseMoveEventTimer;
....
};

  2) 初始化

EventHandler::EventHandler(Frame* frame)
    : m_frame(frame)
    ....
    , m_fakeMouseMoveEventTimer(this, &EventHandler::fakeMouseMoveEventTimerFired)
......


评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值