首页 > 其他分享 >解决使用输入法输入在 React input 框中的问题

解决使用输入法输入在 React input 框中的问题

时间:2023-05-23 23:03:24浏览次数:37  
标签:触发 输入法 ev React isComposition input onChange 输入

问题

在使用 React 绑定 input 输入框的 onChange 方法时,如果使用中文输入法(或者其他输入法),会出现一个问题:还在输入拼音的时候,onChange 方法已经触发了,如下,即输入过程就已经触发了多次 onChange 方法。如果 onChange 方法有较为复杂的逻辑,就可能会带来一些用户体验或者逻辑的问题。

解决使用输入法输入在 React input 框中的问题_compositionEvent

原因

只要有按下键盘的动作,就会触发 onChange 方法,如果输入英文就没什么问题,但使用中/日/韩等输入法的话,比如输入中文拼音已经开始在触发 onChange 事件了。

需求及解决方案

  • 需求:等到选择确认输入中文后,才让它触发 onChange 方法的后续操作,如改变value的值。
  • 解决方案:使用 compositionEvent 事件来解决。

DOM 接口 CompositionEvent 表示用户间接输入文本(如使用输入法)时发生的事件。此接口的常用事件有compositionstart, compositionupdate 和 compositionend

CompositionEvent 事件介绍

  • compositionstart

当用户使用输入法如拼音输入汉字时,这个事件就会被触发,即是在用户开始非直接输入的时候触发,在非直接输入的时候结束,整个过程只触发了一次。

  • compositionupdate

事件触发于字符被输入到一段文字的时候,如在用户开始输入拼音到确定结束的过程都会触发该事件。

  • compositionend

当文本段落的组成完成或取消时, compositionend 事件将被触发 。如用户点击拼音输入法选词确定后,则触发了该事件,此时是直接输入了,整个过程只触发了一次。

可以知道这三个事件就把我们输入中文拼音的三个过程进行了拆分。

实现

我们通过监听输入法开始输入到结束的事件,即是去监听compositionstartcompositionend方法,通过设置一个变量,在两个方法里面设置true/false,来判断是否处在中文输入拼音这个过程当中,如果是,则不触发 onChange 后续事件。

这个未必是优化。搜索框提示的一个很重要用处,不是帮助省出来那么一点打字的时间,而是为了提示打字人应该写什么。很多时候打字者只有一个模糊的需求,全靠搜索框提示才能明白自己真正想搜什么。而这时候对拼音进行搜索提示,不说提醒用户该拼音词也可以搜到结果,单说在某种可能的用况下会避免用户搜索整个输入法却找不到对应汉字(因为输入错误拼音)这点就非常好用了。

如下代码,我们通过设置个对照:value1 对应的为正常 onChange 操作,value2 对应的则是做了输入法处理

import React, { Component } from 'react'
import './style.css'

let isComposition = false

class TestComposition extends Component {
  constructor(props) {
    super(props)
    this.state = {
      value1: '',
      value2: '',
    }
    this.handleChange1 = this.handleChange1.bind(this)
    this.handleChange2 = this.handleChange2.bind(this)
    this.handleComposition = this.handleComposition.bind(this)
  }

  handleChange1 = ev => {
    this.setState({
      value1: ev.target.value,
    })
  }

  handleChange2 = ev => {
    // 未使用输入法或使用输入法完毕才能触发
    if (!isComposition) {
      this.setState({
        value2: ev.target.value,
      })
    }
  }

  handleComposition(ev) {
    if (ev.type === 'compositionend') {
      isComposition = false
    } else {
      isComposition = true
    }
  }

  render() {
    return (
      <div>
        <input type='text' onChange={this.handleChange1} />
        <span>{this.state.value1}</span>
        <input
          type='text'
          onChange={this.handleChange2}
          onCompositionStart={this.handleComposition}
          onCompositionEnd={this.handleComposition}
          placeholder='使用了composition的input框'
        />
        <span>{this.state.value2}</span>
      </div>
    )
  }
}

export default TestComposition

那么这样就能解决了吗?还不行。

其他浏览器不会有问题,但谷歌浏览器却不行。这里要注意的是谷歌浏览器跟其他浏览器的执行顺序不同:

谷歌浏览器: compositionstart -> onChange -> compositionend

其他浏览器: compositionstart -> compositionend -> onChange

所以上述代码运行在谷歌浏览器的话,一开始中文输入我们就将isComposition设置为true,最后一步 compositionend 方法我们才将 isComposition 恢复为 true,而onChange已经执行完了, 按这个逻辑中文输入法打字都改不了input的value值

if (!isComposition) { // isComposition为false 才可以执行onChange后续逻辑
  this.setState({
    value2: ev.target.value,
  })
}

所以我们需要对谷歌浏览器做一次特别处理:

  1. 判断是否为谷歌浏览器
  2. 如果是,则在 compositionend 方法最后再执行一次 onChange 方法

最后附上完整代码:

import React, { Component } from 'react'

let isComposition = false
const isChrome = navigator.userAgent.indexOf('Chrome') > -1

class TestComposition extends Component {
  constructor(props) {
    super(props)
    this.state = {
      value1: '',
      value2: '',
    }
    this.handleChange1 = this.handleChange1.bind(this)
    this.handleChange2 = this.handleChange2.bind(this)
    this.handleComposition = this.handleComposition.bind(this)
  }

