创建主视图
应用程序通常具有带菜单栏的主视图,其中显示了一系列子视图。当用户单击菜单项时,就会显示相应的子视图。
[classname]`AppLayout`组件使您能够创建带有页眉、菜单和内容区域的典型主视图。
它使用完整的路由和导航,比手动连接更容易设置。这使其响应屏幕尺寸和方向的变化,并能够适应桌面和移动浏览器。
[classname]`AppLayout`高度灵活,允许多种主视图的布局,可具有水平菜单或垂直菜单。 菜单可以静态显示或通过单击打开,并具有许多可自定义的元素。 查看设计系统文档了解功能展示。
默认情况下,使用http://start.vaadin.com[Vaadin Start]创建的初始项目会使用[classname]`AppLayout`创建主视图。
主视图
主视图通过扩展[classname]`AppLayout`并在构造函数中设置元素来实现。 您需要为页眉和抽屉(drawer)设置内容。 应用菜单可以位于页眉中横向显示(导航栏),也可以垂直显示在抽屉区域。
以下示例演示如何创建一个带有垂直菜单的抽屉视图,以及在导航栏中显示打开和关闭抽屉的按钮:
Source code
MainView.java
package com.vaadin.demo.flow.application.mainview;
import java.util.Optional;
import com.vaadin.flow.component.Component;
import com.vaadin.flow.component.ComponentUtil;
import com.vaadin.flow.component.applayout.AppLayout;
import com.vaadin.flow.component.applayout.DrawerToggle;
import com.vaadin.flow.component.html.Image;
import com.vaadin.flow.component.html.H1;
import com.vaadin.flow.component.orderedlayout.FlexComponent;
import com.vaadin.flow.component.orderedlayout.HorizontalLayout;
import com.vaadin.flow.component.orderedlayout.VerticalLayout;
import com.vaadin.flow.component.tabs.Tab;
import com.vaadin.flow.component.tabs.Tabs;
import com.vaadin.flow.component.tabs.TabsVariant;
import com.vaadin.flow.router.PageTitle;
import com.vaadin.flow.router.RouterLink;
/**
* The main view is a top-level placeholder for other views.
*/
@CssImport("./styles/views/main/main-view.css")
@JsModule("./styles/shared-styles.js")
public class MainView extends AppLayout {
private final Tabs menu;
private H1 viewTitle;
public MainView() {
// Use the drawer for the menu
setPrimarySection(Section.DRAWER);
// Make the nav bar a header
addToNavbar(true, createHeaderContent());
// Put the menu in the drawer
menu = createMenu();
addToDrawer(createDrawerContent(menu));
}
private Component createHeaderContent() {
HorizontalLayout layout = new HorizontalLayout();
// Configure styling for the header
layout.setId("header");
layout.getThemeList().set("dark", true);
layout.setWidthFull();
layout.setSpacing(false);
layout.setAlignItems(FlexComponent.Alignment.CENTER);
// Have the drawer toggle button on the left
layout.add(new DrawerToggle());
// Placeholder for the title of the current view.
// The title will be set after navigation.
viewTitle = new H1();
layout.add(viewTitle);
// A user icon
layout.add(new Image("images/user.svg", "Avatar"));
return layout;
}
private Component createDrawerContent(Tabs menu) {
VerticalLayout layout = new VerticalLayout();
// Configure styling for the drawer
layout.setSizeFull();
layout.setPadding(false);
layout.setSpacing(false);
layout.getThemeList().set("spacing-s", true);
layout.setAlignItems(FlexComponent.Alignment.STRETCH);
// Have a drawer header with an application logo
HorizontalLayout logoLayout = new HorizontalLayout();
logoLayout.setId("logo");
logoLayout.setAlignItems(FlexComponent.Alignment.CENTER);
logoLayout.add(new Image("images/logo.png", "My Project logo"));
logoLayout.add(new H1("My Project"));
// Display the logo and the menu in the drawer
layout.add(logoLayout, menu);
return layout;
}
private Tabs createMenu() {
final Tabs tabs = new Tabs();
tabs.setOrientation(Tabs.Orientation.VERTICAL);
tabs.addThemeVariants(TabsVariant.LUMO_MINIMAL);
tabs.setId("tabs");
tabs.add(createMenuItems());
return tabs;
}
private Component[] createMenuItems() {
return new Tab[] { createTab("Hello World", HelloWorldView.class),
createTab("Card List", CardListView.class),
createTab("About", AboutView.class) };
}
private static Tab createTab(String text,
Class<? extends Component> navigationTarget) {
final Tab tab = new Tab();
tab.add(new RouterLink(text, navigationTarget));
ComponentUtil.setData(tab, Class.class, navigationTarget);
return tab;
}
@Override
protected void afterNavigation() {
super.afterNavigation();
// Select the tab corresponding to currently shown view
getTabForComponent(getContent()).ifPresent(menu::setSelectedTab);
// Set the view title in the header
viewTitle.setText(getCurrentPageTitle());
}
private Optional<Tab> getTabForComponent(Component component) {
return menu.getChildren()
.filter(tab -> ComponentUtil.getData(tab, Class.class)
.equals(component.getClass()))
.findFirst().map(Tab.class::cast);
}
private String getCurrentPageTitle() {
return getContent().getClass().getAnnotation(PageTitle.class).value();
}
}
您可以通过带有`@CssImport`标记的注解指定CSS文件路径来自定义样式。 样式表应放置在项目中的`frontend`文件夹内。 同样,您也可以使用`JsModule`注解包含JavaScript代码。 在此示例中,包含的JavaScript文件设置了一些共享自定义样式。 请参考加载资源,了解有关导入CSS和JavaScript资源的更多详细信息。
主视图本身未定义路由,因为它仅作为实际内容视图的框架而存在。
创建页眉
[classname]`AppLayout`的导航栏是一个横向元素,可以包含任何组件,比如页眉或横向菜单。 使用项目构建工具创建的应用程序会使用此导航栏构建包含菜单切换按钮、视图标题及用户图像的页眉。
您可以使用[classname]`DrawerToggle`组件来切换显示抽屉视图。
以下示例创建了这样的页眉,在主视图类中使用了`viewTitle`成员:
Source code
MainView.java
package com.vaadin.demo.flow.application.mainview;
import java.util.Optional;
import com.vaadin.flow.component.Component;
import com.vaadin.flow.component.ComponentUtil;
import com.vaadin.flow.component.applayout.AppLayout;
import com.vaadin.flow.component.applayout.DrawerToggle;
import com.vaadin.flow.component.html.Image;
import com.vaadin.flow.component.html.H1;
import com.vaadin.flow.component.orderedlayout.FlexComponent;
import com.vaadin.flow.component.orderedlayout.HorizontalLayout;
import com.vaadin.flow.component.orderedlayout.VerticalLayout;
import com.vaadin.flow.component.tabs.Tab;
import com.vaadin.flow.component.tabs.Tabs;
import com.vaadin.flow.component.tabs.TabsVariant;
import com.vaadin.flow.router.PageTitle;
import com.vaadin.flow.router.RouterLink;
/**
* The main view is a top-level placeholder for other views.
*/
@CssImport("./styles/views/main/main-view.css")
@JsModule("./styles/shared-styles.js")
public class MainView extends AppLayout {
private final Tabs menu;
private H1 viewTitle;
public MainView() {
// Use the drawer for the menu
setPrimarySection(Section.DRAWER);
// Make the nav bar a header
addToNavbar(true, createHeaderContent());
// Put the menu in the drawer
menu = createMenu();
addToDrawer(createDrawerContent(menu));
}
private Component createHeaderContent() {
HorizontalLayout layout = new HorizontalLayout();
// Configure styling for the header
layout.setId("header");
layout.getThemeList().set("dark", true);
layout.setWidthFull();
layout.setSpacing(false);
layout.setAlignItems(FlexComponent.Alignment.CENTER);
// Have the drawer toggle button on the left
layout.add(new DrawerToggle());
// Placeholder for the title of the current view.
// The title will be set after navigation.
viewTitle = new H1();
layout.add(viewTitle);
// A user icon
layout.add(new Image("images/user.svg", "Avatar"));
return layout;
}
private Component createDrawerContent(Tabs menu) {
VerticalLayout layout = new VerticalLayout();
// Configure styling for the drawer
layout.setSizeFull();
layout.setPadding(false);
layout.setSpacing(false);
layout.getThemeList().set("spacing-s", true);
layout.setAlignItems(FlexComponent.Alignment.STRETCH);
// Have a drawer header with an application logo
HorizontalLayout logoLayout = new HorizontalLayout();
logoLayout.setId("logo");
logoLayout.setAlignItems(FlexComponent.Alignment.CENTER);
logoLayout.add(new Image("images/logo.png", "My Project logo"));
logoLayout.add(new H1("My Project"));
// Display the logo and the menu in the drawer
layout.add(logoLayout, menu);
return layout;
}
private Tabs createMenu() {
final Tabs tabs = new Tabs();
tabs.setOrientation(Tabs.Orientation.VERTICAL);
tabs.addThemeVariants(TabsVariant.LUMO_MINIMAL);
tabs.setId("tabs");
tabs.add(createMenuItems());
return tabs;
}
private Component[] createMenuItems() {
return new Tab[] { createTab("Hello World", HelloWorldView.class),
createTab("Card List", CardListView.class),
createTab("About", AboutView.class) };
}
private static Tab createTab(String text,
Class<? extends Component> navigationTarget) {
final Tab tab = new Tab();
tab.add(new RouterLink(text, navigationTarget));
ComponentUtil.setData(tab, Class.class, navigationTarget);
return tab;
}
@Override
protected void afterNavigation() {
super.afterNavigation();
// Select the tab corresponding to currently shown view
getTabForComponent(getContent()).ifPresent(menu::setSelectedTab);
// Set the view title in the header
viewTitle.setText(getCurrentPageTitle());
}
private Optional<Tab> getTabForComponent(Component component) {
return menu.getChildren()
.filter(tab -> ComponentUtil.getData(tab, Class.class)
.equals(component.getClass()))
.findFirst().map(Tab.class::cast);
}
private String getCurrentPageTitle() {
return getContent().getClass().getAnnotation(PageTitle.class).value();
}
}
创建菜单
菜单可以显示在导航栏中,也可以显示在抽屉视图中。 项目构建工具创建的应用程序菜单默认显示在抽屉视图中,这里将对此进行描述。
Source code
MainView.java
package com.vaadin.demo.flow.application.mainview;
import java.util.Optional;
import com.vaadin.flow.component.Component;
import com.vaadin.flow.component.ComponentUtil;
import com.vaadin.flow.component.applayout.AppLayout;
import com.vaadin.flow.component.applayout.DrawerToggle;
import com.vaadin.flow.component.html.Image;
import com.vaadin.flow.component.html.H1;
import com.vaadin.flow.component.orderedlayout.FlexComponent;
import com.vaadin.flow.component.orderedlayout.HorizontalLayout;
import com.vaadin.flow.component.orderedlayout.VerticalLayout;
import com.vaadin.flow.component.tabs.Tab;
import com.vaadin.flow.component.tabs.Tabs;
import com.vaadin.flow.component.tabs.TabsVariant;
import com.vaadin.flow.router.PageTitle;
import com.vaadin.flow.router.RouterLink;
/**
* The main view is a top-level placeholder for other views.
*/
@CssImport("./styles/views/main/main-view.css")
@JsModule("./styles/shared-styles.js")
public class MainView extends AppLayout {
private final Tabs menu;
private H1 viewTitle;
public MainView() {
// Use the drawer for the menu
setPrimarySection(Section.DRAWER);
// Make the nav bar a header
addToNavbar(true, createHeaderContent());
// Put the menu in the drawer
menu = createMenu();
addToDrawer(createDrawerContent(menu));
}
private Component createHeaderContent() {
HorizontalLayout layout = new HorizontalLayout();
// Configure styling for the header
layout.setId("header");
layout.getThemeList().set("dark", true);
layout.setWidthFull();
layout.setSpacing(false);
layout.setAlignItems(FlexComponent.Alignment.CENTER);
// Have the drawer toggle button on the left
layout.add(new DrawerToggle());
// Placeholder for the title of the current view.
// The title will be set after navigation.
viewTitle = new H1();
layout.add(viewTitle);
// A user icon
layout.add(new Image("images/user.svg", "Avatar"));
return layout;
}
private Component createDrawerContent(Tabs menu) {
VerticalLayout layout = new VerticalLayout();
// Configure styling for the drawer
layout.setSizeFull();
layout.setPadding(false);
layout.setSpacing(false);
layout.getThemeList().set("spacing-s", true);
layout.setAlignItems(FlexComponent.Alignment.STRETCH);
// Have a drawer header with an application logo
HorizontalLayout logoLayout = new HorizontalLayout();
logoLayout.setId("logo");
logoLayout.setAlignItems(FlexComponent.Alignment.CENTER);
logoLayout.add(new Image("images/logo.png", "My Project logo"));
logoLayout.add(new H1("My Project"));
// Display the logo and the menu in the drawer
layout.add(logoLayout, menu);
return layout;
}
private Tabs createMenu() {
final Tabs tabs = new Tabs();
tabs.setOrientation(Tabs.Orientation.VERTICAL);
tabs.addThemeVariants(TabsVariant.LUMO_MINIMAL);
tabs.setId("tabs");
tabs.add(createMenuItems());
return tabs;
}
private Component[] createMenuItems() {
return new Tab[] { createTab("Hello World", HelloWorldView.class),
createTab("Card List", CardListView.class),
createTab("About", AboutView.class) };
}
private static Tab createTab(String text,
Class<? extends Component> navigationTarget) {
final Tab tab = new Tab();
tab.add(new RouterLink(text, navigationTarget));
ComponentUtil.setData(tab, Class.class, navigationTarget);
return tab;
}
@Override
protected void afterNavigation() {
super.afterNavigation();
// Select the tab corresponding to currently shown view
getTabForComponent(getContent()).ifPresent(menu::setSelectedTab);
// Set the view title in the header
viewTitle.setText(getCurrentPageTitle());
}
private Optional<Tab> getTabForComponent(Component component) {
return menu.getChildren()
.filter(tab -> ComponentUtil.getData(tab, Class.class)
.equals(component.getClass()))
.findFirst().map(Tab.class::cast);
}
private String getCurrentPageTitle() {
return getContent().getClass().getAnnotation(PageTitle.class).value();
}
}
实际菜单是一个垂直的[classname]Tabs`组件。
其中包含多个[classname]`Tab`组件。
每个选项卡包含一个[classname]`RouterLink,用于导航到对应的视图。
Source code
MainView.java
package com.vaadin.demo.flow.application.mainview;
import java.util.Optional;
import com.vaadin.flow.component.Component;
import com.vaadin.flow.component.ComponentUtil;
import com.vaadin.flow.component.applayout.AppLayout;
import com.vaadin.flow.component.applayout.DrawerToggle;
import com.vaadin.flow.component.html.Image;
import com.vaadin.flow.component.html.H1;
import com.vaadin.flow.component.orderedlayout.FlexComponent;
import com.vaadin.flow.component.orderedlayout.HorizontalLayout;
import com.vaadin.flow.component.orderedlayout.VerticalLayout;
import com.vaadin.flow.component.tabs.Tab;
import com.vaadin.flow.component.tabs.Tabs;
import com.vaadin.flow.component.tabs.TabsVariant;
import com.vaadin.flow.router.PageTitle;
import com.vaadin.flow.router.RouterLink;
/**
* The main view is a top-level placeholder for other views.
*/
@CssImport("./styles/views/main/main-view.css")
@JsModule("./styles/shared-styles.js")
public class MainView extends AppLayout {
private final Tabs menu;
private H1 viewTitle;
public MainView() {
// Use the drawer for the menu
setPrimarySection(Section.DRAWER);
// Make the nav bar a header
addToNavbar(true, createHeaderContent());
// Put the menu in the drawer
menu = createMenu();
addToDrawer(createDrawerContent(menu));
}
private Component createHeaderContent() {
HorizontalLayout layout = new HorizontalLayout();
// Configure styling for the header
layout.setId("header");
layout.getThemeList().set("dark", true);
layout.setWidthFull();
layout.setSpacing(false);
layout.setAlignItems(FlexComponent.Alignment.CENTER);
// Have the drawer toggle button on the left
layout.add(new DrawerToggle());
// Placeholder for the title of the current view.
// The title will be set after navigation.
viewTitle = new H1();
layout.add(viewTitle);
// A user icon
layout.add(new Image("images/user.svg", "Avatar"));
return layout;
}
private Component createDrawerContent(Tabs menu) {
VerticalLayout layout = new VerticalLayout();
// Configure styling for the drawer
layout.setSizeFull();
layout.setPadding(false);
layout.setSpacing(false);
layout.getThemeList().set("spacing-s", true);
layout.setAlignItems(FlexComponent.Alignment.STRETCH);
// Have a drawer header with an application logo
HorizontalLayout logoLayout = new HorizontalLayout();
logoLayout.setId("logo");
logoLayout.setAlignItems(FlexComponent.Alignment.CENTER);
logoLayout.add(new Image("images/logo.png", "My Project logo"));
logoLayout.add(new H1("My Project"));
// Display the logo and the menu in the drawer
layout.add(logoLayout, menu);
return layout;
}
private Tabs createMenu() {
final Tabs tabs = new Tabs();
tabs.setOrientation(Tabs.Orientation.VERTICAL);
tabs.addThemeVariants(TabsVariant.LUMO_MINIMAL);
tabs.setId("tabs");
tabs.add(createMenuItems());
return tabs;
}
private Component[] createMenuItems() {
return new Tab[] { createTab("Hello World", HelloWorldView.class),
createTab("Card List", CardListView.class),
createTab("About", AboutView.class) };
}
private static Tab createTab(String text,
Class<? extends Component> navigationTarget) {
final Tab tab = new Tab();
tab.add(new RouterLink(text, navigationTarget));
ComponentUtil.setData(tab, Class.class, navigationTarget);
return tab;
}
@Override
protected void afterNavigation() {
super.afterNavigation();
// Select the tab corresponding to currently shown view
getTabForComponent(getContent()).ifPresent(menu::setSelectedTab);
// Set the view title in the header
viewTitle.setText(getCurrentPageTitle());
}
private Optional<Tab> getTabForComponent(Component component) {
return menu.getChildren()
.filter(tab -> ComponentUtil.getData(tab, Class.class)
.equals(component.getClass()))
.findFirst().map(Tab.class::cast);
}
private String getCurrentPageTitle() {
return getContent().getClass().getAnnotation(PageTitle.class).value();
}
}
导航处理
当用户导航到某个视图时,应通过设置对应选项卡为“选中”状态来突出显示此视图。 您还可在页眉中设置视图标题。
您可以通过覆盖[classname]`AppLayout`中的[methodname]`afterNavigation()`方法同时实现以上两个功能,如下所示:
Source code
MainView.java
package com.vaadin.demo.flow.application.mainview;
import java.util.Optional;
import com.vaadin.flow.component.Component;
import com.vaadin.flow.component.ComponentUtil;
import com.vaadin.flow.component.applayout.AppLayout;
import com.vaadin.flow.component.applayout.DrawerToggle;
import com.vaadin.flow.component.html.Image;
import com.vaadin.flow.component.html.H1;
import com.vaadin.flow.component.orderedlayout.FlexComponent;
import com.vaadin.flow.component.orderedlayout.HorizontalLayout;
import com.vaadin.flow.component.orderedlayout.VerticalLayout;
import com.vaadin.flow.component.tabs.Tab;
import com.vaadin.flow.component.tabs.Tabs;
import com.vaadin.flow.component.tabs.TabsVariant;
import com.vaadin.flow.router.PageTitle;
import com.vaadin.flow.router.RouterLink;
/**
* The main view is a top-level placeholder for other views.
*/
@CssImport("./styles/views/main/main-view.css")
@JsModule("./styles/shared-styles.js")
public class MainView extends AppLayout {
private final Tabs menu;
private H1 viewTitle;
public MainView() {
// Use the drawer for the menu
setPrimarySection(Section.DRAWER);
// Make the nav bar a header
addToNavbar(true, createHeaderContent());
// Put the menu in the drawer
menu = createMenu();
addToDrawer(createDrawerContent(menu));
}
private Component createHeaderContent() {
HorizontalLayout layout = new HorizontalLayout();
// Configure styling for the header
layout.setId("header");
layout.getThemeList().set("dark", true);
layout.setWidthFull();
layout.setSpacing(false);
layout.setAlignItems(FlexComponent.Alignment.CENTER);
// Have the drawer toggle button on the left
layout.add(new DrawerToggle());
// Placeholder for the title of the current view.
// The title will be set after navigation.
viewTitle = new H1();
layout.add(viewTitle);
// A user icon
layout.add(new Image("images/user.svg", "Avatar"));
return layout;
}
private Component createDrawerContent(Tabs menu) {
VerticalLayout layout = new VerticalLayout();
// Configure styling for the drawer
layout.setSizeFull();
layout.setPadding(false);
layout.setSpacing(false);
layout.getThemeList().set("spacing-s", true);
layout.setAlignItems(FlexComponent.Alignment.STRETCH);
// Have a drawer header with an application logo
HorizontalLayout logoLayout = new HorizontalLayout();
logoLayout.setId("logo");
logoLayout.setAlignItems(FlexComponent.Alignment.CENTER);
logoLayout.add(new Image("images/logo.png", "My Project logo"));
logoLayout.add(new H1("My Project"));
// Display the logo and the menu in the drawer
layout.add(logoLayout, menu);
return layout;
}
private Tabs createMenu() {
final Tabs tabs = new Tabs();
tabs.setOrientation(Tabs.Orientation.VERTICAL);
tabs.addThemeVariants(TabsVariant.LUMO_MINIMAL);
tabs.setId("tabs");
tabs.add(createMenuItems());
return tabs;
}
private Component[] createMenuItems() {
return new Tab[] { createTab("Hello World", HelloWorldView.class),
createTab("Card List", CardListView.class),
createTab("About", AboutView.class) };
}
private static Tab createTab(String text,
Class<? extends Component> navigationTarget) {
final Tab tab = new Tab();
tab.add(new RouterLink(text, navigationTarget));
ComponentUtil.setData(tab, Class.class, navigationTarget);
return tab;
}
@Override
protected void afterNavigation() {
super.afterNavigation();
// Select the tab corresponding to currently shown view
getTabForComponent(getContent()).ifPresent(menu::setSelectedTab);
// Set the view title in the header
viewTitle.setText(getCurrentPageTitle());
}
private Optional<Tab> getTabForComponent(Component component) {
return menu.getChildren()
.filter(tab -> ComponentUtil.getData(tab, Class.class)
.equals(component.getClass()))
.findFirst().map(Tab.class::cast);
}
private String getCurrentPageTitle() {
return getContent().getClass().getAnnotation(PageTitle.class).value();
}
}
所选选项卡应对应于显示的内容(视图)。
您可以如下方法获取当前视图:
Source code
MainView.java
package com.vaadin.demo.flow.application.mainview;
import java.util.Optional;
import com.vaadin.flow.component.Component;
import com.vaadin.flow.component.ComponentUtil;
import com.vaadin.flow.component.applayout.AppLayout;
import com.vaadin.flow.component.applayout.DrawerToggle;
import com.vaadin.flow.component.html.Image;
import com.vaadin.flow.component.html.H1;
import com.vaadin.flow.component.orderedlayout.FlexComponent;
import com.vaadin.flow.component.orderedlayout.HorizontalLayout;
import com.vaadin.flow.component.orderedlayout.VerticalLayout;
import com.vaadin.flow.component.tabs.Tab;
import com.vaadin.flow.component.tabs.Tabs;
import com.vaadin.flow.component.tabs.TabsVariant;
import com.vaadin.flow.router.PageTitle;
import com.vaadin.flow.router.RouterLink;
/**
* The main view is a top-level placeholder for other views.
*/
@CssImport("./styles/views/main/main-view.css")
@JsModule("./styles/shared-styles.js")
public class MainView extends AppLayout {
private final Tabs menu;
private H1 viewTitle;
public MainView() {
// Use the drawer for the menu
setPrimarySection(Section.DRAWER);
// Make the nav bar a header
addToNavbar(true, createHeaderContent());
// Put the menu in the drawer
menu = createMenu();
addToDrawer(createDrawerContent(menu));
}
private Component createHeaderContent() {
HorizontalLayout layout = new HorizontalLayout();
// Configure styling for the header
layout.setId("header");
layout.getThemeList().set("dark", true);
layout.setWidthFull();
layout.setSpacing(false);
layout.setAlignItems(FlexComponent.Alignment.CENTER);
// Have the drawer toggle button on the left
layout.add(new DrawerToggle());
// Placeholder for the title of the current view.
// The title will be set after navigation.
viewTitle = new H1();
layout.add(viewTitle);
// A user icon
layout.add(new Image("images/user.svg", "Avatar"));
return layout;
}
private Component createDrawerContent(Tabs menu) {
VerticalLayout layout = new VerticalLayout();
// Configure styling for the drawer
layout.setSizeFull();
layout.setPadding(false);
layout.setSpacing(false);
layout.getThemeList().set("spacing-s", true);
layout.setAlignItems(FlexComponent.Alignment.STRETCH);
// Have a drawer header with an application logo
HorizontalLayout logoLayout = new HorizontalLayout();
logoLayout.setId("logo");
logoLayout.setAlignItems(FlexComponent.Alignment.CENTER);
logoLayout.add(new Image("images/logo.png", "My Project logo"));
logoLayout.add(new H1("My Project"));
// Display the logo and the menu in the drawer
layout.add(logoLayout, menu);
return layout;
}
private Tabs createMenu() {
final Tabs tabs = new Tabs();
tabs.setOrientation(Tabs.Orientation.VERTICAL);
tabs.addThemeVariants(TabsVariant.LUMO_MINIMAL);
tabs.setId("tabs");
tabs.add(createMenuItems());
return tabs;
}
private Component[] createMenuItems() {
return new Tab[] { createTab("Hello World", HelloWorldView.class),
createTab("Card List", CardListView.class),
createTab("About", AboutView.class) };
}
private static Tab createTab(String text,
Class<? extends Component> navigationTarget) {
final Tab tab = new Tab();
tab.add(new RouterLink(text, navigationTarget));
ComponentUtil.setData(tab, Class.class, navigationTarget);
return tab;
}
@Override
protected void afterNavigation() {
super.afterNavigation();
// Select the tab corresponding to currently shown view
getTabForComponent(getContent()).ifPresent(menu::setSelectedTab);
// Set the view title in the header
viewTitle.setText(getCurrentPageTitle());
}
private Optional<Tab> getTabForComponent(Component component) {
return menu.getChildren()
.filter(tab -> ComponentUtil.getData(tab, Class.class)
.equals(component.getClass()))
.findFirst().map(Tab.class::cast);
}
private String getCurrentPageTitle() {
return getContent().getClass().getAnnotation(PageTitle.class).value();
}
}
可通过视图上标记的`PageTitle`注解来获取视图的标题(见创建视图)。
Source code
MainView.java
package com.vaadin.demo.flow.application.mainview;
import java.util.Optional;
import com.vaadin.flow.component.Component;
import com.vaadin.flow.component.ComponentUtil;
import com.vaadin.flow.component.applayout.AppLayout;
import com.vaadin.flow.component.applayout.DrawerToggle;
import com.vaadin.flow.component.html.Image;
import com.vaadin.flow.component.html.H1;
import com.vaadin.flow.component.orderedlayout.FlexComponent;
import com.vaadin.flow.component.orderedlayout.HorizontalLayout;
import com.vaadin.flow.component.orderedlayout.VerticalLayout;
import com.vaadin.flow.component.tabs.Tab;
import com.vaadin.flow.component.tabs.Tabs;
import com.vaadin.flow.component.tabs.TabsVariant;
import com.vaadin.flow.router.PageTitle;
import com.vaadin.flow.router.RouterLink;
/**
* The main view is a top-level placeholder for other views.
*/
@CssImport("./styles/views/main/main-view.css")
@JsModule("./styles/shared-styles.js")
public class MainView extends AppLayout {
private final Tabs menu;
private H1 viewTitle;
public MainView() {
// Use the drawer for the menu
setPrimarySection(Section.DRAWER);
// Make the nav bar a header
addToNavbar(true, createHeaderContent());
// Put the menu in the drawer
menu = createMenu();
addToDrawer(createDrawerContent(menu));
}
private Component createHeaderContent() {
HorizontalLayout layout = new HorizontalLayout();
// Configure styling for the header
layout.setId("header");
layout.getThemeList().set("dark", true);
layout.setWidthFull();
layout.setSpacing(false);
layout.setAlignItems(FlexComponent.Alignment.CENTER);
// Have the drawer toggle button on the left
layout.add(new DrawerToggle());
// Placeholder for the title of the current view.
// The title will be set after navigation.
viewTitle = new H1();
layout.add(viewTitle);
// A user icon
layout.add(new Image("images/user.svg", "Avatar"));
return layout;
}
private Component createDrawerContent(Tabs menu) {
VerticalLayout layout = new VerticalLayout();
// Configure styling for the drawer
layout.setSizeFull();
layout.setPadding(false);
layout.setSpacing(false);
layout.getThemeList().set("spacing-s", true);
layout.setAlignItems(FlexComponent.Alignment.STRETCH);
// Have a drawer header with an application logo
HorizontalLayout logoLayout = new HorizontalLayout();
logoLayout.setId("logo");
logoLayout.setAlignItems(FlexComponent.Alignment.CENTER);
logoLayout.add(new Image("images/logo.png", "My Project logo"));
logoLayout.add(new H1("My Project"));
// Display the logo and the menu in the drawer
layout.add(logoLayout, menu);
return layout;
}
private Tabs createMenu() {
final Tabs tabs = new Tabs();
tabs.setOrientation(Tabs.Orientation.VERTICAL);
tabs.addThemeVariants(TabsVariant.LUMO_MINIMAL);
tabs.setId("tabs");
tabs.add(createMenuItems());
return tabs;
}
private Component[] createMenuItems() {
return new Tab[] { createTab("Hello World", HelloWorldView.class),
createTab("Card List", CardListView.class),
createTab("About", AboutView.class) };
}
private static Tab createTab(String text,
Class<? extends Component> navigationTarget) {
final Tab tab = new Tab();
tab.add(new RouterLink(text, navigationTarget));
ComponentUtil.setData(tab, Class.class, navigationTarget);
return tab;
}
@Override
protected void afterNavigation() {
super.afterNavigation();
// Select the tab corresponding to currently shown view
getTabForComponent(getContent()).ifPresent(menu::setSelectedTab);
// Set the view title in the header
viewTitle.setText(getCurrentPageTitle());
}
private Optional<Tab> getTabForComponent(Component component) {
return menu.getChildren()
.filter(tab -> ComponentUtil.getData(tab, Class.class)
.equals(component.getClass()))
.findFirst().map(Tab.class::cast);
}
private String getCurrentPageTitle() {
return getContent().getClass().getAnnotation(PageTitle.class).value();
}
}
同样的标题将自动设置为浏览器页面标题,因此无需另行处理。
创建视图
与其他视图一样,要在[classname]AppLayout`中显示的视图也需要使用@Route`注解定义路由。
路由需通过`layout`参数连接到主视图,传递主视图的类对象。
Source code
HelloWorldView.java
package com.vaadin.demo.flow.application.mainview;
import com.vaadin.flow.component.button.Button;
import com.vaadin.flow.component.notification.Notification;
import com.vaadin.flow.component.orderedlayout.HorizontalLayout;
import com.vaadin.flow.component.textfield.TextField;
import com.vaadin.flow.router.Route;
import com.vaadin.flow.router.PageTitle;
import com.vaadin.flow.router.RouteAlias;
@Route(value = "hello", layout = MainView.class)
@PageTitle("Hello World")
@CssImport("./styles/views/helloworld/hello-world-view.css")
@RouteAlias(value = "", layout = MainView.class)
public class HelloWorldView extends HorizontalLayout {
private TextField name;
private Button sayHello;
public HelloWorldView() {
setId("hello-world-view");
name = new TextField("Your name");
sayHello = new Button("Say hello");
add(name, sayHello);
setVerticalComponentAlignment(Alignment.END, name, sayHello);
// Handle clicks
sayHello.addClickListener(e -> {
Notification.show("Hello " + name.getValue());
});
}
}
主视图本身没有定义路由。 为了设置主视图的入口点以及通常是整个应用程序的入口点,需要定义一个默认视图。 您可以通过使用路由别名(route alias)实现这个功能,如默认视图所述。
页面标题
您可以使用`@PageTitle`注解来设置浏览器窗口或选项卡显示的标题。
Source code
HelloWorldView.java
package com.vaadin.demo.flow.application.mainview;
import com.vaadin.flow.component.button.Button;
import com.vaadin.flow.component.notification.Notification;
import com.vaadin.flow.component.orderedlayout.HorizontalLayout;
import com.vaadin.flow.component.textfield.TextField;
import com.vaadin.flow.router.Route;
import com.vaadin.flow.router.PageTitle;
import com.vaadin.flow.router.RouteAlias;
@Route(value = "hello", layout = MainView.class)
@PageTitle("Hello World")
@CssImport("./styles/views/helloworld/hello-world-view.css")
@RouteAlias(value = "", layout = MainView.class)
public class HelloWorldView extends HorizontalLayout {
private TextField name;
private Button sayHello;
public HelloWorldView() {
setId("hello-world-view");
name = new TextField("Your name");
sayHello = new Button("Say hello");
add(name, sayHello);
setVerticalComponentAlignment(Alignment.END, name, sayHello);
// Handle clicks
sayHello.addClickListener(e -> {
Notification.show("Hello " + name.getValue());
});
}
}
您可以在视图的页眉或面包屑导航中使用此页面标题,如导航处理中所示。
视图的样式设计
您可以使用`@CssImport`注解定义视图的自定义样式。
Source code
HelloWorldView.java
package com.vaadin.demo.flow.application.mainview;
import com.vaadin.flow.component.button.Button;
import com.vaadin.flow.component.notification.Notification;
import com.vaadin.flow.component.orderedlayout.HorizontalLayout;
import com.vaadin.flow.component.textfield.TextField;
import com.vaadin.flow.router.Route;
import com.vaadin.flow.router.PageTitle;
import com.vaadin.flow.router.RouteAlias;
@Route(value = "hello", layout = MainView.class)
@PageTitle("Hello World")
@CssImport("./styles/views/helloworld/hello-world-view.css")
@RouteAlias(value = "", layout = MainView.class)
public class HelloWorldView extends HorizontalLayout {
private TextField name;
private Button sayHello;
public HelloWorldView() {
setId("hello-world-view");
name = new TextField("Your name");
sayHello = new Button("Say hello");
add(name, sayHello);
setVerticalComponentAlignment(Alignment.END, name, sayHello);
// Handle clicks
sayHello.addClickListener(e -> {
Notification.show("Hello " + name.getValue());
});
}
}
默认视图
大多数应用程序需要一个入口点。 您可以通过使用`@RouteAlias`为主视图路由定义别名的方法将某个视图定义为默认视图。 定义的路由别名值`value`应为空字符串,以对应根路由。
此外,您需要通过`layout`参数指定包围它的主视图,方法与上述路由设置相同。
Source code
HelloWorldView.java
package com.vaadin.demo.flow.application.mainview;
import com.vaadin.flow.component.button.Button;
import com.vaadin.flow.component.notification.Notification;
import com.vaadin.flow.component.orderedlayout.HorizontalLayout;
import com.vaadin.flow.component.textfield.TextField;
import com.vaadin.flow.router.Route;
import com.vaadin.flow.router.PageTitle;
import com.vaadin.flow.router.RouteAlias;
@Route(value = "hello", layout = MainView.class)
@PageTitle("Hello World")
@CssImport("./styles/views/helloworld/hello-world-view.css")
@RouteAlias(value = "", layout = MainView.class)
public class HelloWorldView extends HorizontalLayout {
private TextField name;
private Button sayHello;
public HelloWorldView() {
setId("hello-world-view");
name = new TextField("Your name");
sayHello = new Button("Say hello");
add(name, sayHello);
setVerticalComponentAlignment(Alignment.END, name, sayHello);
// Handle clicks
sayHello.addClickListener(e -> {
Notification.show("Hello " + name.getValue());
});
}
}
您也可以为主视图指定`/main`路由,然后为子视图定义如`/main/hello`的路由。
完成视图
除此之外,在[classname]`AppLayout`中显示的视图与任何其他视图或复合组件完全相同。
Source code
HelloWorldView.java
package com.vaadin.demo.flow.application.mainview;
import com.vaadin.flow.component.button.Button;
import com.vaadin.flow.component.notification.Notification;
import com.vaadin.flow.component.orderedlayout.HorizontalLayout;
import com.vaadin.flow.component.textfield.TextField;
import com.vaadin.flow.router.Route;
import com.vaadin.flow.router.PageTitle;
import com.vaadin.flow.router.RouteAlias;
@Route(value = "hello", layout = MainView.class)
@PageTitle("Hello World")
@CssImport("./styles/views/helloworld/hello-world-view.css")
@RouteAlias(value = "", layout = MainView.class)
public class HelloWorldView extends HorizontalLayout {
private TextField name;
private Button sayHello;
public HelloWorldView() {
setId("hello-world-view");
name = new TextField("Your name");
sayHello = new Button("Say hello");
add(name, sayHello);
setVerticalComponentAlignment(Alignment.END, name, sayHello);
// Handle clicks
sayHello.addClickListener(e -> {
Notification.show("Hello " + name.getValue());
});
}
}
7CAF8324-78D4-46E3-8825-FD4A6E45DB62