4 min read

ChatGPT都踩过的坑:AI对话框中文输入法完美解决方案

在AI时代,输入框中文输入法处理是一个常见的问题。本文将介绍如何解决这个问题,并提供详细的解决方案。

在我们开发 AI 聊天框的时候,经常会遇到输入框中文输入法处理的问题。

比如:中文输入法输入英文的时候,按下回车键会直接发送消息

在早些的 ChatGPT、POE 等 AI 聊天框中,都会出现这个问题。那我们如何解决呢?

产生原因

在解释解决方案之前,我们需要先了解这个问题产生的原因。当我们使用中文(或日文、韩文等)输入法时,实际上文字输入经历了一个叫做"组合输入"(Composition)的过程:

  1. 组合开始(CompositionStart):当我们切换到输入法并开始输入时,浏览器会触发 compositionstart 事件
  2. 组合更新(CompositionUpdate):当我们输入拼音(如"nihao")并且文字还未确认时,浏览器会不断触发 compositionupdate 事件
  3. 组合结束(CompositionEnd):当我们按下空格或回车确认文字(如"你好")时,浏览器会触发 compositionend 事件

问题就出在这个过程中:在使用中文输入法输入英文单词时,如果用户按下回车键,会同时触发两个事件:

  • 输入法认为用户要确认当前输入,触发 compositionend 事件
  • 键盘按下回车键,触发 keydown 事件(Enter键)

而在许多 AI 聊天应用中,开发者通常会监听回车键来发送消息。这就导致当用户仅仅想要确认输入文字时,消息却被意外发送出去了。

解决方案

解决这个问题有几种方法,最常见的有以下几种:

1. 使用 isComposing 属性检测

在 React 中,我们可以利用键盘事件的 isComposing 属性来判断当前是否处于组合输入状态:

const onSubmit = async (e: React.KeyboardEvent<HTMLTextAreaElement>) => {
  // 如果正在输入法组合状态,不发送消息
  if ((e as unknown as KeyboardEvent).isComposing) {
    return
  }
  
  // 检查是否按下了Enter键(且没有按Shift键)
  if (e.key === 'Enter' && !e.shiftKey) {
    e.preventDefault();
    // 发送消息逻辑
    sendMessage();
    // 清空输入框
    setInputValue('');
  }
  }

注意上面代码中关键的部分:

if ((e as unknown as KeyboardEvent).isComposing) {
  return
}

通过检测 isComposing 属性,我们可以知道当前是否处于输入法的组合状态,如果是则不执行发送操作。

2. 使用 Composition 事件监听

更完整的解决方案是同时监听组合事件,使用一个状态变量来跟踪当前是否处于组合输入状态:

import React, { useRef, useEffect } from 'react';

function ChatInput({ onSend }) {
  const [message, setMessage] = React.useState('');
  const isComposing = useRef(false);
  
  const handleCompositionStart = () => {
    isComposing.current = true;
  };
  
  const handleCompositionEnd = () => {
    isComposing.current = false;
  };
  
  const handleKeyDown = (e) => {
    if (e.key === 'Enter' && !e.shiftKey && !isComposing.current) {
      e.preventDefault();
      onSend(message);
      setMessage('');
    }
  };
  
  return (
    <textarea
      value={message}
      onChange={(e) => setMessage(e.target.value)}
      onKeyDown={handleKeyDown}
      onCompositionStart={handleCompositionStart}
      onCompositionEnd={handleCompositionEnd}
      placeholder="输入消息..."
    />
  );
}

这种方法更可靠,因为它直接监听了输入法的组合事件,能够准确地知道当前是否处于组合输入状态。

3. 使用第三方库

如果你不想自己处理这些复杂的逻辑,也可以使用一些第三方库,比如:

这些库封装了组合事件的处理,使得开发者可以更方便地处理中文输入法的问题。

兼容性测试

在不同的操作系统和浏览器中,输入法的行为可能会有所不同,所以我们需要进行全面的测试:

操作系统 浏览器 是否存在问题 解决方案是否有效
Windows Chrome
Windows Edge
Windows Firefox
macOS Chrome
macOS Safari
macOS Firefox
iOS Safari
Android Chrome

总结

处理输入框中文输入法问题是开发多语言应用时常见的挑战。通过理解浏览器的组合输入事件机制,我们可以采取适当的措施来避免用户体验问题:

  1. 检查键盘事件的 isComposing 属性
  2. 监听 compositionstartcompositionend 事件
  3. 使用专门的第三方库来处理这些问题

这些方法可以确保当用户使用中文输入法时,不会因为按下回车键确认文字而意外发送消息,从而提升用户体验。

对应代码:
https://codesandbox.io/p/sandbox/rnz45l?file=%2Fsrc%2FApp.tsx%3A30%2C8