You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

React Textarea光标自动跳至末尾问题排查与修复求助

问题:React Textarea 编辑时光标自动跳转到末尾

在医生开检查单的React应用中,textarea组件存在以下问题:正常输入时光标行为正常,但将光标移至文本中间编辑时,输入一个字符后光标会自动跳转到末尾。如果移除onChange中的逻辑,光标恢复正常,但无法保存textarea的内容。

原组件代码

Textarea组件

React.createElement('textarea', {
  name: 'SpecialInstruction',
  id: 'rad_SpecialInstruction',
  value: this.props.stateobj.SpecialInstruction,
  onFocus: (event) => {
    const currentValue = event.target.value;
    // event.target.value = currentValue + '.';
    // this.handleOrderChange(event); // trigger the onChange event handler
  },
  onChange: this.handleOrderChange,
  className: 'form-control',
  maxLength: 512,
  style: { fontSize: '12px !important' },
})

原handleOrderChange方法

_this.handleOrderChange = function (e) {
  _this.props.AddModuleState(_defineProperty({}, e.target.name, e.target.value), "RAD");

  // Store the current cursor position
  const cursorPosition = e.target.selectionStart;

  // Prevent the default behavior of the input element
  e.preventDefault();

  _this.props.AddModuleState(_defineProperty({}, e.target.name, e.target.value), "RAD");

  // Restore the cursor position
  e.target.setSelectionRange(cursorPosition, cursorPosition);
};

已尝试的修复

移除重复的AddModuleState调用、删除e.preventDefault(),并添加setTimeout恢复光标位置,但问题未完全解决:

_this.handleOrderChange = function (e) {
  _this.props.AddModuleState(_defineProperty({}, e.target.name, e.target.value), "RAD");

  // Store the current cursor position
  const cursorPosition = e.target.selectionStart;

  setTimeout(() => {
    e.target.setSelectionRange(cursorPosition, cursorPosition);
  }, 0);   
};

解决方案

问题核心是React受控组件的重新渲染会重置光标位置:当AddModuleState更新state后,组件重新渲染,textarea会根据新的value值重新渲染,光标被默认重置到末尾。之前的setTimeout因执行时机不确定,偶尔失效。

步骤1:给textarea添加ref

通过ref获取textarea的DOM元素,方便后续操作:

React.createElement('textarea', {
  ref: (el) => { this.textareaRef = el; }, // 新增ref
  name: 'SpecialInstruction',
  id: 'rad_SpecialInstruction',
  value: this.props.stateobj.SpecialInstruction,
  onFocus: (event) => {
    const currentValue = event.target.value;
    // 保留原有注释代码
  },
  onChange: this.handleOrderChange,
  className: 'form-control',
  maxLength: 512,
  style: { fontSize: '12px !important' },
})

步骤2:在onChange中保存光标位置

将光标位置保存到组件实例属性中,避免在重新渲染时丢失:

_this.handleOrderChange = function (e) {
  // 保存当前光标位置到组件实例
  _this.cursorPosition = e.target.selectionStart;
  // 更新state保存内容
  _this.props.AddModuleState(_defineProperty({}, e.target.name, e.target.value), "RAD");
};

步骤3:在componentDidUpdate中恢复光标

利用React生命周期,在组件更新完成后(确保textarea已重新渲染)恢复光标位置:

componentDidUpdate(prevProps) {
  // 仅当SpecialInstruction内容变化时,恢复光标
  if (this.props.stateobj.SpecialInstruction !== prevProps.stateobj.SpecialInstruction && this.cursorPosition !== undefined) {
    this.textareaRef.setSelectionRange(this.cursorPosition, this.cursorPosition);
    // 重置光标位置,避免后续不必要的恢复
    this.cursorPosition = undefined;
  }
}

这种方法通过明确的生命周期时机控制光标恢复,比setTimeout更可靠,能彻底解决光标跳转问题,同时保证内容正常保存。

内容的提问来源于stack exchange,提问作者Dragut

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.25 00:27:10