如何用元素环绕/包围突出显示的文本

问题描述

| 我想将选定的文本包装在具有span的div容器中,可以吗? 用户将选择一个文本并单击一个按钮,单击按钮时,我想用span元素包装该选定的文本。我可以使用
window.getSelection()
获得所选文本,但是如何知道其在DOM结构中的确切位置?     

解决方法

        如果所选内容完全包含在单个文本节点中,则可以使用从所选内容中获得的范围的“ 1”方法来执行此操作。但是,这非常脆弱:如果选择不能在逻辑上包围在单个元素中(通常,如果范围跨越节点边界,尽管这不是精确的定义),则它不起作用。在一般情况下,要执行此操作,您需要一种更复杂的方法。 另外,IE <9中不支持DOM
Range
window.getSelection()
。对于这些浏览器,您将再次需要另一种方法。您可以使用我自己的Rangy之类的库来规范浏览器行为,并且您可能会发现该类应用程序模块对该问题很有用。 简单的``1''示例jsFiddle:http://jsfiddle.net/VRcvn/ 码:
function surroundSelection(element) {
    if (window.getSelection) {
        var sel = window.getSelection();
        if (sel.rangeCount) {
            var range = sel.getRangeAt(0).cloneRange();
            range.surroundContents(element);
            sel.removeAllRanges();
            sel.addRange(range);
        }
    }
}
    ,        
