You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Vaadin 24.0.5中Dialog内GridContextMenu不显示问题求助

问题:Vaadin 24.0.5中Dialog内Grid的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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.21 12:18:20