Używanie jQuery do zamiany jednego tagu na inny

101

Cel:

Używając jQuery, próbuję zamienić wszystkie wystąpienia:

<code> ... </code>

z:

<pre> ... </pre>

Moje rozwiązanie:

Dotarłem do następujących,

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

Problem z moim rozwiązaniem:

ale problem polega na tym, że zastępuje wszystko między tagami „kod” (drugi, trzeci, czwarty itd.) zawartością między pierwszymi tagami „kod”.

na przykład

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

staje się

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

Myślę, że muszę użyć „tego” i jakiejś funkcji, ale obawiam się, że wciąż się uczę i nie bardzo rozumiem, jak połączyć rozwiązanie.

jon
źródło
Naprawiono teraz rozwiązanie zawijania i rozpakowywania jon - sprawdź to;)
Jens Roland,

Odpowiedzi:

157

Możesz przekazać funkcję do .replaceWith [docs] :

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

Wewnątrz funkcji thisodnosi się do aktualnie przetwarzanego codeelementu.

PRÓBNY

Aktualizacja: nie ma dużej różnicy w wydajności , ale w przypadku, gdy codeelementy mają inne elementy podrzędne HTML, dołączanie elementów podrzędnych zamiast ich serializacji wydaje się być bardziej poprawne:

$('code').replaceWith(function(){
    return $("<pre />").append($(this).contents());
});
Felix Kling
źródło
1
wydaje się, że jest to najbardziej eleganckie rozwiązanie, chociaż przyznaję, że nie rozumiem, co się dzieje w funkcji replaceWith. chciałbym usłyszeć więcej. tj. jak przypisuje się otwierające i zamykające znaczniki? czy przestrzeń w <pre /> to spełnia?
jon
2
@jon: To krótka ręka do tworzenia nowych elementów. Więcej informacji można znaleźć tutaj: api.jquery.com/jQuery/#jQuery2 . jQuery zapętla wszystkie elementy i wykonuje funkcję dla każdego z nich (to samo .each).
Felix Kling
@jon: Ale sprawdź ponownie rozwiązanie Jensa, naprawił to.
Felix Kling
1
+1 za fajną sztuczkę - można jej użyć do czegoś więcej niż tylko zwykłego podstawiania typu tag za tag.
Jens Roland,
@FelixKling Czy to nie nadpisze atrybutów tagów kodu?
tewathia
80

To jest o wiele przyjemniejsze:

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

Chociaż trzeba przyznać, że rozwiązanie Felixa Klinga jest około dwa razy szybsze :

Jens Roland
źródło
4
zadziałało jak urok, moim laikom wydaje się to najbardziej efektywne rozwiązanie. :)
jon
Aha. tak, mieliście rację. dla mnie też nie zadziałało. dzięki za złapanie tego!
jon
1
FWIW $('code').children()zwróci pusty obiekt jQuery dla powyższego przykładu, ponieważ codeelementy nie mają węzłów elementów potomnych. Chociaż działa, jeśli istnieją elementy potomne.
Felix Kling
1
Naprawiono - prawda, gdy zawartość składa się z pojedynczego węzła tekstowego, children()nie działa. Używanie contents()zamiast tego działa doskonale. jsfiddle.net/7Yne9
Jens Roland
1
Oto wersja jsperf, która nie psuje strony: jsperf.com/substituting-one-tag-for-another-with-jquery/2 i widać, że różnica prędkości nie jest już tak duża. Twoje rozwiązanie jest wolniejsze, ponieważ wykonujesz dwie manipulacje DOM na element: unwrapusuwa rodzica i dodaje dzieci do drzewa, wrapodłącza je ponownie i dodaje nowego rodzica.
Felix Kling
26

To prawda, że ​​zawsze otrzymasz codezawartość pierwszego , ponieważ $('code').html()zawsze będzie odnosić się do pierwszego elementu, gdziekolwiek go użyjesz.

Zamiast tego możesz użyć .eachiteracji po wszystkich elementach i zmienić każdy z nich indywidualnie:

$('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
źródło
12

Spróbuj tego:

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

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

});

http://jsfiddle.net/mTGhV/

Kokos
źródło
łał. wymyśliliście dokładnie to samo rozwiązanie w ciągu 2 sekund od siebie. istnieją drobne różnice w formatowaniu. Nie jestem pewien, który z nich głosować za głosem - naprawdę nie podoba mi się spacja między funkcją a () w odpowiedzi Thomasa, a 2 wiersze pustej przestrzeni w odpowiedzi kokos są dość pointlness + powinna być spacja między () i {
Michael Bylstra
11

Co powiesz na to?

$('code').each(function () {
    $(this).replaceWith( "<pre>" + $(this).html() + "</pre>" );
});
Tae-Sung Shin
źródło
6

Opierając się na odpowiedzi Felixa.

$('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;
});

Spowoduje to odtworzenie atrybutów codetagów w pretagach zastępczych .

Edycja: spowoduje to zastąpienie nawet tych codetagów, które znajdują się wewnątrz innerHTMLinnych codetagów.

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
źródło
2
jak dotąd najlepsza odpowiedź. Pozostałe są prawie takie same, co jest naprawdę dziwne, że ludzie je popierają. Gratuluję, że jesteś jedyną osobą, która pomyślała o atrybutach.
Guilherme David da Costa
2

Gdybyś używał waniliowego JavaScript, to:

  • Utwórz nowy element
  • Przenieś elementy potomne starego elementu do nowego elementu
  • Wstaw nowy element przed starym
  • Usuń stary element

Oto odpowiednik tego procesu w jQuery:

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

Oto adres URL jsperf:
http://jsperf.com/substituting-one-tag-for-another-with-jquery/7

PS: Wszystkie rozwiązania, które wykorzystują .html()lub .innerHTMLdestrukcyjne .

Salman A
źródło
2

Kolejny krótki i łatwy sposób:

$('code').wrapInner('<pre />').contents();
Fabian von Ellerts
źródło
0
$('code').each(function(){
    $(this).replaceWith( "<pre>" + $(this).html()  + "</pre>" );
    });

Najlepszy i czysty sposób.

Nimek
źródło
0

Możesz użyć funkcji html jQuery. Poniżej znajduje się próbka polegająca na zamianie znacznika kodowego na znacznik wstępny, przy jednoczesnym zachowaniu wszystkich atrybutów kodu.

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

Może to działać z dowolnym zestawem znaczników elementów HTML, które trzeba było zamienić, zachowując wszystkie atrybuty poprzedniego znacznika.

Arnab C.
źródło
0

Stworzono jquerywtyczkę, zachowując również atrybuty.

$.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;
}

Stosowanie:

$('code').renameTag('pre')
Jagdish Idhate
źródło
0

Wszystkie podane tutaj odpowiedzi zakładają (jak wskazuje przykład pytania), że w tagu nie ma atrybutów. Jeśli zaakceptowana odpowiedź zostanie uruchomiona na tym:

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

jeśli zostanie zastąpiony

<pre>A</pre>

Co jeśli chcesz zachować również atrybuty - co oznaczałoby zastąpienie tagu ...? Oto rozwiązanie:

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

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

    $( this ).replaceWith( content );
} );
patrick
źródło
Wiem, że to ma kilka lat, ale pomyślałem, że wspomnę ... zapomniałeś zachować HTML z poprzedniego elementu. W swoim fragmencie kodu po prostu tworzysz nowy element z atrybutami bez kopiowania żadnego elementu podrzędnego.
Przyjaciel
byłoby to zrobione przez dodaniecontent.html( this.html )
patrick