Auswählen von Text in einem Element (ähnlich wie Hervorheben mit der Maus)

424

Ich möchte, dass Benutzer auf einen Link klicken und dann den HTML-Text in einem anderen Element auswählen ( keine Eingabe).

Mit "auswählen" meine ich die gleiche Art und Weise, wie Sie Text auswählen würden, indem Sie Ihre Maus darüber ziehen. Dies war ein Bär für die Forschung, da alle in anderen Begriffen von "Auswählen" oder "Hervorheben" sprechen.

Ist das möglich? Mein Code bisher:

HTML:

<a href="javascript:" onclick="SelectText('xhtml-code')">Select Code</a>
<code id="xhtml-code">Some Code here </code>

JS:

function SelectText(element) {
    $("#" + element).select();
}

Vermisse ich etwas offensichtliches?

Jason
quelle

Antworten:

611

Einfaches Javascript

function selectText(node) {
    node = document.getElementById(node);

    if (document.body.createTextRange) {
        const range = document.body.createTextRange();
        range.moveToElementText(node);
        range.select();
    } else if (window.getSelection) {
        const selection = window.getSelection();
        const range = document.createRange();
        range.selectNodeContents(node);
        selection.removeAllRanges();
        selection.addRange(range);
    } else {
        console.warn("Could not select text in node: Unsupported browser.");
    }
}

const clickable = document.querySelector('.click-me');
clickable.addEventListener('click', () => selectText('target'));
<div id="target"><p>Some text goes here!</p><p>Moar text!</p></div>
<p class="click-me">Click me!</p>

Hier ist eine funktionierende Demo . Für diejenigen unter Ihnen, die nach einem jQuery-Plugin suchen, habe ich auch eines davon erstellt .


jQuery (ursprüngliche Antwort)

Ich habe in diesem Thread eine Lösung dafür gefunden . Ich konnte die angegebenen Informationen ändern und mit etwas jQuery mischen, um eine großartige Funktion zum Auswählen des Texts in einem beliebigen Element zu erstellen, unabhängig vom Browser:

function SelectText(element) {
    var text = document.getElementById(element);
    if ($.browser.msie) {
        var range = document.body.createTextRange();
        range.moveToElementText(text);
        range.select();
    } else if ($.browser.mozilla || $.browser.opera) {
        var selection = window.getSelection();
        var range = document.createRange();
        range.selectNodeContents(text);
        selection.removeAllRanges();
        selection.addRange(range);
    } else if ($.browser.safari) {
        var selection = window.getSelection();
        selection.setBaseAndExtent(text, 0, text, 1);
    }
}
Jason
quelle
Die jQuery-Lösung gibt mir einen nicht erfassten TypeError: Die Eigenschaft 'msie' von undefined
egmfrs kann
@egmfrs Ja, seit diese Antwort veröffentlicht wurde, hat jquery ihren browserSchnüffler entfernt.
Jason vor
127

Hier ist eine Version ohne Browser-Sniffing und ohne Vertrauen in jQuery:

function selectElementText(el, win) {
    win = win || window;
    var doc = win.document, sel, range;
    if (win.getSelection && doc.createRange) {
        sel = win.getSelection();
        range = doc.createRange();
        range.selectNodeContents(el);
        sel.removeAllRanges();
        sel.addRange(range);
    } else if (doc.body.createTextRange) {
        range = doc.body.createTextRange();
        range.moveToElementText(el);
        range.select();
    }
}

selectElementText(document.getElementById("someElement"));
selectElementText(elementInIframe, iframe.contentWindow);
Tim Down
quelle
Gibt es eine Möglichkeit, den Text von a auszuwählen div contentEditable='true'?
Oldboy
@PrimitiveNom: Dieser Code funktioniert für ein inhaltsbearbeitbares Element, aber Sie müssen sicherstellen, dass es zuerst den Fokus hat.
Tim Down
18

Jasons Code kann nicht für Elemente innerhalb eines Iframes verwendet werden (da sich der Bereich von Fenster und Dokument unterscheidet). Ich habe dieses Problem behoben und es geändert, um es als jedes andere jQuery-Plugin (verkettbar) zu verwenden:

