
在AI时代,输入框中文输入法处理是一个常见的问题。本文将介绍如何解决这个问题,并提供详细的解决方案。
在我们开发 AI 聊天框的时候,经常会遇到输入框中文输入法处理的问题。
比如:中文输入法输入英文的时候,按下回车键会直接发送消息。
在早些的 ChatGPT、POE 等 AI 聊天框中,都会出现这个问题。那我们如何解决呢?
产生原因
在解释解决方案之前,我们需要先了解这个问题产生的原因。当我们使用中文(或日文、韩文等)输入法时,实际上文字输入经历了一个叫做 组合输入(Composition)的过程:
- 组合开始(CompositionStart):当我们切换到输入法并开始输入时,浏览器会触发 compositionstart事件
- 组合更新(CompositionUpdate):当我们输入拼音(如 "nihao")并且文字还未确认时,浏览器会不断触发 compositionupdate事件
- 组合结束(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 | 是 | 是 | 
总结
处理输入框中文输入法问题是开发多语言应用时常见的挑战。通过理解浏览器的组合输入事件机制,我们可以采取适当的措施来避免用户体验问题:
- 检查键盘事件的 isComposing属性
- 监听 compositionstart和compositionend事件
- 使用专门的第三方库来处理这些问题
这些方法可以确保当用户使用中文输入法时,不会因为按下回车键确认文字而意外发送消息,从而提升用户体验。
对应代码:
https://codesandbox.io/p/sandbox/rnz45l?file=%2Fsrc%2FApp.tsx%3A30%2C8
Read more

GitHub Actions + CF Worker:打造完美的持续部署流程
分享一下最近将官网和exportx.dev两个网站(Turborepo管理的)从Vercel迁移到Cloudflare Pages的过程,期间也使用了Github Action来做CI/CD自动化测试和部署,有兴趣的同学可以一起阅读交流下。

1.5G到200M,TurboRepo Docker镜像优化指南:轻松打造轻量级镜像
最近往我的TurboRepo中添加了几个后端项目,然后使用Docker部署到服务器上,网上的TurboRepo的打包部署教程比较少,而且有些文章给的方法让Docker的镜像变得很大,所以我这里记录一下我是怎么减少镜像大小的。

Ghost 博客系列IIII | 文章目录导航-TOC插件
分享一下最近将官网和exportx.dev两个网站(Turborepo管理的)从Vercel迁移到Cloudflare Pages的过程,期间也使用了Github Action来做CI/CD自动化测试和部署,有兴趣的同学可以一起阅读交流下。
