如何用跨度包装选定的单词

时间:2013-12-15 18:41:03

标签: javascript jquery html firefox selection

我希望能够将鼠标悬停在网页上的任何字词上,并在该字词上方弹出该字词。如果没有巨大的性能问题,这似乎几乎是不可能的,所以我尝试双击而不是悬停。

双击,我可以检测到单词的文本,但我无法对页面中的单词本身做任何事情。基本上,我想用span标记包装所选文本,以便我可以相对于它定位事物。我之前看过它用荧光笔做过,但我不知道怎么做。

注意:这只需要在Firefox中使用。

2 个答案:

答案 0 :(得分:3)

您可以使用以下功能:

var range = window.getSelection().getRangeAt(0);
var newNode = document.createElement("b");
range.surroundContents(newNode);

这会使用b-tag围绕您的选择。

答案 1 :(得分:1)

mouseover事件并非不可能。您可以使用{20}在Firefox 20及更高版本中标准化和支持的document.caretPositionFromPoint(),并回归到WebKit的专有等效项。

http://jsfiddle.net/2zzjL/6/

处理鼠标事件的步骤如下:

  • 隐藏单词弹出窗口(如果显示)
  • 从事件中获取光标坐标
  • 使用document.caretPositionFromPoint()或等效的
  • 从光标坐标创建范围
  • 如果范围的容器节点是文本节点,则其偏移量是文本节点文本中的字符索引
  • 从那里开始,在文本节点的文本中向前和向后展开,直到我们点击空格来获取单词
  • 更新范围以包含整个单词
  • 在范围内调用getBoundingClientRect()以获取字词
  • 的坐标
  • 将单词弹出元素放置在远离这些坐标的某个偏移位置并显示

演示非常有限(例如,它不适用于跨越元素边界的单词,单词检测非常粗糙,并且有足够的优化空间)但应该足以让您入门。它适用于当前浏览器,IE除外,它不支持document.caretPositionFromPoint()

以下是关键代码:

function expandToWord(str, offset) {
    var start = offset;
    while ( start >= 1 && /\S/.test( str.charAt(start - 1) ) ) {
        --start;
    }

    var end = offset, len = str.length;
    while ( end < len && /\S/.test( str.charAt(end) ) ) {
        ++end;
    }

    return {
        start: start,
        end: end,
        word: str.slice(start, end)
    };
}

var wordDiv = document.createElement("div");
wordDiv.className = "word";

var createRangeFromPoint = (function(doc) {
    // Try standards-based method first
    if (typeof doc.caretPositionFromPoint != "undefined") {
        return function(x, y) {
            var pos = doc.caretPositionFromPoint(x, y);
            var range = null;
            if (pos) {
                range = doc.createRange();
                range.setStart(pos.offsetNode, pos.offset);
                range.collapse(true);
            }
            return range;
        };
    }

    // Now try WebKit's proprietary method
    else if (typeof doc.caretRangeFromPoint != "undefined") {
        return function(x, y) {
            return doc.caretRangeFromPoint(x, y);
        };
    }

    // Give up
    else {
        return function() { return null; };
    }
})(document);

function mouseEventHandler(e) {
    if (wordDiv.parentNode) {
        wordDiv.parentNode.removeChild(wordDiv);
    }
    var range = createRangeFromPoint(e.clientX, e.clientY);
    if (range) {
        if (range.startContainer.nodeType == 3) {
            var wordInfo = expandToWord(range.startContainer.data, range.startOffset);
            if (wordInfo.word) {
                range.setStart(range.startContainer, wordInfo.start);
                range.setEnd(range.startContainer, wordInfo.end);

                var rect = range.getBoundingClientRect();

                // Get the difference between client and page coordinates from the event
                // for positioning the word div
                var offsetX = e.clientX - e.pageX;
                var offsetY = e.clientY - e.pageY;

                wordDiv.style.left = (rect.left + offsetX) + "px";
                wordDiv.style.top = (rect.top + offsetY - 20) + "px";
                wordDiv.innerHTML = "";
                wordDiv.appendChild( document.createTextNode(wordInfo.word) );

                document.body.appendChild(wordDiv);
            }
        }
    }
}

document.onmousemove = mouseEventHandler;
document.onmouseover = mouseEventHandler;
document.onmouseout = mouseEventHandler;