【问题标题】:How do you pinpoint a word or a selection in the entire document?您如何精确定位整个文档中的一个词或一个选择?
【发布时间】:2014-05-10 22:13:56
【问题描述】:

我正在尝试突出显示我网站上的部分文字。此突出显示的文本将为特定用户保存在数据库中,当再次打开文档时,它将显示先前突出显示的文本。我以为我会使用 javascript 来突出显示文本,但我似乎无法找到一种方法来确定我突出显示的单词的位置。

function getSelText()
{
    var txt = '';
     if (window.getSelection)
    {
        txt = window.getSelection();
             }
    else if (document.getSelection)
    {
        txt = document.getSelection();
            }
    else if (document.selection)
    {
        txt = document.selection.createRange().text;
            }
    else return "";
    return txt;
}

我正在使用它来获取选择,但我无法确定选择在文本中的位置。最大的烦恼是当我在行或文本中有重复项时,所以如果我要使用搜索,那么我会找到第一个实例,而不是我正在寻找的那个。

所以问题是:如何在整个文档中精确定位一个词或一个选择?

【问题讨论】:

    标签: javascript html


    【解决方案1】:

    您可以为此使用我的 Rangy 库及其 selection serialization module。 Rangy 的核心为所有浏览器提供了一致的选择和范围 API,序列化程序模块通过将每个选择边界转换为通过文档的路径来构建此 API。有关详细信息,请参阅链接文档。

    【讨论】:

      【解决方案2】:

      这当然不是一项简单的任务,因为您面临两个主要问题,即在当前文档中定位文本,然后在后续页面加载时再次找到它。如果您的页面内容可能发生变化,问题会更加复杂,因为您甚至不能依靠文本的相对位置来保持不变。

      考虑到所需的努力,您可能想考虑这是否是您尝试完成的任何事情的最佳方法,但这里有一些可能会让您朝着正确的方向开始:

      function getSelection() {
          var selection, position;
      
          if (window.getSelection) {
              selection = window.getSelection();
      
              if (selection && !selection.isCollapsed) {
                  position = {
                      'offset': selection.anchorOffset,
                      'length': selection.toString().length,
                      // We're assuming this will be a text node
                      'node': selection.anchorNode.parentNode
                  };
              }
          } else if (document.selection) {
              selection = document.selection.createRange();
      
              if (selection && selection.text.length) {
                  var text = selection.parentElement().innerText,
                      range = document.body.createTextRange(),
                      last = 0, index = -1;
      
                  range.moveToElementText(selection.parentElement());
      
                  // Figure out which instance of the selected text in the overall
                  // text is the correct one by walking through the occurrences
                  while ((index = text.indexOf(selection.text, ++index)) !== -1) {
                      range.moveStart('character', index - last);
                      last = index;
      
                      if (selection.offsetLeft == range.offsetLeft && selection.offsetTop == range.offsetTop) {
                          break;
                      }
                  }
      
                  position = {
                      'offset': index,
                      'length': selection.text.length,
                      'node': selection.parentElement()
                  };
              }
          }
      
          return position;
      }
      

      以及再次选择文本的方法:

      function setSelection(position) {
          if (!position || !position.node) {
              return;
          }
      
          var selection, range, element;
      
          if (document.createRange) {
              element = position.node.childNodes[0];
              range = document.createRange();
              range.setStart(element, position.offset);
              range.setEnd(element, position.offset + position.length);
              selection = window.getSelection();
              selection.removeAllRanges();
              selection.addRange(range);
          } else if (document.body.createTextRange) {
              range = document.body.createTextRange();
              range.moveToElementText(position.node);
              range.collapse(true);
              range.move('character', position.offset);
              range.moveEnd('character', position.length);
              range.select();
          }
      }
      

      这段代码做了一个相当幼稚的假设,即选定的文本都驻留在同一个 DOM 元素中。如果用户选择任意文本,则很有可能不会出现这种情况。

      鉴于Selection object 使用anchorNodefocusNode 属性解决了这个问题,您可以尝试解决这个问题,但在Internet Explorer 中处理TextRange object 可能会有点问题。

      还有一个问题是如何跨页面请求跟踪position.node 值。在我的 jsFiddle sample 中,我使用了 selector-generating jQuery function 的略微修改版本来生成一个选择器字符串,该字符串可以保存并用于稍后重新选择正确的节点。请注意,该过程相对简单,因此您可以在不使用 jQuery 的情况下轻松完成 - 在这种情况下只是碰巧节省了一些精力。

      当然,如果您在访问之间更改 DOM,这种方法可能会相当不稳定。如果你不是,我觉得它可能是更可靠的选择之一。

      【讨论】:

      • 这与我的 Rangy 库中的 Serializer 模块类似(但不太完全实现):code.google.com/p/rangy/wiki/SerializerModule
      • @TimDown 哦,哇,鉴于我过去的积极经验,我在写答案时没有想到 Rangy,我有点惭愧。感谢您的链接。
      • @TimStone 如果我尝试从“世界”中选择字母,比如只有“orl”。但我从右到左选择开始,然后偏移位置给我 3,但它应该给我 1,因为 o 排在第一位,而不是 l .. 那么我该如何处理从右到左选择字母/单词?
      【解决方案3】:

      createRange 创建一个 textRange 对象。它有各种有用的信息:

                  var range = document.selection.createRange();
      
                  var left = range.boundingLeft;
                  var top = range.boundingTop;
      

      【讨论】:

      • 那行不通,因为我没有文本区域可言,我只是有一个从数据库中读取并显示的文档。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2011-02-19
      • 2023-03-19
      • 1970-01-01
      • 2017-02-16
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多