【问题标题】:Javascript keydown event doesn´t give me the char @ in EDGEJavascript keydown 事件没有给我 EDGE 中的字符 @
【发布时间】:2019-03-22 08:46:38
【问题描述】:

我正在处理一个提及指令,基本上当用户在输入字段中输入时(在这种情况下是一个带有contentEditable=true 的 div),将显示一个用户列表,然后在其中插入用户名一种特定的格式,现在列表将在用户按下@ 后显示,对于 chrome 和 firefox 工作得很好但对于 EDGE 和 IE(不幸的是我需要支持)不起作用,因为在这种情况下 @ 显然不存在。

现在按键我使用@HostListener('keydown', ['$event'])

主机监听器

  @HostListener('keydown', ['$event']) keyHandler(event: any, nativeElement: HTMLInputElement = this._element.nativeElement) {
    let val: string = getValue(nativeElement);
    let pos = getCaretPosition(nativeElement, this.iframe);
    let charPressed = this.keyCodeSpecified ? event.keyCode : event.key;
    if (!charPressed) {
      let charCode = event.which || event.keyCode;
      if (!event.shiftKey && (charCode >= 65 && charCode <= 90)) {
        charPressed = String.fromCharCode(charCode + 32);
      } else if (event.shiftKey && charCode === KEY_2) {
        charPressed = this.triggerChar;
      } else {
        charPressed = String.fromCharCode(event.which || event.keyCode);
      }
    }
    if (event.keyCode == KEY_ENTER && event.wasClick && pos < this.startPos) {
      // put caret back in position prior to contenteditable menu click
      pos = this.startNode.length;
      setCaretPosition(this.startNode, pos, this.iframe);
    }
    // console.log('=== keyHandler', this.startPos, pos, val, charPressed, event);
    this.triggerList(event, charPressed, nativeElement, val, pos);
  }

现在你可以看到我正在使用 event.keycode 和 event.key 从事件 keydown 中获取密钥,我将 do 值传递给方法 this.triggerList()

当且仅当用户按下触发字符(this.triggerChar)时,这基本上会显示提及选项列表。