Beispiel 1: Auswahl des gesamten Textes in <code> -Tags mit einem Klick und Hinzufügen der Klasse "selected":

$(function() {
    $("code").click(function() {
        $(this).selText().addClass("selected");
    });
});

Beispiel 2: Wählen Sie beim Klicken auf die Schaltfläche ein Element in einem Iframe aus:

$(function() {
    $("button").click(function() {
        $("iframe").contents().find("#selectme").selText();
    });
});

Hinweis: Denken Sie daran, dass sich die Iframe-Quelle in derselben Domäne befinden sollte, um Sicherheitsfehler zu vermeiden.

jQuery Plugin:

jQuery.fn.selText = function() {
    var obj = this[0];
    if ($.browser.msie) {
        var range = obj.offsetParent.createTextRange();
        range.moveToElementText(obj);
        range.select();
    } else if ($.browser.mozilla || $.browser.opera) {
        var selection = obj.ownerDocument.defaultView.getSelection();
        var range = obj.ownerDocument.createRange();
        range.selectNodeContents(obj);
        selection.removeAllRanges();
        selection.addRange(range);
    } else if ($.browser.safari) {
        var selection = obj.ownerDocument.defaultView.getSelection();
        selection.setBaseAndExtent(obj, 0, obj, 1);
    }
    return this;
}

Ich habe es in IE8, Firefox, Opera, Safari, Chrome (aktuelle Versionen) getestet. Ich bin nicht sicher, ob es in älteren IE-Versionen funktioniert (aufrichtig ist mir egal).

Lepe
quelle
3
$ .browser ist jetzt veraltet / entfernt - dies muss neu geschrieben werden
James McCormack
2
@ JamesMcCormack: Ja. Ich bin mir nicht sicher, ob sich das Umschreiben lohnt, da hier andere Lösungen veröffentlicht werden, die nicht $ .browser beinhalten.
Lepe
16

Dieser Thread enthält wirklich wundervolle Sachen. Aber ich kann es auf dieser Seite mit FF 3.5b99 + FireBug aufgrund von "Sicherheitsfehler" nicht richtig machen.

Yipee !! Ich konnte mit diesem Code die gesamte rechte Seitenleiste auswählen. Ich hoffe, es hilft Ihnen:

    var r = document.createRange();
    var w=document.getElementById("sidebar");  
    r.selectNodeContents(w);  
    var sel=window.getSelection(); 
    sel.removeAllRanges(); 
    sel.addRange(r); 

PS: - Ich konnte keine Objekte verwenden, die von jquery-Selektoren wie zurückgegeben wurden

   var w=$("div.welovestackoverflow",$("div.sidebar"));

   //this throws **security exception**

   r.selectNodeContents(w);
TheVillageIdiot
quelle
2
Sie müssen das Element von jQuery abrufen, wenn Sie versuchen, ein jQuery-Objekt auszuwählen: var w = $ ("div.welovestackoverflow", $ ("div.sidebar")). Get (0);
Blixt
funktioniert nicht ... Ich erhalte die Fehlermeldung "Objekt unterstützt diese Methode nicht" und hebt die erste Zeile hervor. Ich habe ein bisschen gegraben und festgestellt, dass es ein "document.body.createTextRange ()" gibt, aber dann funktioniert "selectNodeContents" nicht ... und das ist in IE
Jason
Ich habe den Thread gelesen, den Sie gefunden haben ... erstaunlich ... ich konnte aus diesen Informationen eine Funktion erstellen, die in allen Browsern funktioniert. Ich danke dir sehr! Meine Lösung ist veröffentlicht
Jason
6

Mit der folgenden Funktion können Sie den Inhalt eines Elements auswählen:

jQuery.fn.selectText = function(){
    this.find('input').each(function() {
        if($(this).prev().length == 0 || !$(this).prev().hasClass('p_copy')) { 
            $('<p class="p_copy" style="position: absolute; z-index: -1;"></p>').insertBefore($(this));
        }
        $(this).prev().html($(this).val());
    });
    var doc = document;
    var element = this[0];
    console.log(this, element);
    if (doc.body.createTextRange) {
        var range = document.body.createTextRange();
        range.moveToElementText(element);
        range.select();
    } else if (window.getSelection) {
        var selection = window.getSelection();        
        var range = document.createRange();
        range.selectNodeContents(element);
        selection.removeAllRanges();
        selection.addRange(range);
    }
};

