【问题标题】:How to get postition highlighted text in textarea (coords) angular?如何在文本区域(坐标)角度中获取位置突出显示的文本?
【发布时间】:2022-01-23 10:05:17
【问题描述】:

我想在 textarea 中获得类似的东西。我无法将 textarea 更改为 contentaditable div。如何获取所选文本的位置?我需要这个从上面显示这个弹出窗口

【问题讨论】:

    标签: javascript html angular


    【解决方案1】:

    您应该能够轻松地将其转换为角度代码。 这是您需要做的基本工作,它没有经过全面测试,但它几乎可以工作。

    const textarea = document.getElementById('text')
    const result = document.getElementById('selected')
    const tooltip = document.getElementById('tooltip')
    
    const cols = document.getElementById('text').cols;
    const width = document.getElementById('text').clientWidth;
    const height = window.getComputedStyle(textarea).lineHeight;
    
    
    textarea.onclick = function getSelection() {
      const pos = {
        top: textarea.offsetTop,
        left: textarea.offsetLeft,
      };
      result.textContent = `${textarea.selectionStart}, ${textarea.selectionEnd}`;
      let selection
      if (textarea.selectionStart) {
        selection = textarea.selectionStart;
      } else if (document.selection) {
        textarea.focus();
        const r = document.selection.createRange();
        if (r == null) {
          selection = 0;
        }
        let re = textarea.createTextRange();
        let rc = re.duplicate();
        re.moveToBookmark(r.getBookmark());
        rc.setEndPoint('EndToStart', re);
        selection = rc.text.length;
      } else {
        selection = 0
      }
      const row = Math.floor((selection - 1) / cols);
      const col = (selection - (row * cols));
      const x = Math.floor((col * (width / cols)));
      const y = (parseInt(height) * row);
      tooltip.innerHTML = "<b>row: " + row + "<br>columns" + col + "<br>width: " + width + "</b>";
      tooltip.style.top = `${pos.top+y}px`;
      tooltip.style.left = `${pos.left+x+10}px`;
    }
    textarea {
      height: 80px;
      line-height: 12px;
      overflow-y: scroll;
      display: block;
    }
    
    #tooltip {
      position: absolute;
      background:red;
      color: white;
    }
    <textarea id="text">Lopsum</textarea>
    <span id="tooltip"></span>
    <span id="selected"></span>

    【讨论】:

    • 知道索引如何帮助我显示弹出窗口?我想知道选区所在的高度和宽度
    • 宽度:每次151
    • 那是文本区域的宽度,它是静态的。请先检查代码。
    • 但我需要在 px 中定位所选文本
    • x,y定位应该等于tooltip.style.left, tooltip.style.top
    【解决方案2】:

    我想的唯一方法是创建文本区域的副本(非常类似于 SO,(欧文开尔文的回应)关于文本区域中的高亮词

    由于我们只需要位置,我们可以拆分“texarea”和“background”。此外,使用 another SO 中的 Yurzui 响应,我们可以控制何时调整文本区域的大小

    我们可以想象一个 .html 之类的

    <div class="container">
        <div
          #backdrop
          class="backdrop"
          [style.width.px]="textWidth"
          [style.height.px]="textHeight"
        >
          <div
            class="highlights"
            [innerHTML]="sanitizer.bypassSecurityTrustHtml(highlightedText)"
          ></div>
        </div>
      </div>
      <textarea
        #textarea
        spellcheck="false"
        (resize)="rect = null;"
        (select)="applyHighlights(textarea.value)"
        (mousedown)="mouseDown()"
        (blur)="rect = null"
        [ngModel]="textValue"
        (ngModelChange)="textValue = $event; applyHighlights(textarea.value)"
        (scroll)="handleScroll(); applyHighlights(textarea.value)"
      ></textarea>
    
    <div
      class="tooltip"
      *ngIf="rect"
      [style.top.px]="rect.y"
      [style.left.px]="rect.x"
    ></div>
    

    看到“文本”被隐藏了,因为我们有一个像这样的 div 容器

    .container {
      overflow:hidden;
      width:0;
      height:0;
    }
    

    我们使“text”的尺寸由两个变量“textWidth”和“textHeight”决定

    代码是

      ngOnInit() {
        this.resize();
      }
    
      resize() {
        const event = {
          width: this.$textarea.nativeElement.getBoundingClientRect().width,
          height: this.$textarea.nativeElement.getBoundingClientRect().height,
        };
        this.textWidth = event.width;
        this.textHeight = event.height;
      }
      mouseDown() {
        setTimeout(() => {
          const start = this.$textarea.nativeElement.selectionStart;
          const end = this.$textarea.nativeElement.selectionEnd;
          if (start == end) this.rect = null;
        });
      }
      applyHighlights(text: string) {
        if (text) {
          let start = this.$textarea.nativeElement.selectionStart;
          let end = this.$textarea.nativeElement.selectionEnd;
          if (start == end) this.highlightedText = text;
          else {
            const selected = text.substr(start, end - start);
            this.toolTipText=this.getTooltipText(selected)
            this.highlightedText =
              text.substr(0, start) +
              "<span id='mark'>" +
              selected +
              '</span>' +
              text.substr(end);
            this.resize();
            setTimeout(() => {
              const recArea = this.$textarea.nativeElement.getBoundingClientRect();
              const recText = this.$backdrop.nativeElement.getBoundingClientRect();
    
              const rect = document.getElementById('mark').getBoundingClientRect();
              rect.y += window.scrollY;
              rect.x+=rect.width/2
              this.rect = rect.y - window.scrollY < recArea.y ? null : rect;
            });
          }
        }
    
      }
      handleScroll() {
        var scrollTop = this.$textarea.nativeElement.scrollTop;
        this.$backdrop.nativeElement.scrollTop = scrollTop;
    
        var scrollLeft = this.$textarea.nativeElement.scrollLeft;
        this.$backdrop.nativeElement.scrollLeft = scrollLeft;
      }
    

    我在stackblitz 中放入了一个自定义表单组件(原因是欧文为我做了这个工作

    【讨论】:

      猜你喜欢
      • 2019-05-26
      • 2022-01-06
      • 1970-01-01
      • 2021-04-22
      • 2010-09-13
      • 2020-06-07
      • 2020-05-20
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多