onBlur、onClick、onMouseDown联动问题
一个简单有趣的交互执行顺序问题
在antd的table中有这样的场景


其中翻译文本列的内容可以双击,展开输入框,有一个这样的需求:输入框失焦时自动保存翻译好的数据
需要失焦会想到用onBlur实现,所以有了以下代码
const EditInput = React.memo<{
value: string;
onChange: (value: string) => void;
onSave: () => void;
placeholder: string;
}>(({ value, onChange, onSave, placeholder }) => {
const inputRef = React.useRef<any>(null);
React.useEffect(() => {
if (inputRef.current) {
try {
inputRef.current.focus?.({ cursor: 'all' });
} catch (_) {
inputRef.current?.input?.select?.();
}
}
}, []);
return (
<Input
ref={inputRef}
value={value}
onChange={(e) => onChange(e.target.value)}
placeholder={placeholder}
autoFocus
onBlur={onSave}
onPressEnter={onSave}
/>
);
});
如果用户不想保存怎么办?
那得点击操作列的取消按钮,取消按钮的逻辑是onCancel,也就是取消这次操作,取消按钮只有在input被编辑状态才会出现
如果给取消按钮绑定onClick,那么输入框的onBlur事件会优先触发(优先级问题),代码中的onBlur事件绑定了onSave,也就是说会触发保存功能,那么取消按钮绑定的onClick事件就变成摆设了 😗
<Text
className={styles.actionText}
style={{ color: '#1890FF' }}
onClick={() => handleSave(record)}
>
{isSaving ? translatedTexts.saving : translatedTexts.save}
</Text>
<Text
className={styles.actionText}
style={{ color: '#999' }}
onMouseDown={(e) => {
// mousedown 先于 blur 触发,提前标记取消,防止 onBlur 触发 onSave逻辑
handleCancelEdit(record.id);
}}
>
{translatedTexts.cancel}
</Text>
如何避免这个问题?
改变点击事件的执行顺序,将取消按钮的onClick事件变更为onMouseDown,就可以避免取消按钮不生效的问题
但是在这个业务场景中,取消逻辑执行后,自动翻译按钮会取代取消按钮的位置,在MouseUp期间,自动翻译按钮的onClick逻辑也会被触发!也就是说取消逻辑后,又触发了一次自动翻译逻辑 😟
可以采用同样的处理方法,把自动翻译按钮的点击事件也修改为onMouseDown
那么在自动翻译按钮的MouseUp期间呢?因为自动翻译逻辑中包含接口的请求,此时前端进行了保护性措施,无法点击操作列的内容,并且取消按钮中没有绑定MouseUp事件,这样事件冲突就基本解决了 🥳
用户操作优化可能性
上述中有提到,只有在点击取消按钮时才能取消,应该如何优化用户体验呢?
考虑到用户可能只是双击了翻译文本想看看效果,并没有对文本内容进行任何修改,无论怎样,onBlur处的逻辑都是会触发的(onSave,包括点击保存按钮),所以对于没有修改的内容(或者就是空白的内容),逻辑判断需要在onSave中处理,如果有需求的话,可以这样实现