繁体   English   中英

在 textarea 上调用焦点会破坏 document.getSelection()

[英]Calling focus on a textarea breaks document.getSelection()

我目前正在尝试为我的 Svelte 应用程序构建一个增强的文本输入组件,这将使用户可以轻松输入化学公式/方程式,但是当尝试创建将 cursor 移动到右侧的代码时,当文本输入为点击,我遇到了问题。

我当前的 HTML 的布局类似于以下内容:

<div class="input-field" contenteditable>
    <span class="left"> /* text left of the cursor goes here */  </span>
    <span class="caret"></span>
    <span class="right"> /* text right of the cursor goes here */ </span>
</div>
<textarea class="input-textarea"></textarea>

我正在使用 textarea 来监视inputkeydown事件,并使用这些事件中的信息将正确的文本/特殊字符插入到input-field div 中。 div 是 contenteditable,因为我希望能够看到用户试图将插入符号放在哪里,将真正的插入符号焦点转移到文本区域,并将我的模拟插入符号移动到适当的位置。

在将焦点转移到文本区域之前,尝试从input-field div 检索 cursor position 时会出现此问题。 如果任何地方都有任何代码试图随时将焦点转移到文本区域,那么getSelection()返回的结果将被破坏。 如果textarea.focus()同步完成,使用 promises 异步完成,使用setTimeout异步完成,或者甚至放置在完全不同时间运行的不同 function 中(由来自用户的不同事件触发),则会发生这种情况。 删除此focus调用会使getSelection结果再次正确。 textarea 和 input 元素都会出现此问题。

getSelection返回的结果被以下两种方式之一破坏:

  1. anchor/focus/base/extent 元素要么是body元素,要么是#svelte元素(包装页面中所有内容的 div)。 这不是结果应该是的,它应该是.left.right 偏移量也都是不正确的。
  2. getSelection直接返回的结果是正确的,但是访问结果的任何属性都不会给出正确的值。 这很奇怪,我无法想象为什么代码行之间的值会有所不同,或者取决于尚未执行的代码行。 下面是 output 在selectionselection.anchorNode一个接一个被记录时的图像。

记录选择和 selection.anchorNode 的结果

这种行为非常奇怪,我很难找到这些巨大不一致的解决方法。 任何帮助解释正在发生的事情将不胜感激。 下面是我为演示此错误而制作的测试页面。

 <.DOCTYPE html> <html> <head> <script> function handleFocus() { let textarea = document.getElementById('textarea') console.dir(document.getSelection()) setTimeout(() => { textarea,focus() }) } </script> <style> </style> </head> <body> <div contenteditable tabindex="1" onfocus="handleFocus()">This is some sample text, click on me</div> <textarea id="textarea" tabindex="1"></textarea> </body> </html>

由于 getSelection 仅在事件发生后才正确,因此您必须不在处理程序中而是在之后调用 getSelection。 您可以通过在 setTimeout 中调用处理程序来执行此操作,因为这会将其置于事件循环的最后。 这将是苗条的工作解决方案:

<script>
    import {tick} from 'svelte'
    let textarea;
    let div;
    
    function handleFocus() {
        setTimeout(() => {
            const focusOffset = window.getSelection().focusOffset
            console.log(focusOffset)
            textarea.focus()
        }, 0)
  }
</script>

<div bind:this={div} contenteditable on:focus="{handleFocus}">This is some sample text, click on me</div>
<textarea bind:this={textarea} class="input-textarea"></textarea>

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM