Verwenden von jQuery zum Ersetzen eines Tags durch ein anderes

100

Tor:

Mit jQuery versuche ich, alle Vorkommen von zu ersetzen:

<code> ... </code>

mit:

<pre> ... </pre>

Meine Lösung:

Ich bin so weit gekommen,

$('code').replaceWith( "<pre>" + $('code').html() + "</pre>" );

Das Problem mit meiner Lösung:

Das Problem ist jedoch, dass alles zwischen den (zweiten, dritten, vierten usw.) "Code" -Tags durch den Inhalt zwischen den ersten "Code" -Tags ersetzt wird.

z.B

<code> A </code>
<code> B </code>
<code> C </code>

wird

<pre> A </pre>
<pre> A </pre>
<pre> A </pre>

Ich denke, ich muss "dies" und irgendeine Art von Funktion verwenden, aber ich fürchte, ich lerne noch und verstehe nicht wirklich, wie man eine Lösung zusammensetzt.

jon
quelle
Die Wrap-Unwrap-Lösung wurde jetzt behoben jon - check it out;)
Jens Roland

Antworten:

157

Sie können eine Funktion an .replaceWith [docs] übergeben :

$('code').replaceWith(function(){
    return $("<pre />", {html: $(this).html()});
});

thisBezieht sich innerhalb der Funktion auf das aktuell verarbeitete codeElement.

DEMO

Update: Es gibt keinen großen Leistungsunterschied , aber falls die codeElemente andere HTML-Kinder haben, scheint es korrekter zu sein, die Kinder anzuhängen, anstatt sie zu serialisieren:

$('code').replaceWith(function(){
    return $("<pre />").append($(this).contents());
});
Felix Kling
quelle
1
Dies scheint die eleganteste Lösung zu sein, obwohl ich zugeben werde, dass ich nicht verstehe, was in der Funktion replaceWith vor sich geht. würde gerne mehr hören. dh wie werden die öffnenden UND schließenden Tags zugewiesen? erreicht der Raum in <pre /> das?
Jon
2
@jon: Es ist eine kurze Hand zum Erstellen neuer Elemente. Weitere Informationen finden Sie hier: api.jquery.com/jQuery/#jQuery2 . jQuery durchläuft alle Elemente und führt die Funktion für jedes Element aus (dasselbe, was gerade ausgeführt .eachwird).
Felix Kling
@ Jon: Aber überprüfe Jens 'Lösung noch einmal, er hat sie behoben.
Felix Kling
1
+1 für einen schönen Trick - dies kann für viel mehr als nur eine einfache Tag-für-Tag-Ersetzung verwendet werden.
Jens Roland
@FelixKling Würde dies nicht die Attribute der Code-Tags überschreiben?
Tewathia
80

Das ist viel schöner:

$('code').contents().unwrap().wrap('<pre/>');

Zugegeben, die Lösung von Felix Kling ist ungefähr doppelt so schnell :

Jens Roland
quelle
4
hat wie ein Zauber funktioniert, für meine Laien scheint dies die effizienteste Lösung zu sein. :)
Jon
Aha. Ja, ihr hattet recht. es hat auch bei mir nicht funktioniert. Danke, dass du das verstanden hast!
Jon
1
FWIW $('code').children()gibt ein leeres jQuery-Objekt für das obige Beispiel zurück, da die codeElemente keine untergeordneten Elementknoten haben. Obwohl es funktioniert, wenn es untergeordnete Elemente gibt.
Felix Kling
1
Behoben - true, wenn der Inhalt aus einem einzelnen Textknoten besteht, children()funktioniert nicht. Die Verwendung contents()funktioniert stattdessen einwandfrei. jsfiddle.net/7Yne9
Jens Roland
1
Hier ist eine jsperf-Version, die die Seite nicht beschädigt : jsperf.com/substituting-one-tag-for-another-with-jquery/2 und Sie sehen, dass der Geschwindigkeitsunterschied nicht mehr so ​​groß ist. Ihre Lösung ist langsamer, da Sie zwei DOM-Manipulationen pro Element ausführen: unwrapEntfernt das übergeordnete Element und fügt die wrapuntergeordneten Elemente zum Baum hinzu, löst sie erneut und fügt ein neues übergeordnetes Element hinzu.
Felix Kling
26

Es ist richtig, dass Sie immer den codeInhalt des ersten erhalten , da er $('code').html()sich immer auf das erste Element bezieht, wo immer Sie es verwenden.

Stattdessen können Sie .eachalle Elemente durchlaufen und jedes einzeln ändern:

$('code').each(function() {
    $(this).replaceWith( "<pre>" + $(this).html() + "</pre>" );
    // this function is executed for all 'code' elements, and
    // 'this' refers to one element from the set of all 'code'
    // elements each time it is called.
});
pimvdb
quelle
12

Versuche dies:

$('code').each(function(){

    $(this).replaceWith( "<pre>" + $(this).html() + "</pre>" );

});

http://jsfiddle.net/mTGhV/