Diese Funktion kann wie folgt aufgerufen werden:

$('#selectme').selectText();
Wolfack
quelle
5

Ich suchte nach der gleichen Sache, meine Lösung war folgende:

$('#el-id').focus().select();
Auston
quelle
3
Sie können nicht focus()für eine Nicht-Eingabe verwenden, worum es in dieser Frage geht.
Jason
4
Aber Sie können es für ein Textarea-Element verwenden - das war das Problem, das ich gegoogelt habe, um hier anzukommen. Mein Fehler, dass ich die Frage nicht vollständig durchgelesen habe.
Auston
4

Ich mochte Lepes Antwort bis auf ein paar Dinge:

  1. Browser-Sniffing, jQuery oder nein ist nicht optimal
  2. TROCKEN
  3. Funktioniert nicht in IE8 , wenn obj der Eltern nicht unterstützt createtext
  4. Die Fähigkeit von Chrome, setBaseAndExtent zu verwenden, sollte genutzt werden (IMO).
  5. Wählt keinen Text aus, der sich über mehrere DOM-Elemente erstreckt (Elemente innerhalb des "ausgewählten" Elements). Mit anderen Worten, wenn Sie selText für ein div aufrufen, das mehrere span-Elemente enthält, wird nicht der Text jedes dieser Elemente ausgewählt. Das war ein Deal-Breaker für mich, YMMV.

Hier ist, was ich mir ausgedacht habe, mit einer Anspielung auf Lepes Antwort zur Inspiration. Ich bin mir sicher, dass ich verspottet werde, da dies vielleicht ein bisschen hartnäckig ist (und eigentlich mehr sein könnte, aber ich schweife ab). Aber es funktioniert und vermeidet Browser-Schnüffeln und das ist der Punkt .

selectText:function(){

    var range,
        selection,
        obj = this[0],
        type = {
            func:'function',
            obj:'object'
        },
        // Convenience
        is = function(type, o){
            return typeof o === type;
        };

    if(is(type.obj, obj.ownerDocument)
        && is(type.obj, obj.ownerDocument.defaultView)
        && is(type.func, obj.ownerDocument.defaultView.getSelection)){

        selection = obj.ownerDocument.defaultView.getSelection();

        if(is(type.func, selection.setBaseAndExtent)){
            // Chrome, Safari - nice and easy
            selection.setBaseAndExtent(obj, 0, obj, $(obj).contents().size());
        }
        else if(is(type.func, obj.ownerDocument.createRange)){

            range = obj.ownerDocument.createRange();

            if(is(type.func, range.selectNodeContents)
                && is(type.func, selection.removeAllRanges)
                && is(type.func, selection.addRange)){
                // Mozilla
                range.selectNodeContents(obj);
                selection.removeAllRanges();
                selection.addRange(range);
            }
        }
    }
    else if(is(type.obj, document.body) && is(type.obj, document.body.createTextRange)) {

        range = document.body.createTextRange();

        if(is(type.obj, range.moveToElementText) && is(type.obj, range.select)){
            // IE most likely
            range.moveToElementText(obj);
            range.select();
        }
    }

    // Chainable
    return this;
}

Das ist es. Sie sehen unter anderem die Lesbarkeit und / oder Bequemlichkeit. Getestet auf Mac in den neuesten Versionen von Opera, Safari, Chrome, Firefox und IE. Auch in IE8 getestet. Außerdem deklariere ich Variablen normalerweise nur, wenn / wenn sie in Codeblöcken benötigt werden, aber jslint schlug vor, sie alle oben zu deklarieren. Ok jslint.

Bearbeiten Ich habe vergessen anzugeben, wie dies mit dem Code der Operation verknüpft werden soll:

function SelectText(element) {
    $("#" + element).selectText();
}

Prost

