前言:最近在完善 Input 组件字数计算的时候引发了不少的问题:1、到限制字数时,继续输入中文会替换末尾的文字;2、不同浏览器截断的表现不一样等等问题。
先明确一下需求
需求
- 输入到最大长度时,超出截断
- 首尾非文字(空格、换行等)不计入字数统计中
- 超出截断时保持已输入的文字以及开头非文字部分
尝试
总体思路
1、不能直接使用 input 的 maxLength,因为计算数字的时候会把首尾非文字也计算其中
2、监听 input 的 onChange 事件,当输入的长度大于最大长度时截断
根据以上思路,既然不能直接使用 input 的 maxLength,那就在 onChange 事件里进行逻辑处理。
第一次尝试
1 | const v = e.target.value.trim(); |
存在的问题
- 输入到最大长度时开头空格或换行会被截掉
- 输入中文时会从尾部开始替换掉输入框的值
- 尾部空格较多时,截取的时候会出问题,计算数字的时候会把空格计算其中
第二次尝试
1 | const { value } = e.target; |
通过上面两个逻辑判断和处理已经解决了第一次尝试的两个问题,那还有一个问题是不是没解决呢?其实在其他浏览器能解决输入中文时替换掉输入框的值,但是 Chrome 浏览器却不行,WTF!Chrome 竟然不行。其实原因是我上面提到的 Chrome 和其他浏览器输入中文时的表现不一样。
我们用两张图来看一下就明白了
第一张图是 Chrome 输入中文的表现,第二张图是其他浏览器输入中文的表现。是的,Chrome 输入中文时会实时把拼音显示在输入框内,这样就会导致在截取的时候判断不准确替换掉了尾部的值,那有没有什么解决方案呢?那肯定是有的,接下来就来优化一下这个问题。
优化
判断是否中文输入
当用户使用拼音输入法输入时,我们会发现 onChange/onInput
取得的值是拼音值,但是很明显,我们需要计算的是用户输入的中文值的长度,而不是拼音值的长度。所以这里需要解决使用拼音输入法时会取得拼音值的问题。
我们先来看两个比较陌生的事件:
- compositionstart:文本合成系统如 input method editor(即输入法编辑器)开始新的输入合成时会触发
compositionstart
事件。例如,当用户使用拼音输入法开始输入汉字或者使用语音输入时,这个事件就会被触发。 - compositionend:当文本段落的组成完成或取消时,
compositionend
事件将被触发 (具有特殊字符的触发,需要一系列键和其他输入,如语音识别或移动中的字词建议)。例如,当用户使用拼音输入法输入汉字或者使用语音输入完毕或者取消时,这个事件就会被触发。
因此我们可以声明一个标记lock
,在compositionstart
、compositionend
两个事件过程之间的时候lock
值为 true,在 input onChange
事件中通过lock
的值来判断当前输入的状态和截取。
1 | if (e.type === 'compositionstart') { |
总结
那到这里一个 Input 组件字数计算的问题总算解决了,从中也是吸取了不少的经验和总结,继续加油!!!