Docs

Documentation versions (currently viewingVaadin 24)
Documentation translations (currently viewingChinese)

本页面为机器翻译,原官方文档请见 http://vaadin.com/docs。翻译内容可能存在错误、不准确或表述不当之处。Vaadin 不保证翻译的准确性、可靠性或时效性,也不作任何声明。

运行时修改 Bootstrap 页面

自定义应用程序 shell(即 bootstrap 页面)以提升页面加载速度。

应用程序 shell 模型 旨在通过优先加载网页的_重要_部分来加快网站访问速度,从而提升用户体验。关键点在于首次访问时交付显示用户界面所需的最小 HTML、CSS 和 JavaScript,并将其缓存以便后续访问时使用。

Vaadin Flow 中的 应用程序 Shell 也被称为 Bootstrap 页面,或 index.html

修改应用程序 Shell

开发人员可以完全控制 index.html 的内容。可以通过多种方式进行修改。

在客户端,当内容为静态内容(如 <viewport> 标签)时,您可以编辑 frontend/index.html。在服务端,您可以进行需要动态服务端内容的更改,或者当更倾向于使用 Java 语法时。例如,可以通过启用 @PWA 内置功能,使应用程序支持安装。

对于 AppShellSettings API 所覆盖的情况,可以实现 AppShellConfigurator,或者通过注解的方式实现。对于需要高级修改文档结构的场景,可以配置 IndexHtmlRequestListener

应用程序 Shell 模板

Vaadin servlet 使用 frontend/index.html 文件作为模板来生成 bootstrap 页面响应。Servlet 会处理模板,并注入以下信息:

  • <base href='./relative/to/root'>:Vaadin 根据当前请求路径计算到应用根路径的相对路径。这样可以确保视图模板中的相对链接能够正确运行。

  • 打包后的脚本:Vaadin 会自动添加由 frontend/index.ts 文件生成的打包优化脚本。它使用内置的 Vite 实例,作为模块打包工具,Vite 已包含在 vaadin-maven-plugin 中。因此,frontend/index.html 模板无需显式包含 index.ts 脚本,或者 index.js 脚本。

Tip
frontend 目录路径可以通过在执行 vaadin-maven-plugin 的 Maven 目标 prepare-frontendbuild-frontend 时,提供属性 vaadin.frontend.frontend.folder 来更改。

默认模板与入口点

如果 frontend 文件夹下缺少 index.htmlindex.ts 文件,vaadin-maven-plugin 会在 target 文件夹中自动生成对应的默认文件。在此情况下,应用程序仅使用服务端路由。您可以通过将这些文件移入 frontend 文件夹中来对其进行控制。默认情况下,这些文件类似如下:

Source code
默认 index.html
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8" />
  <meta name="viewport" content="width=device-width, initial-scale=1" />
  <style>
    body, #outlet {
      height: 100vh;
      width: 100vw;
      margin: 0;
    }
  </style>
  <!-- index.ts is included here automatically (either by the dev server or during the build) -->
</head>
<body>
  <!-- vaadin-router in index.ts needs an outlet for displaying the views -->
  <div id="outlet"></div>
</body>
</html>
Source code
默认 index.ts
// import Vaadin client-router to handle client-side and server-side navigation
import { Router } from '@vaadin/router';

// import Flow module to enable navigation to Vaadin server-side views
import { Flow } from '@vaadin/flow-frontend';

const {serverSideRoutes} = new Flow({
  imports: () => import('../target/frontend/generated-flow-imports')
});

const routes = [
  // for client-side, place routes below

  // for server-side, the next magic line sends all unmatched routes:
  ...serverSideRoutes // IMPORTANT: this must be the last entry in the array
];

// The Vaadin router needs an outlet in the index.html page to display views
export const router = new Router(document.querySelector('#outlet'));
router.setRoutes(routes);

这里是自定义应用程序 shell 的最佳位置,例如添加统计分析标签。

Source code
index.html
...
<head>
  <title>My App</title>
</head>
<body>
  ...
  <!-- Google Analytics -->
  <script>
    (function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){
    (i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o),
    m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m)
    })(window,document,'script','http://www.google-analytics.com/analytics.js','ga');

    ga('create', 'UA-XXXXX-Y', 'auto');
    ga('send', 'my-app-bootstrap');
  </script>
</body>

运行时自定义应用程序 Shell

您可以使用几种方法在运行时自定义应用程序 shell。它们会在以下各小节中介绍。

AppShellConfigurator 接口

在 Java 代码中,如需在引导过程中添加动态内容,应该使用 AppShellConfigurator 标记接口,而不是直接编辑 index.html 文件。

整个 Vaadin 应用必须只有一个应用程序 shell,因此不能有多个类实现 AppShellConfigurator。在多模块应用中,实现 AppShellConfigurator 的类不能放在启动该应用的 JAR 或 WAR 文件所依赖的 JAR 文件内。

Note
AppShellConfigurator 替代了已废弃的 PageConfigurator 接口。

AppShellConfigurator.configurePage() 方法

