Javascript 从DOM中删除添加的高光

Javascript 从DOM中删除添加的高光,javascript,google-chrome,google-chrome-extension,Javascript,Google Chrome,Google Chrome Extension,我正在使用创建一个突出显示。现在,我希望用户再次单击浏览器操作将其删除 我想我可以在这个片段中添加另一个if语句: function makeEditableAndHighlight(colour) { var range, sel = window.getSelection(); if (sel.rangeCount && sel.getRangeAt) { range = sel.getRangeAt(0); } documen

我正在使用创建一个突出显示。现在,我希望用户再次单击浏览器操作将其删除

我想我可以在这个片段中添加另一个
if
语句:

function makeEditableAndHighlight(colour) {
    var range, sel = window.getSelection();
    if (sel.rangeCount && sel.getRangeAt) {
        range = sel.getRangeAt(0);
    }
    document.designMode = "on";
    if (range) {
        sel.removeAllRanges();
        sel.addRange(range);
    }
    // Use HiliteColor since some browsers apply BackColor to the whole block
    if (!document.execCommand("HiliteColor", false, '#FFFF00')) {
        document.execCommand("BackColor", false, '#FFFF00');
    }
    if (!document.execCommand("HiliteColor", true, '#FFFF00')) {  // Added this logic
        document.execCommand("removeFormat", false, null);
    }
    document.designMode = "off";
}
我的想法是,如果
“HiliteColor”
返回
true
,它将删除格式,但它不起作用。有什么想法吗

编辑 在阅读了更多的内容后,我了解到
execCommand
中的布尔值与返回值没有任何关系。如何改进逻辑以反转背景色?甚至可行吗?

您需要一种方法来“序列化”所选范围,以便以后访问。
说明如何实现序列化/反序列化

您的代码可能如下所示:

var serializedRange;

/* Serializes and returns the specified range
 * (ignoring it if its length is zero) */
function serializeRange(range) {
    return (!range || ((range.startContainer === range.endContainer)
                       && (range.startOffset === range.endOffset)))
            ? null : {
                startContainer: range.startContainer,
                startOffset:    range.startOffset,
                endContainer:   range.endContainer,
                endOffset:      range.endOffset
            };
}

/* Restores the specified serialized version
 * (removing any ranges currently seleted) */
function restoreRange(serialized) {
    var range = document.createRange();
    range.setStart(serialized.startContainer, serialized.startOffset);
    range.setEnd(serialized.endContainer, serialized.endOffset);

    var sel = window.getSelection();
    sel.removeAllRanges();
    sel.addRange(range);
}

/* Hilites the currently selected range or removes the hilite
 * (if there is a previously serialized range) */
function toggleHilite() {
    document.designMode = 'on';

    var sel = window.getSelection();
    if (serializedRange) {
        /* There is a hilited range, let's remove the hilite */
        restoreRange(serializedRange);
        serializedRange = null;
        document.execCommand('removeFormat', false, null);
        sel.removeAllRanges();
    } else {
        /* There is no hilited range, so hilite
         * the currently selected range (if any) */
        if (sel.rangeCount && sel.getRangeAt) {
            document.execCommand('hiliteColor', false, '#FFFF00');
            serializedRange = serializeRange(sel.getRangeAt(0));
            // it is important to serialize the range *after* hiliting,
            // because `execCommand` will change the DOM affecting the
            // range's start-/endContainer and offsets.
        }
    }

    document.designMode = 'off';
}
您需要一种方法来“序列化”所选范围,以便以后访问。
说明如何实现序列化/反序列化

您的代码可能如下所示:

var serializedRange;

/* Serializes and returns the specified range
 * (ignoring it if its length is zero) */
function serializeRange(range) {
    return (!range || ((range.startContainer === range.endContainer)
                       && (range.startOffset === range.endOffset)))
            ? null : {
                startContainer: range.startContainer,
                startOffset:    range.startOffset,
                endContainer:   range.endContainer,
                endOffset:      range.endOffset
            };
}

/* Restores the specified serialized version
 * (removing any ranges currently seleted) */
function restoreRange(serialized) {
    var range = document.createRange();
    range.setStart(serialized.startContainer, serialized.startOffset);
    range.setEnd(serialized.endContainer, serialized.endOffset);

    var sel = window.getSelection();
    sel.removeAllRanges();
    sel.addRange(range);
}

/* Hilites the currently selected range or removes the hilite
 * (if there is a previously serialized range) */
function toggleHilite() {
    document.designMode = 'on';

    var sel = window.getSelection();
    if (serializedRange) {
        /* There is a hilited range, let's remove the hilite */
        restoreRange(serializedRange);
        serializedRange = null;
        document.execCommand('removeFormat', false, null);
        sel.removeAllRanges();
    } else {
        /* There is no hilited range, so hilite
         * the currently selected range (if any) */
        if (sel.rangeCount && sel.getRangeAt) {
            document.execCommand('hiliteColor', false, '#FFFF00');
            serializedRange = serializeRange(sel.getRangeAt(0));
            // it is important to serialize the range *after* hiliting,
            // because `execCommand` will change the DOM affecting the
            // range's start-/endContainer and offsets.
        }
    }

    document.designMode = 'off';
}

这太棒了!非常感谢您的帮助。总是很乐意帮助!(只是提醒一下:我在
serializeRange()
中做了一点小小的改进)好的,因为我还在学习,我只是想确保我理解这个变化:您添加的
==
确保选择的起点/终点不会被DOM重构搞砸,对吗?换句话说,如果返回的值不相同,它将测试false ad,然后添加一个突出显示,而不是删除?我注意到,有时(例如,当在具有可选文本的区域中单击时),Chrome会报告在同一容器中的同一索引处开始和结束的选定范围(基本上是0长度的选择)。将这样一个选择隐藏起来不会产生视觉效果,因此对用户体验有害(如果不清楚原因,我可以举一个例子)。因此,我必须检查一个选择是否具有0长度,并将其视为完全没有选择。起初我只是比较起始偏移和结束偏移。但我意识到我必须比较好容器ss(因为从容器y中的位置x开始,在位置x结束,沿着DOM向下的十几个容器并不表示我是0长度范围)。这太棒了!非常感谢您的帮助。总是很乐意帮助!(只是提醒一下:我在
serializeRange()
中做了一点小小的改进)好的,因为我还在学习,我只是想确保我理解这个变化:您添加的
==
确保选择的起点/终点不会被DOM重构搞砸,对吗?换句话说,如果返回的值不相同,它将测试false ad,然后添加一个突出显示,而不是删除?我注意到,有时(例如,当在具有可选文本的区域中单击时),Chrome会报告在同一容器中的同一索引处开始和结束的选定范围(基本上是0长度的选择)。将这样一个选择隐藏起来不会产生视觉效果,因此对用户体验有害(如果不清楚原因,我可以举一个例子)。因此,我必须检查一个选择是否具有0长度,并将其视为完全没有选择。起初我只是比较开始偏移和结束偏移,但我意识到我必须比较容器ss(因为从容器y中的x位置开始,到x位置结束,沿着DOM向下的十几个容器并不表示我的长度范围为0)。