Madbreaks
quelle
Ja, das sieht für mich hartnäckig aus, obwohl es richtig erscheint. Mein Hauptkritikpunkt ist, dass die Verwendung des Nicht-Standards, setBaseAndExtent()nur weil er existiert, für mich sinnlos erscheint, wenn Sie diesen Zweig einfach entfernen können und alles genauso gut und standardbasiert funktioniert. Die Funktionserkennung ist nett, aber ich würde es leid sein, alles so schnell gründlich zu testen.
Tim Down
Nun, @TimDown ist der Punkt der Hebelwirkung, setBaseAndExtentdass es wesentlich effizienter ist, und selbst mit dem hinzugefügten ifStatus ist dies immer noch weitaus effizienter, als wenn Sie "diesen Zweig entfernen". Ich verstehe den Kommentar von "Ich würde müde werden ..." nicht wirklich? Schreiben Sie es und vergessen Sie es. Sie müssen nur die Funktion aufrufen und nicht schreiben. :)
Madbreaks
@ Madbreaks Ich wäre überrascht, wenn setBaseAndExtentes deutlich performanter wäre als addRange. Warum sollte es sein? Mein anderer Kommentar bezog sich auf Ihr Feature-Test-Ethos, das auf alle DOM-Interaktionen ausgedehnt wurde: Es ist eine Menge Code, um jede einzelne DOM-Methode und -Eigenschaft zu testen, bevor Sie sie verwenden. Ich missbillige nicht; Ich bin nur froh, die Grenze zu ziehen und ein paar weitere Annahmen in meinem Code zu treffen.
Tim Down
4

Eine aktualisierte Version, die in Chrome funktioniert:

function SelectText(element) {
    var doc = document;
    var text = doc.getElementById(element);    
    if (doc.body.createTextRange) { // ms
        var range = doc.body.createTextRange();
        range.moveToElementText(text);
        range.select();
    } else if (window.getSelection) {
        var selection = window.getSelection();
        var range = doc.createRange();
        range.selectNodeContents(text);
        selection.removeAllRanges();
        selection.addRange(range);

    }
}

$(function() {
    $('p').click(function() {
        SelectText("selectme");

    });
});

http://jsfiddle.net/KcX6A/326/

Kimtho6
quelle
3

Für jedes Tag kann man den gesamten Text innerhalb dieses Tags mit diesem kurzen und einfachen Code auswählen. Es markiert den gesamten Tag-Bereich mit gelber Farbe und wählt mit einem Klick den darin enthaltenen Text aus.

document.onclick = function(event) {
    var range, selection;
event.target.style.backgroundColor = 'yellow';
        selection = window.getSelection();
        range = document.createRange();
        range.selectNodeContents(event.target);
        selection.removeAllRanges();
        selection.addRange(range);
};
knjhaveri
quelle
2

lepe - Das funktioniert super für mich danke! Ich habe Ihren Code in eine Plugin-Datei eingefügt und ihn dann in Verbindung mit jeder Anweisung verwendet, sodass Sie mehrere Pre-Tags und mehrere Links "Alle auswählen" auf einer Seite haben können und das richtige Pre zum Hervorheben ausgewählt wird:

<script type="text/javascript" src="../js/jquery.selecttext.js"></script>
<script type="text/javascript">
  $(document).ready(function() { 
        $(".selectText").each(function(indx) {
                $(this).click(function() {                 
                    $('pre').eq(indx).selText().addClass("selected");
                        return false;               
                    });
        });
  });

DaveR
quelle
1

Schauen Sie sich das Selection-Objekt (Gecko-Engine) und das TextRange-Objekt (Trident-Engine) an. Ich kenne keine JavaScript-Frameworks, die browserübergreifend unterstützt werden, aber ich habe auch nie danach gesucht Es ist möglich, dass sogar jQuery es hat.

Blixt
quelle
0

Tims Methode funktioniert perfekt für meinen Fall - indem ich den Text in einem Div für IE und FF auswähle, nachdem ich die folgende Anweisung ersetzt habe:

range.moveToElementText(text);

mit den folgenden:

range.moveToElementText(el);