触发器列表方法

  private triggerList(event, charPressed, nativeElement, val, pos): any {
    if (charPressed == this.triggerChar) {
      this.startPos = pos;
      this.startNode = (this.iframe ? this.iframe.contentWindow.getSelection() : window.getSelection()).anchorNode;
      // console.log('=== HERE CHAR', this.startNode, this.startPos);

      // check if mentioning is allowed based on the text before the mention start char
      if (!this.configService.appConfig.platform.EDGE) {
        let position = this.getHtmlCaretPosition(nativeElement);
        const charBefore = val[position - 1];

        if (charBefore == undefined || charBefore.trim() == '' || charBefore == ':') {
          this.log.trace('Start mentioning');
          this.stopSearch = false;
          this.searchString = null;
          this.showSearchList(nativeElement);
          this.updateSearchList();
        }
      } else {
        this.stopSearch = false;
        this.searchString = null;
        this.showSearchList(nativeElement);
        this.updateSearchList();
      }
    } else if (this.startPos >= 0 && !this.stopSearch) {
      if (pos <= this.startPos) {
        this.searchList.hidden = true;
      }
      // ignore shift when pressed alone, but not when used with another key
      else if (event.keyCode !== KEY_SHIFT && !event.metaKey && !event.altKey && !event.ctrlKey && pos > this.startPos) {
        if (event.keyCode === KEY_SPACE) {
          this.startPos = -1;
        } else if (event.keyCode === KEY_BACKSPACE && pos > 0) {
          pos--;
          if (pos == 0) {
            this.stopSearch = true;
          }
          this.searchList.hidden = this.stopSearch;
        } else if (!this.searchList.hidden) {
          if (event.keyCode === KEY_TAB || event.keyCode === KEY_ENTER) {
            this.stopEvent(event);
            this.searchList.hidden = true;
            // value is inserted without a trailing space for consistency
            // between element types (div and iframe do not preserve the space)
            let textValue = this.mentionSelect(this.searchList.activeItem);
            insertValue(nativeElement, this.startPos, pos, textValue, this.iframe);
            this.emitSelection(nativeElement);
            if (this.htmlStyling) {
              let quillElement = document.querySelector('.ql-editor');
              let innerHtml = quillElement.innerHTML;
              let strings = innerHtml.split(textValue);
              if (strings.length === 2) {
                innerHtml = `${strings[0]}<span id="mention${textValue.substring(1)}${strings.length - 1}" style="color: #0065FF; background: rgba(0,101,255,.2)">${textValue}</span> ${strings[1]}`;
              } else {
                let openSpan = false;
                innerHtml = strings.reduce((total, current, currentIndex) => {
                  if (current.indexOf(`mention${textValue.substring(1)}`) > 0) {
                    return `${total}${openSpan ? '</span> ' : ''}${current}${textValue}`;
                  } else if (openSpan) {
                    return `${total}</span> ${currentIndex < strings.length - 1 ? current + textValue : current}`;
                  } else {
                    openSpan = true;
                    return `${total}${current}<span id="mention${textValue.substring(1)}${strings.length - 1}" style="color: #0065FF; background: rgba(0,101,255,.2)">${textValue}`;
                  }
                }, '');
              }
              quillElement.innerHTML = innerHtml;
              // tslint:disable-next-line:no-angle-bracket-type-assertion
              let mentionElement: HTMLInputElement = document.getElementById(`mention${textValue.substring(1)}${strings.length - 1}`) as HTMLInputElement;
              // tslint:disable-next-line:no-angle-bracket-type-assertion
              setCaretPosition(mentionElement.nextSibling as HTMLInputElement, 1);
            }
            // fire input event so angular bindings are updated
            if ('createEvent' in document) {
              let evt = document.createEvent('HTMLEvents');
              evt.initEvent('input', false, true);
              nativeElement.dispatchEvent(evt);
            }
            this.startPos = -1;
            return false;
          } else if (event.keyCode === KEY_ESCAPE) {
            this.stopEvent(event);
            this.searchList.hidden = true;
            this.stopSearch = true;
            return false;
          } else if (event.keyCode === KEY_DOWN) {
            this.stopEvent(event);
            this.searchList.activateNextItem();
            return false;
          } else if (event.keyCode === KEY_UP) {
            this.stopEvent(event);
            this.searchList.activatePreviousItem();
            return false;
          }
        }

        if (event.keyCode === KEY_LEFT || event.keyCode === KEY_RIGHT) {
          this.stopEvent(event);
          return false;
        } else {
          let mention = val.substring(this.startPos + 1, pos);
          if (event.keyCode !== KEY_BACKSPACE) {
            mention += charPressed;
          }
          this.searchString = mention;
          this.searchTerm.emit(this.searchString);
          this.updateSearchList();
        }
      }
    }
  }

现在这里的问题是如果用户插入字符@需要使用ALT + Q的组合,EDGE只检测ALT然后Q,比较firefox和chrome用@组合987654338@ 检测 @ 因为这个原因列表不显示,因为字符永远不匹配。

【问题讨论】:

标签: javascript angular typescript


【解决方案1】:

首先我将事件keydown 替换为keypress,然后将字符保存在变量charPress 中,我创建一个条件来检查浏览器是EDGE 还是IE,并使用event.charCode 获取字符代码最后使用String.fromCharCode(event.charCode) 将其转换为字符串,如下所示。

  @HostListener('keypress', ['$event']) keyHandler(event: any, nativeElement: HTMLInputElement = this._element.nativeElement) {
    let val: string = getValue(nativeElement);
    let pos = getCaretPosition(nativeElement, this.iframe);
    let charPressed = this.keyCodeSpecified ? event.keyCode : event.key;
    if (this.configService.appConfig.platform.EDGE) {
      charPressed = String.fromCharCode(event.charCode);
    }
    ......

【讨论】:

    猜你喜欢
    • 2016-03-18
    • 1970-01-01
    • 2013-02-12
    • 2023-03-23
    • 2012-08-05
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多