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

使用replace与光标定位方法时出现光标跳转异常问题

Angular输入框实时转格鲁吉亚语光标跳转问题修复

问题描述

编写了一段Angular代码,实现输入框内容实时转换为格鲁吉亚语的功能,转换功能正常,但在文本中间输入内容时,光标会自动跳转到文本末尾。

原代码

HTML代码

<mat-form-field *ngIf="operationType != 'joint'"
[ngClass]="{'inputBIG uniqueStander':item?.person?.factualAddress?.length > 50, 'inputBIG':!item?.person?.factualAddress?.length > 50}"
class="inputBIG" appearance="outline">
<mat-label>მისამართი</mat-label>
<input autocomplete="off" autocomplete="off" matInput placeholder=""
  [(ngModel)]="dataaa" name="address" [maxlength]="maxFactAddress"
  (keyup)="iReplaceToGEO('firstAddr')" id="firstAddr">
</mat-form-field>

TypeScript代码

dataaa: any;

public iReplaceToGEO(position?): void {
  console.log('position', position);
  if (position) {
    this.getCaretPosition(position);
  }
  this.dataaa = replacer(this.dataaa);
  if (position) {
    this.setCaretPosition(position, this.caretPos, this.caretPos);
  }
  function replacer(val): string {
    val = val
      .replace(/a/g, 'ა')
      .replace(/b/g, 'ბ')
      .replace(/c/g, 'ც')
      .replace(/d/g, 'დ')
      .replace(/e/g, 'ე')
      .replace(/f/g, 'ფ')
      .replace(/g/g, 'გ')
      .replace(/h/g, 'ჰ')
      .replace(/i/g, 'ი')
      .replace(/j/g, 'ჯ')
      .replace(/k/g, 'კ')
      .replace(/l/g, 'ლ')
      .replace(/m/g, 'მ')
      .replace(/n/g, 'ნ')
      .replace(/o/g, 'ო')
      .replace(/p/g, 'პ')
      .replace(/q/g, 'ქ')
      .replace(/r/g, 'რ')
      .replace(/s/g, 'ს')
      .replace(/t/g, 'ტ')
      .replace(/u/g, 'უ')
      .replace(/v/g, 'ვ')
      .replace(/w/g, 'წ')
      .replace(/x/g, 'ხ')
      .replace(/y/g, 'ყ')
      .replace(/z/g, 'ზ')
      .replace(/J/g, 'ჟ')
      .replace(/T/g, 'თ')
      .replace(/R/g, 'ღ')
      .replace(/S/g, 'შ')
      .replace(/C/g, 'ჩ')
      .replace(/Z/g, 'ძ')
      .replace(/W/g, 'ჭ');
    return val;
  }
}

caretPos: number = 0;
public getCaretPosition(ctrl) {
  let arr: any = document.getElementById(ctrl);
  console.log('getCaretPosition', arr.selectionStart);
  if (arr.selectionStart || arr.selectionStart == '0') {
    this.caretPos = arr.selectionStart;
    return {
      start: arr.selectionStart,
      end: arr.selectionEnd,
    };
  } else {
    this.caretPos = 0;
    return {
      start: 0,
      end: 0,
    };
  }
}
public setCaretPosition(ctrl, start, end) {
  let arr: any = document.getElementById(ctrl);
  console.log('setCaretPosition', arr.setSelectionRange);
  console.log('start', start);
  console.log('end', end);
  if (arr.setSelectionRange) {
    arr.focus();
    arr.setSelectionRange(start, end);
  } else if (arr.createTextRange) {
    var range = arr.createTextRange();
    range.collapse(true);
    range.moveEnd('character', end);
    range.moveStart('character', start);
    range.select();
  }
  this.caretPos = this.caretPos + 1;
}

问题原因

  1. 使用keyup事件触发转换,Angular更新ngModel后会重新绑定输入框值,导致光标被重置到末尾。
  2. setCaretPosition方法中this.caretPos = this.caretPos + 1的代码会错误地偏移光标位置。

修复方案

修改后的HTML代码

<mat-form-field *ngIf="operationType != 'joint'"
[ngClass]="{'inputBIG uniqueStander':item?.person?.factualAddress?.length > 50, 'inputBIG':!item?.person?.factualAddress?.length > 50}"
class="inputBIG" appearance="outline">
<mat-label>მისამართი</mat-label>
<input autocomplete="off" matInput placeholder=""
  [(ngModel)]="dataaa" name="address" [maxlength]="maxFactAddress"
  (input)="iReplaceToGEO('firstAddr')" id="firstAddr">
</mat-form-field>

修改后的TypeScript代码

dataaa: any;

public iReplaceToGEO(position?: string): void {
  if (!position) return;
  const inputElement = document.getElementById(position) as HTMLInputElement;
  // 记录当前光标位置
  const caretPosition = inputElement.selectionStart;

  // 执行文本转换
  this.dataaa = replacer(this.dataaa);

  // 等待Angular完成DOM更新后恢复光标位置
  setTimeout(() => {
    inputElement.focus();
    inputElement.setSelectionRange(caretPosition, caretPosition);
  }, 0);

  function replacer(val: string): string {
    return val
      .replace(/a/g, 'ა')
      .replace(/b/g, 'ბ')
      .replace(/c/g, 'ც')
      .replace(/d/g, 'დ')
      .replace(/e/g, 'ე')
      .replace(/f/g, 'ფ')
      .replace(/g/g, 'გ')
      .replace(/h/g, 'ჰ')
      .replace(/i/g, 'ი')
      .replace(/j/g, 'ჯ')
      .replace(/k/g, 'კ')
      .replace(/l/g, 'ლ')
      .replace(/m/g, 'მ')
      .replace(/n/g, 'ნ')
      .replace(/o/g, 'ო')
      .replace(/p/g, 'პ')
      .replace(/q/g, 'ქ')
      .replace(/r/g, 'რ')
      .replace(/s/g, 'ს')
      .replace(/t/g, 'ტ')
      .replace(/u/g, 'უ')
      .replace(/v/g, 'ვ')
      .replace(/w/g, 'წ')
      .replace(/x/g, 'ხ')
      .replace(/y/g, 'ყ')
      .replace(/z/g, 'ზ')
      .replace(/J/g, 'ჟ')
      .replace(/T/g, 'თ')
      .replace(/R/g, 'ღ')
      .replace(/S/g, 'შ')
      .replace(/C/g, 'ჩ')
      .replace(/Z/g, 'ძ')
      .replace(/W/g, 'ჭ');
  }
}

修复说明

  1. 替换事件类型:将keyup改为input事件,确保输入值变化时立即触发转换,避免按键延迟导致的光标问题。
  2. 简化光标处理逻辑:直接在转换函数内获取和恢复光标位置,移除冗余的getCaretPosition和setCaretPosition方法。
  3. 移除错误代码:删除原代码中导致光标偏移的this.caretPos = this.caretPos + 1语句。
  4. 确保DOM更新后恢复光标:使用setTimeout延迟执行光标恢复操作,等待Angular完成输入框值的绑定更新,保证光标位置设置生效。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.01 19:02:12