Kokos
quelle
Beeindruckend. Ihr habt innerhalb von 2 Sekunden genau die gleiche Lösung gefunden. Es gibt winzige Formatierungsunterschiede. Ich bin mir nicht sicher, welches ich verbessern soll - ich mag den Raum zwischen Funktion und () in Thomas 'Antwort wirklich nicht und die 2 Zeilen des leeren Raums in der Antwort von kokos sind ziemlich pointiert + es sollte ein Raum zwischen () sein und der {
Michael Bylstra
11

Wie wäre es damit?

$('code').each(function () {
    $(this).replaceWith( "<pre>" + $(this).html() + "</pre>" );
});
Tae-Sung Shin
quelle
6

Aufbauend auf Felix 'Antwort.

$('code').replaceWith(function() {
    var replacement = $('<pre>').html($(this).html());
    for (var i = 0; i < this.attributes.length; i++) {
        replacement.attr(this.attributes[i].name, this.attributes[i].value);
    }
    return replacement;
});

Dadurch werden die Attribute der codeTags in den Ersatz- preTags reproduziert .

Bearbeiten: Dies ersetzt auch die codeTags, die sich innerHTMLin anderen codeTags befinden.

function replace(thisWith, that) {
    $(thisWith).replaceWith(function() {
        var replacement = $('<' + that + '>').html($(this).html());
        for (var i = 0; i < this.attributes.length; i++) {
            replacement.attr(this.attributes[i].name, this.attributes[i].value);
        }
        return replacement;
    });
    if ($(thisWith).length>0) {
        replace(thisWith, that);
    }
}

replace('code','pre');
Tewathia
quelle
2
beste Antwort bisher. Die anderen sind so ziemlich alle gleich, was wirklich seltsam ist, dass die Leute sie unterstützen. Congratz dafür, dass er der einzige war, der über die Attribute nachdachte.
Guilherme David da Costa
2

Wenn Sie Vanille-JavaScript verwenden würden, würden Sie:

  • Erstellen Sie das neue Element
  • Verschieben Sie die untergeordneten Elemente des alten Elements in das neue Element
  • Fügen Sie das neue Element vor dem alten ein
  • Entfernen Sie das alte Element

Hier ist das jQuery-Äquivalent zu diesem Prozess:

$("code").each(function () {
    $("<pre></pre>").append(this.childNodes).insertBefore(this);
    $(this).remove();
});

Hier ist die jsperf-URL:
http://jsperf.com/substituting-one-tag-for-another-with-jquery/7

PS: Alle Lösungen , die Verwendung .html()oder .innerHTMLsind zerstörerisch .

Salman A.
quelle
2

Ein weiterer kurzer und einfacher Weg:

$('code').wrapInner('<pre />').contents();
Fabian von Ellerts
quelle
0
$('code').each(function(){
    $(this).replaceWith( "<pre>" + $(this).html()  + "</pre>" );
    });

Beste und saubere Art und Weise.

Nimek
quelle
0

Sie können die HTML-Funktion von jQuery verwenden. Unten finden Sie ein Beispiel, bei dem ein Code-Tag durch ein Pre-Tag ersetzt wird, wobei alle Attribute des Codes beibehalten werden.

    $('code').each(function() {
        var temp=$(this).html();
        temp=temp.replace("code","pre");
        $(this).html(temp);
    });

Dies kann mit jedem Satz von HTML-Element-Tags funktionieren, die ausgetauscht werden müssen, während alle Attribute des vorherigen Tags beibehalten werden.

Arnab C.
quelle
0

Hergestellt jqueryPlugin, Pflege auch Attribute.

$.fn.renameTag = function(replaceWithTag){
  this.each(function(){
        var outerHtml = this.outerHTML;
        var tagName = $(this).prop("tagName");
        var regexStart = new RegExp("^<"+tagName,"i");
        var regexEnd = new RegExp("</"+tagName+">$","i")
        outerHtml = outerHtml.replace(regexStart,"<"+replaceWithTag)
        outerHtml = outerHtml.replace(regexEnd,"</"+replaceWithTag+">");
        $(this).replaceWith(outerHtml);
    });
    return this;
}

Verwendung:

$('code').renameTag('pre')
JagsSparrow
quelle
0

Alle hier gegebenen Antworten setzen voraus (wie das Fragenbeispiel zeigt), dass das Tag keine Attribute enthält. Wenn die akzeptierte Antwort darauf ausgeführt wird:

<code class='cls'>A</code>

if wird ersetzt durch

<pre>A</pre>

Was ist, wenn Sie auch die Attribute behalten möchten - was würde das Ersetzen eines Tags bedeuten ...? Das ist die Lösung:

$("code").each( function(){
    var content = $( "<pre>" );

    $.each( this.attributes, function(){ 
         content.attr( this.name, this.value );
    } );

    $( this ).replaceWith( content );
} );
Patrick
quelle
Ich weiß, dass dies ein paar Jahre alt ist, aber ich dachte nur, ich würde erwähnen ... Sie haben vergessen, das HTML vom vorherigen Element fernzuhalten. In Ihrem Code-Snippet erstellen Sie lediglich ein neues Element mit den Attributen, ohne eines der untergeordneten Elemente zu kopieren.
Ein Freund
Das würde durch Hinzufügen voncontent.html( this.html )
Patrick