9

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

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();
        }
    }
}​

到现在为止还挺好。但是,如果您snapSelectionToWord在所选内容上多次调用该函数,则每次调用时它都会在两个方向上向外扩展一个单词,如果您想在选择文本时多次调用它,这并不好。

这是一个现场 jsFiddle 示例,它允许您重复单击“Snap”按钮,它演示了问题。

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

  • 我更愿意对原始解决方案发表评论,但遗憾的是,StackOverflow 业力旅还没有给我足够的业力——否则,我只会在那里问。而且我不确定如何解决这个问题,所以我不会编辑原始解决方案。

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

4

3 回答 3

9

我写了那个样本。由于您指出的原因,我从未对它感到满意,并且还因为它在所有浏览器中(或在 Opera 中根本没有)都无法始终如一地工作。

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

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

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

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

关键线是

rangy.getSelection().expand("word");

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

于 2012-06-09T22:50:30.840 回答
7

也许在你捕捉到单词之前尝试在任一方向弹出一个字符:

        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");
        }

http://jsfiddle.net/3RAkZ/

于 2012-06-09T21:33:11.027 回答
1

您的代码在阿拉伯语文本中无法正常工作您可以尝试使用此代码段代替

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) {
           
           var rng2 = sel.getRangeAt(0);
           var startOffset = rng2.startOffset;
           startOffset = 0
           for (var i = rng2.startOffset; i >= 0; i--) {
              if (rng2.startContainer.data[i].match(/\S/) != null) {
                 startOffset++;
              } else
                 break;
           }
           var endOffset = rng2.endOffset;
           endOffset = 0;
           for (var i = rng2.endOffset; i < rng2.endContainer.data.length; i++)
              if (rng2.endContainer.data[i].match(/\S/)) {
                 endOffset++;
              } else
                 break;

           startOffset = rng2.startOffset - startOffset;
           startOffset = startOffset < 0 ? 0 : startOffset;

           endOffset = rng2.endOffset + endOffset;
           endOffset = endOffset >= rng2.endContainer.data.length ? rng2.endContainer.data.length - 1 : endOffset;

           rng2.setStart(rng2.startContainer, startOffset);
           rng2.setEnd(rng2.endContainer, endOffset);
           sel.removeAllRanges();
           sel.addRange(rng2);
           
        }
    } 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();
        }
    }
}

于 2015-01-29T15:32:06.627 回答