如何在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
相关产品推荐
相关产品推荐

