Vaadin Grid交互模式下调用refreshItem刷新行后焦点丢失问题
问题根因
调用dataProvider.refreshItem(item)时,Vaadin Grid会销毁目标行的全部渲染内容,重新执行所有列的渲染逻辑生成新的组件替换原有内容,原本处于聚焦状态的输入组件会被直接销毁,因此会丢失焦点。
可落地解决方案
方案1:局部刷新计算列,避免重渲染输入列
如果只有非组件的计算列需要更新值,不需要修改当前输入列的内容,可以不用触发全量行刷新,仅刷新指定计算列即可:
- 先给所有计算列设置唯一标识key
// 给需要更新的计算列设置唯一key grid.addColumn(item -> item.getCalculatedAmount()).setKey("calculated_amount_col");
- 值变更后仅刷新指定计算列
private void palettChanged(Item item, Integer value) { // 完成item其他属性的修改逻辑 item.setInputValue(value); item.recalculateRelatedFields(); // 仅刷新目标计算列,不会重渲染输入列,自然不会丢失焦点 grid.getColumnByKey("calculated_amount_col").getElement() .callJsFunction("refresh", item.getUniqueId()); }
方案2:暂存焦点状态,刷新后主动回焦
如果业务逻辑要求必须全量刷新整行,可以在刷新前记录当前聚焦的条目标识,刷新完成后主动把焦点切回对应输入框:
// 全局变量存储当前聚焦的条目唯一ID private Object currentFocusedItemId; // 输入列渲染逻辑 addColumn(new ComponentRenderer<>(item -> { AmountField amountField = new AmountField(); amountField.setWidth("7em"); // 添加焦点监听,存储当前聚焦的条目ID amountField.addFocusListener(e -> { currentFocusedItemId = item.getUniqueId(); }); amountField.addValueChangeListener(ignored -> palettChanged(item, amountField.getIntegerValue())); return amountField; })).setKey("amount_input_col"); // 给输入列设置唯一key private void palettChanged(Item item, Integer value) { // 完成item其他属性的修改逻辑 item.setInputValue(value); item.recalculateRelatedFields(); // 先判断当前刷新的行是否是正在聚焦的行 boolean needRefocus = item.getUniqueId().equals(currentFocusedItemId); getDataProvider().refreshItem(item); // 如果是之前聚焦的行,刷新后找到对应输入框重新聚焦 if (needRefocus) { grid.getCell(item, grid.getColumnByKey("amount_input_col")) .getComponent() .ifPresent(input -> input.getElement().callJsFunction("focus")); } }
方案3:改用Grid编辑器模式
如果业务场景允许,直接使用Vaadin Grid自带的单元格/行编辑器功能,平时单元格仅展示文本,用户点击编辑时才渲染输入组件,编辑完成后切回文本展示,从根源上避免整行刷新时的焦点丢失问题。
内容的提问来源于stack exchange,提问作者Ankesh
相关产品推荐
相关产品推荐

