FED实验室 - 专注WEB端开发和用户体验

煦涵说JS(七):Selection 和 Range 对象应用实战

煦涵说 煦涵 865℃ 0评论

Selection 对象表示用户选择的文本范围或插入符号的当前位置。它代表页面中的文本选区,可能横跨多个元素。文本选区由用户拖拽鼠标经过文字而产生。要获取用于检查或修改的Selection对象,请调用 window.getSelection()。Range,表示包含节点和部分文本节点的文档片段,可以通过 Selection 对象的 getRangeAt 方法取得,也可以通过 Document 对象的 createRange 方法创建。

Selection 和 Range 对象应用实战

在我们日常前端开发中,可能会遇到这样的场景,实现划词翻译、点击取词翻译、编辑器中的复制、粘贴等需求,下面我们通过对这两种需求场景来介绍 Selection 对象 和 Range 对象在实际项目中的应用。

应用一:实现点击取词并翻译

实现基本思路,点击时获取 Selection 对象,并创建选取,通过 Range 的 setStart 和 setEnd 方法扩大文档片段的范围,以空格或者特殊符号为临界状态,终止循环。

1.方法一实现相关逻辑如下:

if (window.getSelection) {
    let selection, range, node, start, end, text, rect, isFun, isText;

    // 回调函数判断
    isFun = !!window.JSInvoker && typeof window.JSInvoker.toggleWordTooltip === 'function';

    // 文本判断
    isText = function (text) {
        return text && /^[a-zA-Z]+$/.test(text);
    }

    // 如果 tooltip 存在,需要先关闭
    isFun && window.JSInvoker.toggleWordTooltip(false);

    selection = window.getSelection();
    range = selection.getRangeAt(0);
    node = selection.anchorNode;
    start = range.startOffset;
    end = range.endOffset;
    text = range.toString();

    // <<<
    while (!/^\s+/.test(text)) {
        if (start === 0) {
            range.setStart(node, start);
            text = range.toString();
            break;
        } else {
            start -= 1;
            range.setStart(node, start);
            text = range.toString();
        }
        if (!isText(text)) {
            start += 1;
            range.setStart(node, start);
            text = range.toString();
            break;
        }
    }
    // >>>
    while (!/\s+$/.test(text)) {
        if (end === node.length) {
            range.setEnd(node, end);
            text = range.toString();
            break;
        } else {
            end += 1;
            range.setEnd(node, end);
            text = range.toString();
        }
        if (!isText(text)) {
            end -= 1;
            range.setEnd(node, end);
            text = range.toString();
            break;
        }
    }

    // 获取当前文档片段位置信息
    rect = range.getBoundingClientRect();
    text = text.trim();
    if (isText(text) && isFun && rect) {
        // 打开 tooltip
        window.JSInvoker.toggleWordTooltip(true, text, rect.x, rect.y, rect.width, rect.height);
    } else {
        alert(`Text: ${text}, isFun: ${isFun}, Rect: ${JSON.stringify(rect)}`);
    }
} else {
    // todo
}

ps: 文本选中颜色可以通过 CSS3 ::selection 来实现,但是兼容性是个问题,可以通过 rect 属性值来创建个 mask 浮层 position:absolute; 来实现

2.方法二实现方案比较简单,实现代码逻辑如下:

if (window.getSelection) {
    let selection, start, end, word;

    selection = window.getSelection();

    selection.modify('extend', 'backward', 'word');
    start = selection.toString();

    selection.modify('extend', 'forward', 'word');
    end = selection.toString();

    selection.modify('move', 'forward', 'character');

    word = start + end;
    alert(`Selected Text: ${word}`);
} else {
    // todo
}

应用二:实现划词翻译

1.获取划词文本

function getSelected () {
    let selection;
    if (window.getSelection) {
        // webkit and mozilla and IE9 +
        selection = window.getSelection();
    } else if (document.getSelection) {
        // 同上
        selection = document.getSelection();
    } else if (document.selection) {
        // IE
        selection = document.selection.createRange().text;
    }

    return selection.toString().trim();
}

2.清空选中文本

function removeSelection () {
    if (window.getSelection) {
        window.getSelection().removeAllRanges();
    } else if (document.getSelection && document.getSelection.empty) {
        document.getSelection().empty();
    } else if (document.selection && document.selection.empty) {
        document.selection.empty();
    }
}

第三方库

rangy A cross-browser JavaScript range and selection library.

下面是「FED实验室」的微信公众号二维码,欢迎扫描关注:

FED实验室

行文不易,如有帮助,欢迎打赏!

赞赏支持or喜欢 (0)or分享 (0)
捐赠共勉
发表我的评论
取消评论

表情

Hi,您需要填写昵称和邮箱!

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址