如何使用JavaScript将选择范围扩展到单词边界?

Ina*_*ist 7 html javascript dom selection

我正在使用此答案中显示的技术将网页的选择扩展到单词边界:

function snapSelectionToWord() {
    var sel;

    // Check for existence of window.getSelection() and that it has a
    // modify() method. IE 9 has both selection APIs but no modify() method.
    if (window.getSelection && (sel = window.getSelection()).modify) {
        sel = window.getSelection();
        if (!sel.isCollapsed) {

            // Detect if selection is backwards
            var range = document.createRange();
            range.setStart(sel.anchorNode, sel.anchorOffset);
            range.setEnd(sel.focusNode, sel.focusOffset);
            var backwards = range.collapsed;
            range.detach();

            // modify() works on the focus of the selection
            var endNode = sel.focusNode, endOffset = sel.focusOffset;
            sel.collapse(sel.anchorNode, sel.anchorOffset);
            if (backwards) {
                sel.modify("move", "forward", "word");
                sel.extend(endNode, endOffset);
                sel.modify("extend", "backward", "word");

            } else {
                sel.modify("move", "backward", "word");
                sel.extend(endNode, endOffset);
                sel.modify("extend", "forward", "word");
            }
        }
    } else if ( (sel = document.selection) && sel.type != "Control") {
        var textRange = sel.createRange();
        if (textRange.text) {
            textRange.expand("word");
            // Move the end back to not include the word's trailing space(s),
            // if necessary
            while (/\s$/.test(textRange.text)) {
                textRange.moveEnd("character", -1);
            }
            textRange.select();
        }
    }
}?
Run Code Online (Sandbox Code Playgroud)

到现在为止还挺好.但是如果你snapSelectionToWord在选择中多次调用该函数,它会在每次调用时向两个方向向外扩展一个单词,如果你想在选择文本时多次调用它,那就不好了.

这是一个实时的jsFiddle示例,允许您重复单击"Snap"按钮,这将演示此问题.

如何修复原始解决方案,以便它不会扩展选择,如果它已经在单词边界上?

  • 我更愿意对最初的解决方案发表评论,但遗憾的是,StackOverflow业力旅还没有给予足够的业力 - 否则,我只会问那里.而且我不确定如何解决问题,因此我不会编辑原始解决方案.

编辑:为每个请求添加代码段

Tim*_*own 9

我写了那个样本.由于你指出的原因,我从来没有对它感到满意,也因为它在所有浏览器中都不能保持一致(或者在Opera中一直没有).

我一直在为我的Rangy库开发一个跨浏览器的解决方案.当前版本被描述为alpha,但它运行良好.这是一个演示:

http://rangy.googlecode.com/svn/trunk/demos/textrange.html

这是你的演示,修改为使用Rangy:

http://jsfiddle.net/timdown/RgZ8r/

至关重要的是

rangy.getSelection().expand("word");
Run Code Online (Sandbox Code Playgroud)

如果你不想像Rangy那样使用重量级的东西(使用TextRange模块可以使用50KB的代码)那么就可以改进原始代码(正如Matt M在他的回答中所做的那样),但它仍然有局限性.


Mat*_*tag 6

也许在你拼写单词之前尝试从任一方向弹出一个字符:

        if (backwards) {
            sel.modify("move", "backward", "character");
            sel.modify("move", "forward", "word");
            sel.extend(endNode, endOffset);
            sel.modify("extend", "forward", "character");
            sel.modify("extend", "backward", "word");

        } else {
            sel.modify("move", "forward", "character");
            sel.modify("move", "backward", "word");
            sel.extend(endNode, endOffset);
            sel.modify("extend", "backward", "character");
            sel.modify("extend", "forward", "word");
        }
Run Code Online (Sandbox Code Playgroud)

http://jsfiddle.net/3RAkZ/

  • +1.在Google Chrome上工作.这是一个删除这些冗余代码的较小版本:http://jsfiddle.net/3RAkZ/1/ (2认同)