Der Text im div wird durch Klicken mit der folgenden jQuery-Funktion ausgewählt:

$(function () {
    $("#divFoo").click(function () {
        selectElementText(document.getElementById("divFoo"));
    })
});
Hong
quelle
0

Hier ist eine weitere einfache Lösung, um den ausgewählten Text in Form einer Zeichenfolge zu erhalten. Sie können diese Zeichenfolge einfach verwenden, um ein untergeordnetes div-Element an Ihren Code anzuhängen:

var text = '';

if (window.getSelection) {
    text = window.getSelection();

} else if (document.getSelection) {
    text = document.getSelection();

} else if (document.selection) {
    text = document.selection.createRange().text;
}

text = text.toString();
Nadeem Yasin
quelle
Dies dient dazu, den markierten Text zurückzugeben und keine Hervorhebung zu erstellen.
MKN Web Solutions
0

Mein spezieller Anwendungsfall war die Auswahl eines Textbereichs innerhalb eines bearbeitbaren Bereichselements, der, soweit ich sehen konnte, in keiner der Antworten hier beschrieben ist.

Der Hauptunterschied besteht darin, dass Sie einen Knoten vom Typ Textan das RangeObjekt übergeben müssen, wie in der Dokumentation von Range.setStart () beschrieben :

Wenn der startNode ein Knoten vom Typ Text, Comment oder CDATASection ist , ist startOffset die Anzahl der Zeichen ab dem Start von startNode. Bei anderen Knotentypen ist startOffset die Anzahl der untergeordneten Knoten zwischen dem Start des startNode.

Der TextKnoten ist der erste untergeordnete Knoten eines span-Elements. Um ihn zu erhalten, greifen Sie childNodes[0]auf das span-Element zu. Der Rest ist der gleiche wie in den meisten anderen Antworten.

Hier ein Codebeispiel:

var startIndex = 1;
var endIndex = 5;
var element = document.getElementById("spanId");
var textNode = element.childNodes[0];

var range = document.createRange();
range.setStart(textNode, startIndex);
range.setEnd(textNode, endIndex);

var selection = window.getSelection();
selection.removeAllRanges();
selection.addRange(range);

Andere relevante Dokumentation: Bereichsauswahl
Document.createRange () window.getSelection ()


Domysee
quelle
-1

jQuery.browser.webkitZum "else if" für Chrome hinzugefügt . In Chrome 23 konnte dies nicht funktionieren.

Dieses Skript wurde unten erstellt, um den Inhalt in einem <pre>Tag auszuwählen , das das enthält class="code".

jQuery( document ).ready(function() {
    jQuery('pre.code').attr('title', 'Click to select all');
    jQuery( '#divFoo' ).click( function() {
        var refNode = jQuery( this )[0];
        if ( jQuery.browser.msie ) {
            var range = document.body.createTextRange();
            range.moveToElementText( refNode );
            range.select();
        } else if ( jQuery.browser.mozilla || jQuery.browser.opera  || jQuery.browser.webkit ) {
            var selection = refNode.ownerDocument.defaultView.getSelection();
            console.log(selection);
            var range = refNode.ownerDocument.createRange();
            range.selectNodeContents( refNode );
            selection.removeAllRanges();
            selection.addRange( range );
        } else if ( jQuery.browser.safari ) {
            var selection = refNode.ownerDocument.defaultView.getSelection();
            selection.setBaseAndExtent( refNode, 0, refNode, 1 );
        }
    } );
} );
Derk
quelle
-1

Gemäß der jQuery-Dokumentation von select():

Lösen Sie das Auswahlereignis jedes übereinstimmenden Elements aus. Dadurch werden alle Funktionen ausgeführt, die an dieses Auswahlereignis gebunden wurden, und die Standardauswahlaktion des Browsers für die übereinstimmenden Elemente wird aufgerufen.

Es gibt Ihre Erklärung, warum die jQuery select()in diesem Fall nicht funktioniert.

Kees de Kooter
quelle
4
Ich versuche nicht, den Text mit einem CSS-Stil hervorzuheben. Ich möchte, dass der Text ausgewählt wird.
Jason