  handleChange1 = ev => {
    this.setState({
      value1: ev.target.value,
    })
  }

  handleChange2 = ev => {
    // 未使用输入法或使用输入法完毕才能触发
    if (!isComposition) {
      this.setState({
        value2: ev.target.value,
      })
    }
  }

  handleComposition(ev) {
    if (ev.type === 'compositionend') {
      isComposition = false
      if (!isComposition && isChrome) {
        this.handleChange2(ev)
      }
    } else {
      isComposition = true
    }
  }

  render() {
    return (
      <div>
        <input type='text' onChange={this.handleChange1} />
        <span>{this.state.value1}</span>
        <input
          type='text'
          onChange={this.handleChange2}
          onCompositionStart={this.handleComposition}
          onCompositionEnd={this.handleComposition}
          placeholder='使用了composition的input框'
        />
        <span>{this.state.value2}</span>
      </div>
    )
  }
}

export default TestComposition

效果:

解决使用输入法输入在 React input 框中的问题_compositionEvent_02

注:

  • Vue 自带解决了上述问题,v-model 有用到compositionEvent事件
  • 该做法视乎项目需求场景,因为如果有需要进行搜索中文拼音过程也要提示英文单词的来说,那就没必要了
  • 也可以使用 ref 的方式进行绑定,上述只是其中一种解决方式

参考:


标签:触发,输入法,ev,React,isComposition,input,onChange,输入
From: https://blog.51cto.com/u_16056437/6334906

相关文章

  • 对于输入法的评价
    讯飞输入法在用户界面方面,提供了丰富的个性化设置选项,如主题、键盘布局、字体等,同时通过记住用户选择,加快用户输入速度,提高用户的工作效率。在短期刺激方面,讯飞输入法使用了多种方式来吸引用户使用,例如提供了语音输入、手写输入、智能预测等功能,使得用户能够快捷地完成输入任务。......
  • react+mock
    之前写过一篇react项目添加mock的文章,在文章中说的mock代码是打包配置的时候写入的,这种方式导致每次修改mock数据后都需要重新启动服务才能获取到新的mock数据。今天使用另外一种方式来实现开发过程中的数据mock。在项目中安装axios和mock.js两个框架然后在webpack配置文件中......
  • react项目在不暴露配置文件的情况下配置环境变量
    react项目在不暴露配置文件的情况下修改打包配置需要用到 react-app-rewired和customize-cra包对打包配置文件进行修改。 添加自定义环境变量有两种方法:方法1:使用dotenv-cli1、运行 yarnglobaladddotenv-cli 全局安装dotenv-cli2、在根目录下添加.env.pre文件,写入变......
  • 用Python开发输入法后台(3)——我自己的输入法的规则
    我的输入法基本开发完成了,如下所示:  现在总结一下我的输入规则:1.用户输入几个字符,就代表几个字的词.比如输入'w'表示以w开头的单字词,输入wm,表示拼音首字母开头的双字词,gsm表示拼音首字母开头的3字词; 2.输入分号,表示词的个数已固定,需要进一步筛选;同时......
  • React笔记-Hooks(九)(非常全面)
    React笔记-Hooks(九)Hooks概念ReactHooks的意思是组件尽量写成纯函数如果需要外部功能和副作用就用钩子把外部代码"钩"进来函数组件和类组件区别函数组件没有状态(state)类组件有函数组件没有生命周期类组件有(挂载-更新-销毁)函数组件没有this类组件有函数组......
  • 扩展可能性:发挥React Native与小程序集成的优势
    ReactNative是一个强大的前端跨端框架,可以帮助开发者高效地构建移动应用程序,并充分利用跨平台开发的优势,同时提供接近原生应用程序的性能和用户体验。它具有许多技术上的优势:跨平台开发:使用ReactNative,您可以使用相同的代码库构建同时运行在iOS和Android平台上的应用程序。......
  • 评价输入法软件
    用户界面:界面友好但是功能并不明显,对于中英文的切换以及符号的设置不合理,查找符号不方便。记住用户选择:优点:这个功能比较友好,对于我自己的名字、一些常用词都有记住,输入时不需要输入全部拼音,通过简写的拼音就能够输出自己的姓名。缺点:如果在第一次选择错误,在后面......
  • 对于手头正在使用输入法或者搜索类的软件产品评价
    百度产品。用户界面一个好的用户界面可以让用户更容易地掌握输入法或搜索类软件的功能,从而提高用户的效率。用户界面应该具有简单、易用、明确的特点,让用户一目了然地了解软件的功能和操作方法。同时,用户界面还应该具有美观、大方、简洁的特点,这样可以吸引用户的注意力,提高用户......
  • [React Typescript] Overriding and Removing Component Props
    UsingOmitimport{ComponentProps}from'react';import{Equal,Expect}from'../helpers/type-utils';exportconstInput=(props:Omit<ComponentProps<'input'>,'onChange'>&{onChange:......
  • [React Typescript] Useful React Prop Type Examples
    RelevantforcomponentsthatacceptotherReactcomponentsasprops.exportdeclareinterfaceAppProps{children?:React.ReactNode;//best,acceptseverythingReactcanrenderchildrenElement:JSX.Element;//AsingleReactelementstyle?:React.C......