{Java} Vaadin 14 -检测用户离开(关闭选项卡、按f5键等)

5lhxktic  于 2023-02-02  发布在  Java
关注(0)|答案(3)|浏览(99)

我目前正在使用Vaadin Flow版本14https://github.com/vaadin/platform/releases/tag/14.0.0
我运行的是64位的Java版本1.8.0_231。
我只是希望能够检测(在java中!)用户何时执行以下操作之一:

  • 关闭当前浏览器选项卡(或其浏览器)
  • 单击键盘上的F5,或按浏览器中的“刷新”按钮
  • 单击链接(或其他任何内容),将其重定向到远离我的网站的位置

我尝试了很多不同的方法来检测这个问题。到目前为止,我唯一能够检测到的是当前VaadinSession何时到期(我可以通过VaadinSession.getCurrent().getSession().setMaxInactiveInterval(15)来更改)。这使得每个会话在15秒后到期(15在我的情况下只是一个测试数字)。
有了Vaadin 8,我相信你可以做到这一点,它将开箱即用:

JavaScript.getCurrent().execute(
            "function closeListener() { catchClose(); } " +
                    "window.addEventListener('beforeunload', closeListener); " +
                    "window.addEventListener('unload', closeListener);"
        );
        JavaScript.getCurrent().addFunction("catchClose", arguments ->
        {
            System.out.println("user has quit :o");
        });

我不能用这个,因为我用的是Vaadin 14,而不是8
我已经尝试将此添加到我的View类:

@Override
    protected void onDetach(DetachEvent detachEvent)
    {
        System.out.println("onDetach " + detachEvent);
    }

它只在会话到期时打印此消息(在我的例子中为15秒),即使我没有关闭页面。
我尝试过实现BeforeLeaveObserver/BeforeLeaveListener并覆盖此命令:

@Override
    public void beforeLeave(BeforeLeaveEvent beforeLeaveEvent)
    {
        System.out.println("beforeLeave");
    }

这从来不打印。
我也尝试了所有这些方法,但它们不能满足我的需要:

VaadinResponse.getCurrent().getService().addUIInitListener(e ->
        {
            System.out.println("1 addUIInitListener : " + e);
            e.getUI().addBeforeLeaveListener(e2 ->
            {
                System.out.println("1.1 addBeforeLeaveListener : " + e2);
            });
            e.getUI().addDetachListener(e2 ->
            {
                System.out.println("1.2 addDetachListener : " + e2);
            });
        });
        VaadinResponse.getCurrent().getService().addServiceDestroyListener(e ->
        {
            System.out.println("2 addServiceDestroyListener : " + e);
        });
        VaadinResponse.getCurrent().getService().addSessionDestroyListener(e ->
        {
            System.out.println("3 addSessionDestroyListener : " + e);
        });

1 addUIInitListener在用户加载页面时打印。
1.1 addBeforeLeaveListener从不打印。
2 addServiceDestroyListener从不打印。服务与会话不同。这是有意义的。
1.23 addSessionDestroyListener打印wafter一段时间。需要15-30秒tho。
难道没有一种方法可以基本上立即检测到这一点吗?:/

alen0pnh

alen0pnh1#

检测关闭的JavaScript方法仍然有效。
语法只是做了一点更改

UI.getCurrent().getPage().executeJs("function closeListener() { $0.$server.windowClosed(); } " +
        "window.addEventListener('beforeunload', closeListener); " +
        "window.addEventListener('unload', closeListener);",getElement());

@ClientCallable
public void windowClosed() {
    System.out.println("Window closed");
}

虽然这不是100%的防弹方式,因为我认为不是所有的浏览器工作方式相同.例如,上面的代码触发两次与Chrome,其中监听beforeunload是足够的.
这允许简化JavaScript以

UI.getCurrent().getPage().executeJs(
"window.addEventListener('beforeunload', () => $0.$server.windowClosed()); ",getElement());

BeforeLeaveObserver用于导航。因此,如果使用RouterLink或调用ui.navigate("route"),则会调度BeforeLeaveEvent,但调用page.setLocation()时不会调度。

浏览器可能会因崩溃而关闭,或者因其他原因丢失,那么beforeunload自然不会发生。最后一招是基于心跳的检测机制。即在丢失三次心跳后,Vaadin服务器将得出浏览器丢失的结论。这自然会有延迟,这是无法避免的。

deikduxw

deikduxw2#

根据您需要支持的浏览器,您可能还想看看Beacon API,它被所有现代浏览器支持,但不支持IE11。
API的优点是无阻塞,使用卸载监听器,客户端在关闭选项卡之前等待响应,这可能是不好的用户体验。
尽管如此,正如Tatu提到的,如果浏览器崩溃或用户失去互联网连接,您所能做的就是等待会话超时。

myzjeezk

myzjeezk3#

Vaadin流程22的解决方案。我在index.html中放置了一个部分,就在关闭标记之后:

<script>
      window.addEventListener('beforeunload', function (event) {
       event.returnValue = 'Are you sure you want to close the application?';
      });
  </script>

最有可能的是,你不会在对话框窗口中看到你的自定义消息--你会看到默认的消息。我也没有看到它,但仍然应用它;)

相关问题