GWT的sinkEvent功能是如何工作的?

5

我有一个简单的GWT测试设置:

<g:HTMLPanel ui:field="container" width="500px" height="300px">
    <g:Label ui:field="inner" text="hello"></g:Label>
</g:HTMLPanel>

添加处理程序后:

container.addDomHandler(new ClickHandler()
{
    @Override
    public void onClick(ClickEvent event)
    {
        Window.alert("click on container");
    }
}, ClickEvent.getType());

inner.addDomHandler(new ClickHandler()
{
    @Override
    public void onClick(ClickEvent event)
    {
        Window.alert("click on inner");
    }
}, ClickEvent.getType());

根据源代码,这些addHandler调用都使用了

DOM.sinkEvents(Element elem, int eventBits)

方法来设置事件的下沉。

根据文档,"Sets the current set of events sunk by a given element. These events will be fired to the nearest {@link EventListener} specified on any of the element's parents."

实际上,如果单击内部 div,无论以哪种方式处理,单击事件都将传递到其父div:

  • 如果我没有在子元素上设置任何 ClickHandlers

  • 如果我已经为子元素设置了处理程序

  • 如果我已经设置了处理程序,但清除了 ClickEvent 的下沉

DOM.sinkEvents(inner.getElement(), DOM.getEventsSunk(getElement()) & ~Event.getTypeInt(ClickEvent.getType().getName()));

为什么会发生这种情况?事件下沉的真正作用是什么?添加处理程序与事件下沉有何关联?是否有可能在不显式删除处理程序的情况下防止给定小部件上添加的所有处理程序都被调用?也就是说,有没有一种方法可以停止处理某个小组件上的所有事件?

1个回答

8

首先,sinkEvent 是在元素上添加本地事件处理程序的方法,如 GWT wiki 中所解释的那样。

你看到的是事件冒泡,这是浏览器中事件的工作方式:当分发事件时,有两个阶段:捕获阶段(旧版 IE 中未实现)允许任何祖先元素在事件到达目标之前捕获它,然后在冒泡阶段,事件在 DOM 层次结构中向上冒泡。因此,如果你在 HTMLPanel 上监听点击事件,你也会接收到来自 Label 的冒泡点击事件。

你可以通过在 Label 级别监听事件并调用 stopPropagation() 来防止这种情况,以使其不冒泡到 HTMLPanel


谢谢,Thomas。但是如果我想要防止任何事件在标签级别上处理 - 看起来我所需要的就是通过DOM.sinkEvents(label.getElement(), 0)将sunkEvents清零,我是对的吗?而且我可以很容易地通过添加ClickEvent位掩码来切换回去,而不需要添加/删除处理程序。 - KutaBeach
可以这么做,但那是一个很丑陋的大Hack!何不在事件处理程序中仅测试您是否有工作要做(即,您是否已禁用)? sinkEvents 真的是一个低级API,只应在小部件内部使用;不要干扰其他小部件,否则可能会破坏它们。 - Thomas Broyer
这就是我所做的 - 在所有事件处理程序中添加了if子句,以防止在我的小部件被禁用时处理事件。但是,在5个处理程序中复制粘贴相同的“if”看起来也不太好:/ - KutaBeach
链接不幸已经失效。 - Stefan Falk
这些事情发生在两年前的链接上。链接已经修复。 - Thomas Broyer

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接