通过重写 configurePage() 方法,并通过调用以下 AppShellSettings 方法,可以向 index.html 模板添加内容:

  • AppShellSettings.setViewport() 设置 viewport 值。将替换 index.html 模板中的 viewport。

  • AppShellSettings.setPageTitle() 设置初始页面标题。将替换模板中的 title 标签。

  • AppShellSettings.setBodySize() 配置 body 的宽度和高度。

  • AppShellSettings.addMetaTag() 向 head 添加 Meta 标签。

  • AppShellSettings.addInlineFromFile() 包含资源文件内容。

  • AppShellSettings.addInlineWithContents() 添加任意内容。

  • AppShellSettings.addLink() 向 head 部分添加 link。

  • AppShellSettings.addFavIcon() 配置 favicon。

  • AppShellSettings.getLoadingIndicatorConfiguration() 在使用传统引导方式时配置加载指示器。此方法已弃用:详见代码示例后的说明。

  • AppShellSettings.getReconnectDialogConfiguration() 在使用传统引导方式时配置重连对话框。此方法已弃用:详见代码示例后的说明。

  • AppShellSettings.getPushConfiguration() 在使用传统引导方式时自定义推送机制。此方法已弃用:详见代码示例后的说明。

Source code
Java
public class AppShell implements AppShellConfigurator {

  @Override
  public void configurePage(AppShellSettings settings) {
    settings.setViewport("width=device-width, initial-scale=1");
    settings.setPageTitle("A Cool Vaadin App");
    settings.setBodySize("100vw", "100vh");
    settings.addMetaTag("author", "bunny");
    settings.addFavIcon("icon", "icons/icon-192.png", "192x192");
    settings.addLink("shortcut icon", "icons/favicon.ico");

    settings.addInlineFromFile(
            TargetElement.BODY,
            Position.APPEND,
            "custom.html",
            Wrapping.AUTOMATIC);
    settings.addInlineWithContents(Position.PREPEND,
            "console.log(\"foo\");", Wrapping.JAVASCRIPT);
  }
}
Source code
ServiceListener.java

Java 注解

Vaadin 提供了一组注解来修改应用程序 shell。

  • @Viewport 用于设置 viewport 值。

  • @PageTitle 用于设置初始页面标题。

  • @BodySize 用于配置 body 大小。

  • @Meta 用于向 head 添加 meta 标签。

  • @Inline 用于将资源文件内容包含到 index.html 中。

  • @PWA 用于定义应用程序的 PWA 属性。

  • @Push 用于配置服务端推送。

Source code
Java
@Viewport("width=device-width, initial-scale=1")
@PageTitle("A Cool Vaadin App")
@BodySize(height = "100vh", width = "100vw")
@Meta(name = "author", content = "bunny")
@Inline(wrapping = Wrapping.AUTOMATIC,
        position = Position.APPEND,
        target = TargetElement.BODY,
        value = "custom.html")
@PWA(name = "Cool Vaadin App", shortName = "my-app")
@Push(value = PushMode.MANUAL, transport = Transport.WEBSOCKET)
public class AppShell implements AppShellConfigurator {
}

AppShellConfigurator.configurePage() 中的修改优先于等效注解。注解不能涵盖通过重写 AppShellConfigurator.configurePage() 方法实现的所有场景。

服务端无效响应后强制页面重载

如果 XHR 响应无法解析为 JSON,Vaadin 会在响应文本的任意位置查找字符串 “Vaadin-Refresh”。如果找到了,Vaadin 会重载页面,而不是显示错误信息。通常这类响应由第三方服务器返回,此时您需要在该服务器返回的 HTML 页面的 Meta 标签中添加刷新令牌。

带 Meta 标签的 HTML 响应示例

Source code
XML
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width">
  <meta name="refresh" content="Vaadin-Refresh">
  <title>Vaadin App</title>
</head>
<body>
  <h1>Invalid server response</h1>
</body>
</html>

但有时候由于代理或防火墙超时,客户端会被分配一个新会话,而客户端对此并不知情。这种情况下,您需要在 Vaadin bootstrap 页面中添加刷新令牌。

Source code
Java
public class AppShell implements AppShellConfigurator {

  @Override
  public void configurePage(AppShellSettings settings) {
    settings.addMetaTag("refresh", "Vaadin-Refresh");
  }
}

IndexHtmlRequestListener 接口

针对前文未覆盖的高级场景,可以通过 IndexHtmlRequestListener 修改内容。

实现的监听器应在 VaadinService 初始化时,通过 ServiceInitEvent 添加。关于如何使用 Vaadin ServiceInitListeners 的详细说明,请参见 ServiceInitListener 教程

以下示例可动态更改 body 的 class:

Source code
Java
public class MyIndexHtmlRequestListener implements
        IndexHtmlRequestListener {

    @Override
    public void modifyIndexHtmlResponse(
            IndexHtmlResponse indexHtmlResponse) {

        Document document = indexHtmlResponse.getDocument();
        Element body = document.body();
        body.classNames(computeBodyClassNames());
    }

    private Set<String> computeBodyClassNames() {
        // Introduce some logic to dynamically change the body class
        return Collections.singleton("my-className");
    }
}

这也可以通过名为 useDeprecatedV14Bootstrapping 的 servlet 容器部署属性实现。请注意,只有在前端构建工具使用 webpack 时才支持该选项,若应用使用 Vite(默认)则不支持。可通过对应的 feature flag 启用 webpack。详细了解启用办法请查阅 Hot Deploy & Live Reload 文档页面。

38A2B3F1-CC6B-45DF-8CB8-9DEF23BA53B0