【问题标题】:How to measure word/caret position in Google Docs?如何测量 Google Docs 中的单词/插入符号位置?
【发布时间】:2012-04-10 15:37:23
【问题描述】:

对于那些没有使用过 Google 文档编辑器的人,这里简要解释一下它的工作原理:

  • Google 文档没有可见的可编辑 textarea 或 contentEditable 元素。
  • Google Docs 在单独的 iFrame 中侦听 keydown/press/up,他们将 OS 光标放置在其中以进行事件侦听。
  • 当 iFrame 捕获事件时,Google 会通过对可见文档执行等效操作来处理它。
  • Google 文档中的“插入符号”是一个 DIV,其样式和脚本看起来和行为都像操作系统光标。

除此之外,这是我的要求:

我正在开发一个与 Google Doc 交互的插件,我需要能够做两件事:

  • 使用不透明的叠加 DIV 突出显示单词。
  • 确定字词内的光标位置。

我已经用尽了很多关于如何处理这个问题的想法,但到目前为止,我只设法为后一个问题找到了一个错误的解决方案(我执行退格键,确定文本更改的位置并撤消退格)。

我正在寻找您能想出的所有最佳想法来解决这些问题。它们不需要跨浏览器,但它们确实需要能够变成强大的东西,也可以处理诸如字体大小更改中线之类的事情。

一些额外的信息解释了 Google Doc 在 HTML 中的样子:

<wrapper> // Simplified wrapper containing margins, pagination and similar
  <div class="kix-paragraphrenderer"> // single DIV per page wrapping all content
    // Multiple paragraphs separated by linebreak created by Enter key:
    <div class="kix-paragraphrendeder">...</div>
    <div class="kix-paragraphrendeder">...</div>
    <div class="kix-paragraphrendeder">
      // Multiple wrapper divs created by Google's word wrapping:
      <div class="kix-lineview">...</div>
      <div class="kix-lineview">...</div>
      <div class="kix-lineview">
        // Single inner wrapper, still full width of first wrapper paragraph:
        <div class="kix-lineview-content">
          // Single wrapper SPAN containing full text of the line, but not display:block
          <span class="kix-lineview-text-block">
            // Multiple spans, one per new font change such as normal/bold text,
              // change in font size, indentation and similar:
            <span>This is normal text</span>
            <span style="font-size:40px; padding-left:4px;">This larger text.</span>
            <span style="font-weight:bold; padding-left:10px;">This is bold text</span>
            <span style="padding-left:4px;">More normal text</span>
          </span>
        </div>
      </div>
    </div>
  </div>
</wrapper>

【问题讨论】:

    标签: javascript google-docs html caret cursor-position


    【解决方案1】:

    经过更多修改后,我得出的结论是,尝试以编程方式确定光标相对于 &lt;span&gt; 中的字母的位置非常麻烦(如果不是不可能的话),因为 &lt;span&gt; 是最小的元素是可衡量的(如果我错了,请纠正我)。

    那么如何解决这个问题呢?这是我最终做的:

    • 我创建了一个屏幕外定位&lt;div&gt;
    • 我得到了当前段落的文本 (&lt;div class="kix-paragraphrenderer"&gt;) - 我可以得到整个文本,但想限制计算负载。
    • 我通过以下方式循环遍历其子级来提取段落的每个单个字符:
      • 循环浏览段落的 linveviews (&lt;div class="kix-lineview"&gt;)
      • 获取lineview内容(&lt;div class="kix-lineview-content"&gt;)
      • 循环浏览 lineview 内容的文本块 (&lt;span class="kix-lineview-text-block"&gt;)
      • 循环遍历文本块的&lt;span&gt;
      • 循环通过innerText&lt;span&gt;
      • 我在我的屏幕外&lt;div&gt; 中附加每个字符从当前&lt;span&gt;style.cssText 中提取的当前应用样式
      • 对于附加的每个字符,我测量&lt;div&gt; 的宽度并将其保存在一个数组中。我现在有了每个字符的位置。
    • 我测量了光标相对于宽度的位置,瞧 - 我知道光标在文本中的位置。

    这显然有点简单(我省略了有关不同元素的边距和填充的详细信息),但它涵盖了如何获取光标位置背后的想法。

    它工作得很好,但有很多陷阱和需要大量的测量。最重要的是,如果您想将其用于任何内容,还需要对文本进行后解析,因为innerText 中并不总是包含制表符、空格和换行符(取决于这些在文本中的位置,Google 可能会或可能无法通过新元素的定位来制作它们)。

    【讨论】:

      【解决方案2】:

      两年前我制作了类似 Kix 的 Google Docs。对于任何 HTML 设计,是的,也适用于 IE6 :-) 怎么样?我们只需要计算字母的绝对位置。如何?用没有布局的内联元素替换 textNode,这很重要,然后使用 Element.getClientRects 我记得我还需要只包装字母并通过快速可靠的 https://developer.mozilla.org/en-US/docs/Web/API/Element.getBoundingClientRect 计算其位置

      如何检测 home 键和 end 键的行和换行的技巧是基于一些垂直的启发式字母位置变化。就像基线不同,而不是停止插入符号行走。它非常快,有任何标记,没有任何缓存。圣杯:)

      唯一无法解决的问题是合理的文本,因为字母是随机分布的,它们之间的空格是不可计算的。

      那个项目现在已经死了http://webeena.com。糟糕的管理扼杀了它(我几乎也是)。

      【讨论】:

      • 不确定我是否按照您的意思替换 textNode,但自从我的回答以来,我已经更新了我的代码,以执行与您所建议的类似的操作。与更改任何 HTML 不同,我创建了一个 Range 对象并操作开始和结束节点,直到 Range.getBoundingClientRect() 可以通过与 cursor.getBoundingClientRect() 比较来告诉我光标在哪里。
      猜你喜欢
      • 1970-01-01
      • 2017-12-06
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-05-21
      • 1970-01-01
      • 1970-01-01
      • 2020-08-17
      相关资源
      最近更新 更多