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

如何在Vaadin 24.7.6(Java 21、Maven环境)中使用JavaScript构建自定义Vaadin组件

如何在Vaadin 24.7.6(Java 21、Maven环境)中使用JavaScript构建自定义Vaadin组件

我完全懂你的感受——之前用Vaadin时想从零用JavaScript写自定义组件卡了壳,转去用Perl+Mojolicious搞HTML/JS组件却顺得不行,现在回到Vaadin 24.7.6(搭着Java 21和Maven),照着教程操作还踩坑报错,这种前后落差确实让人头疼。我来给你一步步捋清楚正确的操作流程,帮你搞定自定义JS组件的问题:

一、先把前端资源放对位置

Vaadin 24对前端文件的存放路径有硬性要求,别瞎放:

  • 把你的JavaScript组件代码放在src/main/resources/META-INF/frontend/目录下,比如新建一个my-custom-component.js文件
  • 如果需要样式,CSS文件也放同一个目录,或者直接在JS组件里内置样式

二、写符合规范的Web Component(JavaScript部分)

Vaadin底层基于Web Components,所以你的JS组件得遵循Custom Elements规范,给你一个最基础的可运行示例:

import { LitElement, html, css } from 'lit';

class MyCustomComponent extends LitElement {
  // 定义组件属性,和Java端对应
  static get properties() {
    return {
      label: { type: String }
    };
  }

  constructor() {
    super();
    // 设置属性默认值
    this.label = 'Default Label';
  }

  // 渲染组件HTML结构
  render() {
    return html`
      <div class="custom-wrapper">
        <p class="custom-label">${this.label}</p>
        <button @click=${this._onButtonClick}>点击触发事件</button>
      </div>
    `;
  }

  // 按钮点击事件处理,同时向Java端派发自定义事件
  _onButtonClick() {
    this.dispatchEvent(new CustomEvent('custom-button-click', { 
      detail: 'JS组件的按钮被点击啦',
      bubbles: true,
      composed: true
    }));
  }

  // 内置组件样式
  static get styles() {
    return css`
      .custom-wrapper {
        padding: 1rem;
        border: 1px solid #e0e0e0;
        border-radius: 4px;
        background-color: #f5f5f5;
      }
      .custom-label {
        margin: 0 0 0.5rem 0;
        font-size: 1.1rem;
      }
      button {
        padding: 0.5rem 1rem;
        cursor: pointer;
      }
    `;
  }
}

// 注册自定义元素,标签名必须含连字符
customElements.define('my-custom-component', MyCustomComponent);

划重点:Vaadin 24已经内置了Lit库,不用额外安装,直接导入用就行

三、编写Java端的组件绑定类

要在Java代码里调用这个JS组件,得写个对应的Java类做绑定,核心是几个注解不能错:

import com.vaadin.flow.component.Component;
import com.vaadin.flow.component.Tag;
import com.vaadin.flow.component.dependency.JsModule;
import com.vaadin.flow.component.dependency.NpmPackage;
import com.vaadin.flow.shared.Registration;

@Tag("my-custom-component") // 必须和JS里注册的自定义元素标签名完全一致
@JsModule("./my-custom-component.js") // 指向frontend目录下的JS文件,路径要对
@NpmPackage(value = "lit", version = "2.8.0") // 版本要和Vaadin 24.7.6内置的Lit匹配,一般是2.8.x
public class MyCustomComponent extends Component {

    // 给JS组件的label属性提供Java端的setter/getter
    public void setLabel(String label) {
        getElement().setProperty("label", label);
    }

    public String getLabel() {
        return getElement().getProperty("label");
    }

    // 给JS派发的自定义事件绑定Java端的监听器
    public Registration addCustomButtonClickListener(ComponentEventListener<CustomButtonClickEvent> listener) {
        return addListener(CustomButtonClickEvent.class, listener);
    }

    // 自定义事件类,对应JS里的custom-button-click事件
    public static class CustomButtonClickEvent extends ComponentEvent<MyCustomComponent> {
        private final String detail;

        public CustomButtonClickEvent(MyCustomComponent source, boolean fromClient) {
            super(source, fromClient);
            this.detail = source.getElement().getProperty("detail");
        }

        public String getDetail() {
            return detail;
        }
    }
}

四、在View中使用自定义组件

现在就可以像用普通Vaadin组件一样,把它加到你的视图里了:

import com.vaadin.flow.component.notification.Notification;
import com.vaadin.flow.component.orderedlayout.VerticalLayout;
import com.vaadin.flow.router.Route;

@Route("") // 设置为默认路由
public class MainView extends VerticalLayout {
    public MainView() {
        // 创建自定义组件实例
        MyCustomComponent myComponent = new MyCustomComponent();
        // 设置JS组件的label属性
        myComponent.setLabel("来自Java端的文本");

        // 监听JS组件派发的自定义事件
        myComponent.addCustomButtonClickListener(event -> {
            Notification.show("收到JS组件的事件:" + event.getDetail());
        });

        // 把组件加到视图里
        add(myComponent);
    }
}

五、你大概率会踩的坑(排查报错)

照着教程还报错?先检查这几个地方:

  • 前端文件路径错了:必须放在src/main/resources/META-INF/frontend/下,@JsModule的路径要写./xxx.js,别写错层级
  • 标签名不符合规范:自定义元素标签名必须包含连字符,比如my-custom-component,不能是mycustomcomponent
  • 注解写错:@Tag的名字要和JS里customElements.define的第一个参数完全一致,大小写都不能错
  • 缓存问题:Maven执行clean命令清掉旧缓存,或者在Vaadin的Dev Mode界面点"Clear cache and reload"
  • 事件没触发:JS里派发事件时要加bubbles: true和composed: true,不然Java端监听不到

内容来源于stack exchange

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.08 13:13:13