12

我遇到了应该执行以下操作的 Angular2 指令的问题:

  • 检测用户是否输入'.' 特点。
  • 如果下一个字符也是 '.',则删除重复的 '.' 并将光标位置移动到“。”之后 字符

我有上述工作,但是,当将它与 ngModel 结合使用时,每次更新模型时光标位置都会跳到末尾。

输入:

<input type="text" name="test" [(ngModel)]="testInput" testDirective/>

指令:

 import {Directive, ElementRef, Renderer, HostListener, Output, EventEmitter} from '@angular/core';

@Directive({
  selector: '[testDirective][ngModel]'
})
export class TestDirective {


  @Output() ngModelChange: EventEmitter<any> = new EventEmitter();

  constructor(private el: ElementRef,
    private render: Renderer) { }

  @HostListener('keyup', ['$event']) onInputChange(event) {
    // get position
    let pos = this.el.nativeElement.selectionStart;

    let val = this.el.nativeElement.value;

    // if key is '.' and next character is '.', skip position
    if (event.key === '.' &&
      val.charAt(pos) === '.') {

      // remove duplicate periods
      val = val.replace(duplicatePeriods, '.');

      this.render.setElementProperty(this.el.nativeElement, 'value', val);
      this.ngModelChange.emit(val);
      this.el.nativeElement.selectionStart = pos;
      this.el.nativeElement.selectionEnd = pos;

    }
  }
}

这有效,除了光标位置跳到末尾。删除线:

this.ngModelChange.emit(val);

修复问题,光标位置正确,但模型未更新。

任何人都可以推荐一个解决方案吗?或者,也许我对问题采取了错误的方法?

谢谢

4

3 回答 3

14

您需要在 setTimeout() 调用中包含以下几行。原因是您需要给浏览器时间来呈现新值,然后才更改光标位置,在新值呈现后重置。不幸的是,这会导致一些闪烁,但我无法找到任何其他方法让它工作。

setTimeout(() => {
  this.el.nativeElement.selectionStart = pos;
  this.el.nativeElement.selectionEnd = pos;
});
于 2016-12-02T13:04:51.490 回答
7

您可以在没有 setTimout() 的情况下更改光标的位置,并按照setSelectionRange()接受的答案中的建议进行闪烁,如下所示:

this.el.nativeElement.setSelectionRange(position, position, 'none');

示例:堆栈闪电战

于 2018-03-26T16:50:02.070 回答
2

就我而言,不使用 setTimeout 的可接受解决方案是:

  1. 不更新 keyup 上的模型
  2. 更新模型而不是关注焦点

    @HostListener('focusout') focusOut() {
      this.ngModelChange.emit(this.el.nativeElement.value);
    }
    
于 2016-12-02T13:55:03.103 回答