function wrapSelectedText() {       
    var selection= window.getSelection().getRangeAt(0);
    var selectedText = selection.extractContents();
    var span= document.createElement(\"span\");
    span.style.backgroundColor = \"yellow\";
    span.appendChild(selectedText);
    selection.insertNode(span);
}
Lorem ipsum dolor sit amet,consectetur adipiscing elit. Nam rhoncus  gravida magna,quis interdum magna mattis quis. Fusce tempor sagittis  varius. Nunc at augue at erat suscipit bibendum id nec enim. Sed eu odio  quis turpis hendrerit sagittis id sit amet justo. Cras ac urna purus,non rutrum nunc. Aenean nec vulputate ante. Morbi scelerisque sagittis  hendrerit. Pellentesque habitant morbi tristique senectus et netus et  malesuada fames ac turpis egestas. Nulla tristique ligula fermentum  tortor semper at consectetur erat aliquam. Sed gravida consectetur  sollicitudin. 

<input type=\"button\" onclick=\"wrapSelectedText();\" value=\"Highlight\" />
,        有可能的。您需要使用range API和Range.surroundContents()方法。它将内容包装所在的节点放在指定范围的开始处。 参见https://developer.mozilla.org/en/DOM/range.surroundContents     ,        仅当您选择的内容仅包含文本而不包含HTML时,aroundContents才起作用。这是一个更灵活的跨浏览器解决方案。这将插入如下范围:
<span id=\"new_selection_span\"><!--MARK--></span>
在选择之前,将跨度插入到最近的打开HTML标记之前。
var span = document.createElement(\"span\");
span.id = \"new_selection_span\";
span.innerHTML = \'<!--MARK-->\';

if (window.getSelection) { //compliant browsers
    //obtain the selection
    sel = window.getSelection();
    if (sel.rangeCount) {
        //clone the Range object
        var range = sel.getRangeAt(0).cloneRange();
        //get the node at the start of the range
        var node = range.startContainer;
        //find the first parent that is a real HTML tag and not a text node
        while (node.nodeType != 1) node = node.parentNode;
        //place the marker before the node
        node.parentNode.insertBefore(span,node);
        //restore the selection
        sel.removeAllRanges();
        sel.addRange(range);
    }
} else { //IE8 and lower
    sel = document.selection.createRange();
    //place the marker before the node
    var node = sel.parentElement();
    node.parentNode.insertBefore(span,node);
    //restore the selection
    sel.select();
}
    ,        请发现以下代码对于包装所有类型的span标签都将有所帮助。请仔细阅读代码,并为您的实现使用逻辑。
getSelectedText(this);
addAnnotationElement(this,this.parent);

function getSelectedText(this) {
    this.range = window.getSelection().getRangeAt(0);
    this.parent = this.range.commonAncestorContainer;
    this.frag = this.range.cloneContents();
    this.clRange = this.range.cloneRange();
    this.start = this.range.startContainer;
    this.end = this.range.endContainer;
}


function addAnnotationElement(this,elem) {
    var text,textParent,origText,prevText,nextText,childCount,annotationTextRange,span = this.htmlDoc.createElement(\'span\');

    if (elem.nodeType === 3) {
        span.setAttribute(\'class\',this.annotationClass);
        span.dataset.name = this.annotationName;
        span.dataset.comment = \'\';
        span.dataset.page = \'1\';
        origText = elem.textContent;            
        annotationTextRange = validateTextRange(this,elem);
        if (annotationTextRange == \'textBeforeRangeButIntersect\') {
            text = origText.substring(0,this.range.endOffset);
            nextText = origText.substring(this.range.endOffset);
        } else if (annotationTextRange == \'textAfterRangeButIntersect\') {
            prevText = origText.substring(0,this.range.startOffset);
            text = origText.substring(this.range.startOffset);
        } else if (annotationTextRange == \'textExactlyInRange\') {
            text = origText
        } else if (annotationTextRange == \'textWithinRange\') {
            prevText = origText.substring(0,this.range.startOffset);
            text = origText.substring(this.range.startOffset,this.range.endOffset);
            nextText = origText.substring(this.range.endOffset);
        } else if (annotationTextRange == \'textNotInRange\') {
            return;
        }
        span.textContent = text;
        textParent = elem.parentElement;
        textParent.replaceChild(span,elem);
        if (prevText) {
            var prevDOM = this.htmlDoc.createTextNode(prevText);
            textParent.insertBefore(prevDOM,span);
        }
        if (nextText) {
            var nextDOM = this.htmlDoc.createTextNode(nextText);
            textParent.insertBefore(nextDOM,span.nextSibling);
        }
        return;
    }
    childCount = elem.childNodes.length;
    for (var i = 0; i < childCount; i++) {
        var elemChildNode = elem.childNodes[i];
        if( Helper.isUndefined(elemChildNode.tagName) ||
            ! ( elemChildNode.tagName.toLowerCase() === \'span\' &&
            elemChildNode.classList.contains(this.annotationClass) ) ) {
            addAnnotationElement(this,elem.childNodes[i]);
        }
        childCount = elem.childNodes.length;
    }
}

  function validateTextRange(this,elem) {
    var textRange = document.createRange();

    textRange.selectNodeContents (elem);
    if (this.range.compareBoundaryPoints (Range.START_TO_END,textRange) <= 0) {
        return \'textNotInRange\';
    }
    else {
        if (this.range.compareBoundaryPoints (Range.END_TO_START,textRange) >= 0) {
            return \'textNotInRange\';
        }
        else {
            var startPoints = this.range.compareBoundaryPoints (Range.START_TO_START,textRange),endPoints = this.range.compareBoundaryPoints (Range.END_TO_END,textRange);

            if (startPoints < 0) {
                if (endPoints < 0) {
                    return \'textBeforeRangeButIntersect\';
                }
                else {
                    return \"textExactlyInRange\";
                }
            }
            else {
                if (endPoints > 0) {
                    return \'textAfterRangeButIntersect\';
                }
                else {
                    if (startPoints === 0 && endPoints === 0) {
                        return \"textExactlyInRange\";
                    }
                    else {
                        return \'textWithinRange\';
                    }
                }
            }
        }
    }
}
    

相关问答

Selenium Web驱动程序和Java。元素在(x,y)点处不可单击。其...
Python-如何使用点“。” 访问字典成员?
Java 字符串是不可变的。到底是什么意思?
Java中的“ final”关键字如何工作?(我仍然可以修改对象。...
“loop:”在Java代码中。这是什么,为什么要编译?
java.lang.ClassNotFoundException:sun.jdbc.odbc.JdbcOdbc...