45 Stimmen

Textbereich mit JavaScript hervorheben

Ich möchte einen bestimmten Textbereich hervorheben (css anwenden), der durch seine Anfangs- und Endposition gekennzeichnet ist. Dies ist schwieriger als es scheint, da es andere Tags innerhalb des Textes geben kann, die ignoriert werden müssen.

Beispiel:

<div>abcd<em>efg</em>hij</div>

highlight(2, 6) muss hervorgehoben werden "cdef ", ohne das Etikett zu entfernen.

Ich habe bereits versucht, ein TextRange-Objekt zu verwenden, jedoch ohne Erfolg.

Vielen Dank im Voraus!

70voto

Tim Down Punkte 304837

Nachfolgend finden Sie eine Funktion, mit der die Auswahl auf ein Paar von Zeichenabständen innerhalb eines bestimmten Elements festgelegt wird. Dies ist eine naive Implementierung: Sie berücksichtigt keinen Text, der unsichtbar gemacht werden kann (entweder durch CSS oder weil er sich innerhalb einer <script> ou <style> Element, zum Beispiel) und kann Browser-Diskrepanzen (IE gegen alle anderen) mit Zeilenumbrüchen haben und berücksichtigt keine kollabierten Leerzeichen (wie 2 oder mehr aufeinanderfolgende Leerzeichen, die zu einem sichtbaren Leerzeichen auf der Seite kollabieren). Für Ihr Beispiel funktioniert es jedoch in allen gängigen Browsern.

Für den anderen Teil, die Hervorhebung, würde ich vorschlagen, dass Sie document.execCommand() dafür. Sie können meine Funktion unten verwenden, um die Auswahl festzulegen und dann die Funktion document.execCommand() . Sie müssen das Dokument vorübergehend in Nicht-IE-Browsern bearbeitbar machen, damit der Befehl funktioniert. Siehe meine Antwort hier für den Code: getSelection & surroundContents über mehrere Tags hinweg

Hier ist ein jsFiddle-Beispiel, das die ganze Sache in allen gängigen Browsern zeigt: http://jsfiddle.net/8mdX4/1211/

Und der Code für die Einstellung der Auswahl:

function getTextNodesIn(node) {
    var textNodes = [];
    if (node.nodeType == 3) {
        textNodes.push(node);
    } else {
        var children = node.childNodes;
        for (var i = 0, len = children.length; i < len; ++i) {
            textNodes.push.apply(textNodes, getTextNodesIn(children[i]));
        }
    }
    return textNodes;
}

function setSelectionRange(el, start, end) {
    if (document.createRange && window.getSelection) {
        var range = document.createRange();
        range.selectNodeContents(el);
        var textNodes = getTextNodesIn(el);
        var foundStart = false;
        var charCount = 0, endCharCount;

        for (var i = 0, textNode; textNode = textNodes[i++]; ) {
            endCharCount = charCount + textNode.length;
            if (!foundStart && start >= charCount
                    && (start < endCharCount ||
                    (start == endCharCount && i <= textNodes.length))) {
                range.setStart(textNode, start - charCount);
                foundStart = true;
            }
            if (foundStart && end <= endCharCount) {
                range.setEnd(textNode, end - charCount);
                break;
            }
            charCount = endCharCount;
        }

        var sel = window.getSelection();
        sel.removeAllRanges();
        sel.addRange(range);
    } else if (document.selection && document.body.createTextRange) {
        var textRange = document.body.createTextRange();
        textRange.moveToElementText(el);
        textRange.collapse(true);
        textRange.moveEnd("character", end);
        textRange.moveStart("character", start);
        textRange.select();
    }
}

3voto

Sie können einen Blick darauf werfen, wie dieses leistungsstarke JavaScript-Dienstprogramm funktioniert, das die Auswahl über mehrere DOM-Elemente unterstützt:

MASHA (kurz für Mark & Share) ermöglichen es Ihnen, interessante Teile von Webseiteninhalten zu markieren und zu teilen

http://mashajs.com/index_eng.html

Es ist auch auf GitHub https://github.com/SmartTeleMax/MaSha

Funktioniert sogar auf Mobile Safari und IE!

1voto

FrameMuse Punkte 33

Ich weiß, dass die Frage in diesem Zusammenhang nicht relevant ist, aber genau danach habe ich gesucht.

Wenn Sie SELECTED TEXT hervorheben möchten

Verwenden Sie das folgende Prinzip: Arbeiten Sie mit Selection Range Methoden, wie diese

document.getSelection().getRangeAt(0).surroundContents(YOUR_WRAPPER_NODE) // Adds wrapper
document.getSelection().getRangeAt(0).insertNode(NEW_NODE) // Inserts a new node

Das war's. Ich empfehle Ihnen, mehr zu erfahren über Range Methoden.

Ich hatte damit zu kämpfen und meine Suchanfragen waren falsch, also habe ich beschlossen, es hier zu posten, für den Fall, dass es Leute wie mich gibt.

Nochmals Entschuldigung für die unzutreffende Antwort.

