2011-03-07 47 views
8

我想突出显示我网站上的部分文字。该突出显示的文本将被保存为数据库中的特定用户,并且当文档再次打开时,它将显示先前突出显示的文本。我认为我会使用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; 
} 

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

所以问题是:你如何在整个文档中找出一个词或一个选择?

回答

4

您可以使用我的Rangy库和它的selection serialization module。 Rangy的核心为所有浏览器提供了一致的选择和范围API,并且通过将每个选择边界转换为文档中的路径,串行器模块在此基础上进行构建。有关更多详细信息,请参阅链接文档

1

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

  var range = document.selection.createRange(); 

      var left = range.boundingLeft; 
      var top = range.boundingTop; 
+0

因为我没有textarea可言,所以这不会真正起作用,我只是从文件中读出数据并显示出来。 – vman 2011-03-07 03:31:40

3

这当然不是一件容易的事情,因为你面对当前文档中定位文本,然后能够找到它的两大问题再次在后续页面加载。如果您的页面内容可能发生变化,问题就会变得更加复杂,因为您甚至不能依靠文本的相对位置来保持相同。

你可能要考虑这是否是任何你要完成给定所需要的努力,最好的办法,但这里的东西,可能让你在正确的方向开始:

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,此方法可能会相当不稳定。如果你不是,我觉得它可能是更可靠的选择之一。

+1

这是一个和我的Rangy库中的串行器模块类似的(但不太完全实现)的方法:http://code.google.com/p/rangy/wiki/SerializerModule – 2011-03-07 10:35:42

+0

@TimDown哦哇,我有点惭愧考虑到我过去积极的经验,我在写出答案时没有想到Rangy。感谢您的链接。 – 2011-03-07 15:57:53

+0

非常感谢一群rangy图书馆做的伎俩。 – vman 2011-03-14 02:26:30

相关问题