如何在整个文档中查明单词或选择?

时间:2011-03-07 02:35:37

标签: javascript html

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

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

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

3 个答案:

答案 0 :(得分:4)

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

答案 1 :(得分: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 objectanchorNodefocusNode属性进行了解释,您可以尝试解决此问题,但在Internet Explorer中处理TextRange object可能会证明有点问题。

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

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

答案 2 :(得分:1)

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

            var range = document.selection.createRange();

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