0voto

Niklas Punkte 29492

Die folgende Lösung funktioniert nicht für den IE, Sie müssen dafür TextRange-Objekte usw. verwenden. Da hierbei Auswahlen verwendet werden, sollte der HTML-Code in normalen Fällen nicht beschädigt werden, zum Beispiel:

<div>abcd<span>efg</span>hij</div>

Mit highlight(3,6);

Ausgänge:

<div>abc<em>d<span>ef</span></em><span>g</span>hij</div>

Beachten Sie, wie das erste Zeichen außerhalb der Spanne in eine em und dann der Rest innerhalb der span in eine neue. Wenn es nur bei Zeichen 3 geöffnet und bei Zeichen 6 beendet würde, würde es ungültiges Markup wie:

<div>abc<em>d<span>ef</em>g</span>hij</div>

Der Code:

~~var r = document.createRange(); var s = window.getSelection()

r.selectNode($('div')[0]);
s.removeAllRanges();
s.addRange(r);

// not quite sure why firefox has problems with this
if ($.browser.webkit) {
    s.modify("move", "backward", "documentboundary");
}

function highlight(start,end){
    for(var st=0;st<start;st++){
        s.modify("move", "forward", "character");
    }

    for(var st=0;st<(end-start);st++){
        s.modify("extend", "forward", "character");
    }
}

highlight(2,6);

var ra = s.getRangeAt(0);
var newNode = document.createElement("em");
newNode.appendChild(ra.extractContents()); 
ra.insertNode(newNode);

Exemple : http://jsfiddle.net/niklasvh/4NDb9/

modifier Sieht so aus, als hätte zumindest mein FF4 einige Probleme mit

s.modify("move", "backward", "documentboundary");

aber gleichzeitig scheint es auch ohne zu funktionieren, also habe ich es einfach geändert in

if ($.browser.webkit) {
        s.modify("move", "backward", "documentboundary");
}~~ 

modifier Tim wies darauf hin, dass "modify" erst ab FF4 verfügbar ist, also habe ich einen anderen Ansatz gewählt, um die Auswahl zu erhalten, der die "modify"-Methode nicht benötigt, in der Hoffnung, sie etwas browser-kompatibler zu machen (IE braucht immer noch seine eigene Lösung).

Der Code:

var r = document.createRange();
var s = window.getSelection()

var pos = 0;

function dig(el){
    $(el).contents().each(function(i,e){
        if (e.nodeType==1){
            // not a textnode
         dig(e);   
        }else{
            if (pos<start){
               if (pos+e.length>=start){
                range.setStart(e, start-pos);
               }
            }

            if (pos<end){
               if (pos+e.length>=end){
                range.setEnd(e, end-pos);
               }
            }            

            pos = pos+e.length;
        }
    });  
}
var start,end, range;

function highlight(element,st,en){
    range = document.createRange();
    start = st;
    end = en;
    dig(element);
    s.addRange(range);

}
highlight($('div'),3,6);

var ra = s.getRangeAt(0);

var newNode = document.createElement("em");
newNode.appendChild(ra.extractContents()); 
ra.insertNode(newNode);

Beispiel: http://jsfiddle.net/niklasvh/4NDb9/

0voto

Bill Punkte 399

Basierend auf den Ideen der jQuery.highlight Plugin.

    private highlightRange(selector: JQuery, start: number, end: number): void {
        let cur = 0;
        let replacements: { node: Text; pos: number; len: number }[] = [];

        let dig = function (node: Node): void {
            if (node.nodeType === 3) {
                let nodeLen = (node as Text).data.length;
                let next = cur + nodeLen;
                if (next > start && cur < end) {
                    let pos = cur >= start ? cur : start;
                    let len = (next < end ? next : end) - pos;
                    if (len > 0) {
                        if (!(pos === cur && len === nodeLen && node.parentNode &&
                            node.parentNode.childNodes && node.parentNode.childNodes.length === 1 &&
                            (node.parentNode as Element).tagName === 'SPAN' && (node.parentNode as Element).className === 'highlight1')) {

                            replacements.push({
                                node: node as Text,
                                pos: pos - cur,
                                len: len,
                            });
                        }
                    }
                }
                cur = next;
            }
            else if (node.nodeType === 1) {
                let childNodes = node.childNodes;
                if (childNodes && childNodes.length) {
                    for (let i = 0; i < childNodes.length; i++) {
                        dig(childNodes[i]);
                        if (cur >= end) {
                            break;
                        }
                    }
                }
            }
        };

        selector.each(function (index, element): void {
            dig(element);
        });

        for (let i = 0; i < replacements.length; i++) {
            let replacement = replacements[i];
            let highlight = document.createElement('span');
            highlight.className = 'highlight1';
            let wordNode = replacement.node.splitText(replacement.pos);
            wordNode.splitText(replacement.len);
            let wordClone = wordNode.cloneNode(true);
            highlight.appendChild(wordClone);
            wordNode.parentNode.replaceChild(highlight, wordNode);
        }
    }

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X