Vaadin中CustomField的addBlurListener()无法触发问题求助
问题描述
我并非专业开发者,编程只是个人爱好。现遇到Vaadin组件Blur事件不触发的问题,求助解决。
使用版本
<properties> <java.version>21</java.version> <vaadin.version>24.4.12</vaadin.version> </properties>
自定义组件代码
我创建了继承自CustomField的类:
@FieldDefaults(level = AccessLevel.PRIVATE) public class ValueCustomComponent extends CustomField<ValueDTO> { NumberField numberField; ComboBox<String> comboBox; ValueDTO value = new ValueDTO(); public ValueCustomComponent() { initialize(); } private void initialize() { this.numberField = new NumberField(); this.comboBox = new ComboBox<>(); comboBox.setItems(List.of("First Value", "Second Value", "Third Value")); comboBox.setAllowCustomValue(true); numberField.getElement().setAttribute("disabled", true); comboBox.addBlurListener(comboBoxBlurEvent -> { if(comboBox.getValue() != null && !comboBox.getValue().equals(value.getDrug())){ numberField.getElement().setAttribute("disabled", false); } }); setValues(); add(comboBox, new Text(" "), numberField); } private void setValues() { if (value.getDrug() != null) { comboBox.setValue(value.getDrug().toString()); } if (value.getAmount() != null) { numberField.setValue(value.getAmount()); } } @Override protected ValueDTO generateModelValue() { value.setDrug(comboBox.getValue()); value.setAmount(numberField.getValue()); return value; } @Override protected void setPresentationValue(ValueDTO valueDTO) { comboBox.setValue(valueDTO.getDrug().getValue()); numberField.setValue(valueDTO.getAmount()); } }
测试视图代码
我尝试在该组件失去焦点时触发通知:
@Route(value = "test") @FieldDefaults(level = lombok.AccessLevel.PRIVATE) public class TestView extends VerticalLayout { public TestView() { ValueCustomComponent valueCustomComponent = new ValueCustomComponent(); valueCustomComponent.addBlurListener(this::onBlur); add(valueCustomComponent); } private void onBlur(BlurNotifier.BlurEvent<CustomField<ValueDTO>> customFieldBlurEvent) { showNotification(customFieldBlurEvent.getSource().getValue().toString()); } private void showNotification(String value) { Notification notification = new Notification(value, 2000, Notification.Position.TOP_CENTER); notification.addThemeVariants(NotificationVariant.LUMO_SUCCESS); notification.open(); } }
但onBlur()方法始终未被调用。请问默认实现的addBlurListener()为何无法生效?我该如何操作才能让addBlurListener()正常工作?我已查阅Vaadin文档、论坛及Stack Overflow,但未找到解决办法。
问题原因及解决方法
原因分析
Vaadin的CustomField本质是容器组件,本身没有原生可聚焦元素,默认不会触发Blur事件。用户操作时焦点会落在组件内的子元素(ComboBox、NumberField)上,而非CustomField本身,因此绑定在CustomField上的BlurListener永远不会被触发。
解决步骤
1. 让CustomField成为可聚焦元素
在自定义组件的初始化方法中,给根元素添加tabindex属性,使其能获取焦点:
private void initialize() { // 原有代码保持不变 // 添加此行,让组件可被聚焦 getElement().setAttribute("tabindex", "0"); add(comboBox, new Text(" "), numberField); }
2. 监听子元素焦点,判断是否离开组件范围
给子元素添加Blur监听,检查焦点是否还在当前CustomField内部,若不在则手动触发父组件的Blur事件:
private void initialize() { this.numberField = new NumberField(); this.comboBox = new ComboBox<>(); // 原有代码保持不变 // 给子元素绑定Blur监听 comboBox.addBlurListener(e -> checkFocusLost()); numberField.addBlurListener(e -> checkFocusLost()); getElement().setAttribute("tabindex", "0"); add(comboBox, new Text(" "), numberField); } private void checkFocusLost() { // 通过客户端JS延迟检查焦点是否仍在组件内,不在则触发Blur事件 getElement().executeJs("setTimeout(() => { const active = document.activeElement; if (!this.contains(active)) { this.dispatchEvent(new Event('blur')); } }, 0);"); }
3. 优化焦点行为(可选)
若希望点击组件内任意区域时,焦点自动切换到父组件,可添加点击事件监听:
private void initialize() { // 原有代码保持不变 addClickListener(e -> getElement().focus()); }
完成以上处理后,当用户点击组件区域外时,CustomField的Blur事件会被正常触发,onBlur()方法即可执行。
内容的提问来源于stack exchange,提问作者Gleb
相关产品推荐
相关产品推荐

