it-swarm.com.de

Markieren Sie den Textbereich mit JavaScript

Ich möchte einen bestimmten Textbereich hervorheben (Anwenden von CSS), der durch seine Start- und Endposition gekennzeichnet ist. Dies ist schwieriger als es scheint, da im Text möglicherweise andere Tags vorhanden sind, die ignoriert werden müssen.

Beispiel:

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

highlight(2, 6) muss "cdef "hervorheben, ohne das Tag zu entfernen.

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

Danke im Voraus!

36
Vincent

Nachfolgend finden Sie eine Funktion, um die Auswahl auf ein Paar von Zeichenversätzen innerhalb eines bestimmten Elements festzulegen. Dies ist eine naive Implementierung: Es berücksichtigt keinen Text, der unsichtbar gemacht werden kann (entweder durch CSS oder durch ein <script>- oder <style>-Element) und kann Browser-Diskrepanzen (IE und alles andere) mit Zeilenumbrüchen aufweisen. und berücksichtigt keine reduzierten Leerzeichen (z. B. zwei oder mehr aufeinanderfolgende Leerzeichen, die auf einen sichtbaren Bereich auf der Seite reduziert werden). Es funktioniert jedoch für Ihr Beispiel in allen gängigen Browsern.

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

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

Und der Auswahl-Einstellcode:

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();
    }
}
52
Tim Down

Sie können einen Blick auf die Funktionsweise dieses leistungsstarken JavaScript-Dienstprogramms werfen, das die Auswahl über mehrere DOM-Elemente unterstützt:

MASHA (Abkürzung für Mark & ​​Share) Sie können interessante Teile des Webseiteninhalts markieren und teilen

http://mashajs.com/index_eng.html

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

Funktioniert auch auf Mobile Safari und IE! 

2
yumyo

Die folgende Lösung funktioniert nicht für den Internet Explorer. Dafür müssen Sie TextRange-Objekte usw. anwenden. Da dies mithilfe von Auswahlen erfolgt, sollte der HTML-Code in normalen Fällen nicht beschädigt werden. 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 des Bereichs in ein em und der Rest innerhalb des span in ein neues umgebrochen wird. Wo, als ob es es nur bei Zeichen 3 öffnen und bei Zeichen 6 enden würde, würde es ungültiges Markup geben 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);

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

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

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

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

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

edit Wie Tim Pointed hervorhob, ist modify erst ab FF4 verfügbar, daher habe ich einen anderen Ansatz gewählt, um die Auswahl zu erhalten, für den keine Änderung erforderlich ist Methode, in der Hoffnung, es ein bisschen mehr Browser-kompatibel zu machen (IE braucht noch eine 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/

0
Niklas

Basierend auf den Ideen des Plugins jQuery.highlight .

    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);
        }
    }
0
Bill