在Vaadin中如何从JavaScript引用现有Java类并调用其方法?
实现方案
要在Vaadin中实现从Java触发Shepherd引导、并在JavaScript中调用Java方法的需求,核心是利用Vaadin的客户端-服务端通信机制——通过传递Java对象的客户端代理给JS,再通过$server调用标注了@ClientCallable的Java方法。以下是具体实现步骤:
1. 标记Java类中可被JS调用的方法
在需要被JS调用的目标Java类中,给要暴露的方法添加@ClientCallable注解(该注解来自com.vaadin.flow.component包),让Vaadin允许客户端JS调用这些方法:
import com.vaadin.flow.component.ClientCallable; import com.vaadin.flow.component.Component; public class ExamplePageController extends Component { // 示例方法:打开指定标签页 @ClientCallable public void openTargetTab() { // 这里编写操作Vaadin组件的逻辑,比如切换标签页 // 例如:tabSheet.setSelectedTab(targetTab); } // 示例方法:关闭标签页 @ClientCallable public void closeCurrentTab() { // 实现关闭标签页的业务逻辑 } }
注意:该类最好继承
Component或本身是Vaadin组件,这样Vaadin能自动管理它的客户端代理;如果是普通类,需确保它可被Vaadin序列化传递到客户端。
2. 在触发类中传递Java对象给JS
修改executeShepherd方法,获取目标类的有效实例(比如从当前UI中查找,或根据页面标题实例化),然后作为参数传递给executeJs:
import com.vaadin.flow.component.UI; public class TourPageController { public static void executeShepherd(String appTitle) { UI currentUI = UI.getCurrent(); switch(appTitle) { case "example": // 从当前UI中获取目标控制器实例(根据实际场景调整获取方式) ExamplePageController pageController = currentUI.getChildren() .filter(ExamplePageController.class::isInstance) .map(ExamplePageController.class::cast) .findFirst() .orElseThrow(() -> new RuntimeException("找不到ExamplePageController实例")); // 将Java对象传递给JS,Vaadin会自动包装成客户端可调用的代理对象 currentUI.getPage().executeJs("window.startTour($0)", pageController); break; // 其他页面的case逻辑 } } }
3. 调整JS的startTour函数接收并使用Java对象
修改页面头部的JS代码,让startTour接收Java对象参数,并在Shepherd步骤中通过$server调用Java方法:
window.startTour = function(pageController) { // 初始化Shepherd引导实例 const tour = new Shepherd.Tour({ useModalOverlay: true, defaultStepOptions: { cancelIcon: { enabled: true } } }); // 添加引导步骤,在beforeShowPromise中调用Java方法 tour.addStep({ title: '切换标签页', text: '点击下一步打开目标标签页', attachTo: { element: '#target-button', on: 'bottom' }, beforeShowPromise: function() { return new Promise(function(resolve) { // 通过$server调用Java端标注了@ClientCallable的方法 pageController.$server.openTargetTab(); resolve(); }); }, buttons: [ { text: '下一步', action: tour.next } ] }); // 启动引导 tour.start(); };
关键注意事项
- 方法参数与返回值限制:
@ClientCallable标注的方法,参数和返回值必须是Vaadin支持的序列化类型(如String、int、List等),复杂自定义对象需实现Serializable接口。 - UI线程安全:
UI.getCurrent()必须在UI线程中调用,按钮点击监听器本身处于UI线程,无需额外处理;若从后台线程触发,需用UI.access()包裹逻辑。 - 实例有效性:确保传递给JS的Java对象是当前UI中的有效实例,避免空指针或无效调用。
内容的提问来源于stack exchange,提问作者Ji Lin
相关产品推荐
相关产品推荐

