Vaadin 24.0.5中Dialog内GridContextMenu不显示问题求助
从Vaadin 23升级到24.0.5后,Dialog内部Grid的GridContextMenu组件无法显示,且无任何报错信息,但页面直接挂载的Grid上下文菜单可正常工作。
环境信息
os: Windows 10 Pro (21H2) browser: chrome-113.0.5672.93, firefox-113.0.1 java: 17.0.3 nodejs: 18.16.0 spring-boot: 3.0.6 vaadin: 24.0.5
示例代码
import com.vaadin.flow.component.dialog.Dialog; import com.vaadin.flow.component.grid.Grid; import com.vaadin.flow.component.grid.contextmenu.GridContextMenu; import com.vaadin.flow.component.html.Div; import com.vaadin.flow.component.html.Label; import com.vaadin.flow.router.PageTitle; import com.vaadin.flow.router.Route; import java.util.List; @PageTitle("Example-01") @Route(value = "example01", layout = MainLayout.class) public class Example01View extends Div { public Example01View() { add(createGrid()); // GridContextMenu 正常显示 Dialog dialog = new Dialog(); dialog.add(createGrid()); // GridContextMenu 无法显示 dialog.open(); } private Grid<Product> createGrid() { Grid<Product> grid = new Grid<>(Product.class, false); grid.addColumn(Product::id).setHeader("Id"); grid.addColumn(Product::name).setHeader("Name"); GridContextMenu<Product> menu = grid.addContextMenu(); menu.addItem(new Label("Text 1")); menu.addItem(new Label("Text 2")); grid.setItems(List.of( new Product(1L, "name1"), new Product(2L, "name2") )); return grid; } public record Product(Long id, String name) { } }
未复现环境
- Vaadin 22.0.x + Spring Boot 2.5.x
- Vaadin 23.3.x + Spring Boot 2.7.x
问题原因
Vaadin 24基于Lit框架重构了部分组件渲染逻辑,其中Dialog默认启用Shadow DOM实现样式隔离。而GridContextMenu默认会将菜单元素挂载到全局文档根节点(<body>),Shadow DOM的隔离特性导致Dialog内部无法感知到外部挂载的菜单元素,进而无法正常渲染;同时由于Shadow DOM的上下文隔离,浏览器也不会抛出明显报错。
解决方案
方案1:指定GridContextMenu的挂载目标为Dialog的内容容器
修改代码,将GridContextMenu的挂载目标设置为Dialog的Shadow DOM内部内容节点,确保菜单处于Dialog的上下文范围内:
public Example01View() { add(createGrid()); Dialog dialog = new Dialog(); Grid<Product> dialogGrid = createGrid(); dialog.add(dialogGrid); // 将菜单挂载到Dialog的Shadow DOM内容容器 GridContextMenu<Product> menu = dialogGrid.getContextMenu(); menu.setTarget(dialog.getElement().getShadowRoot().getFirstChild()); dialog.open(); }
方案2:禁用Dialog的Shadow DOM(不推荐)
通过设置Dialog的no-shadow主题属性关闭Shadow DOM隔离,让Dialog内容直接挂载到主DOM中,菜单即可正常显示。但此方法会破坏Dialog的样式隔离,可能引发样式冲突:
Dialog dialog = new Dialog(); dialog.getElement().setAttribute("theme", "no-shadow"); dialog.add(createGrid()); dialog.open();
内容的提问来源于stack exchange,提问作者Roman
相关产品推荐
相关产品推荐

