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

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.17 18:53:16