解决办法:维护一个光标值
问题描述
在使用 Taro 开发小程序时,遇到了一个非常困扰的问题:在使用受控的 Input
组件时,每次输入都会导致光标跳转到文字末尾。
具体表现:
-
在输入框中间插入或删除字符时,光标会立即跳到文字末尾
-
严重影响了用户输入体验
-
在所有输入框(文本、数字、多行文本)中都存在此问题
问题根源分析
经过多次尝试和排查,问题的根本原因是:
-
React 的状态更新机制:每次 onInput 事件触发时,我们调用 setInputValue 更新状态
-
组件重新渲染:状态更新导致整个组件重新渲染
-
Taro Input 的限制:在重新渲染过程中,Taro 的 Input 组件没有正确保持光标位置
尝试过的方案
我尝试了多种常见的解决方案,但都没有效果:
-
❌ 使用 onBlur 代替 onInput - 问题依旧
-
❌ 使用 defaultValue 非受控组件 - 无法实时显示输入内容
-
❌ 拆分状态为独立的 useState - 问题依旧
-
❌ 使用 memo 优化子组件 - 问题依旧
-
❌ 防抖处理 - 问题依旧
最终解决方案
核心思路
问题的突破口在于:Taro 的 onInput 事件对象中包含了光标位置信息
( e.detail.cursor )。
我们只需要:
-
维护一个光标位置状态
-
在输入时记录光标位置
-
在渲染时将光标位置传递给 Input 组件
const [cursor, setCursor] = useState(0);
const [value, setValue] = useState('');<Input
value={value}
cursor={cursor}
onInput={(e) => {
setValue(e.detail.value);
setCursor(e.detail.cursor);
}}
/>
为什么这个方案有效
- Taro 的 cursor 属性:Taro 的 Input 组件支持 cursor
属性,可以显式设置光标位置
-
事件对象中的光标信息:onInput 事件的 e.detail.cursor 提供了当前光标位置
-
状态同步:通过维护光标位置状态,在组件重新渲染时能够正确恢复光标
适用场景
这个方案适用于:
-
✅ Taro 3.x 版本
-
✅ 微信小程序、H5、支付宝小程序等多端
-
✅ 受控 Input 组件
-
✅ Textarea 组件(同样支持 cursor 属性)
注意事项
-
不要混用光标状态:每个输入框应该有独立的光标状态,不要共享
-
重置时清零:当清空输入框时,记得将光标位置重置为 0
-
类型转换:e.detail.cursor 是数字类型,直接使用即可
总结
这个问题的解决关键在于发现了 Taro 事件对象中的 cursor
属性。很多时候,框架提供的解决方案就在事件对象中,只是我们容易忽略。
希望这篇文章能帮助遇到同样问题的开发者节省排查时间!