Usando jQuery para substituir uma tag por outra


100

Objetivo:

Usando jQuery, estou tentando substituir todas as ocorrências de:

<code> ... </code>

com:

<pre> ... </pre>

Minha solução:

Eu cheguei até o seguinte,

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

O problema com minha solução:

mas o problema é que ele está substituindo tudo entre as (segunda, terceira, quarta, etc) tags de "código" pelo conteúdo entre as primeiras tags de "código".

por exemplo

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

torna-se

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

Acho que preciso usar "isso" e algum tipo de função, mas ainda estou aprendendo e não entendo realmente como montar uma solução.


Corrigida a solução de empacotamento agora jon - confira;)
— Jens Roland

Respostas:


157

Você pode passar uma função para .replaceWith [documentos] :

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

Dentro da função, thisrefere-se ao codeelemento processado atualmente .

DEMO

Atualização: não há grande diferença de desempenho , mas caso os codeelementos tenham outros filhos HTML, anexar os filhos em vez de serializá-los parece ser mais correto:

$('code').replaceWith(function(){
    return $("<pre />").append($(this).contents());
});

1
esta parece ser a solução mais elegante, embora eu admita que não entendo o que está acontecendo dentro da função replaceWith. adoraria ouvir mais. ou seja, como é atribuir as tags de abertura e fechamento? o espaço em <pre /> cumpre isso?
— junho de

2
@jon: É um atalho para a criação de novos elementos. Mais informações podem ser encontradas aqui: api.jquery.com/jQuery/#jQuery2 . jQuery faz um loop em todos os elementos e executa a função para cada um deles (o mesmo que .eachestá fazendo).
— Felix Kling de

@jon: Mas verifique a solução de Jens novamente, ele consertou.
— Felix Kling de

1
+1 para um bom truque - isso pode ser usado para muito mais do que uma simples substituição tag por tag.
— Jens Roland

@FelixKling Isso não substituiria os atributos das tags de código?
— tewathia de

80

Isso é muito melhor:

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

Embora reconhecidamente a solução de Felix Kling seja aproximadamente duas vezes mais rápida :


4
funcionou como um encanto, aos meus olhos leigos esta parece ser a solução mais eficiente. :)
— jon

aha. sim, vocês estavam certos. não funcionou para mim também. obrigado por pegar isso!
— junho de

1
FWIW, $('code').children()retornará um objeto jQuery vazio para o exemplo acima, porque os codeelementos não têm nós de elemento filho. Embora funcione se houver elementos filho.
— Felix Kling de

1
Fixo - verdadeiro, quando o conteúdo consiste em um único nó de texto, children()não funciona. Usar em contents()vez disso funciona perfeitamente. jsfiddle.net/7Yne9
— Jens Roland

1
Aqui está uma versão do jsperf que não quebra a página: jsperf.com/substituting-one-tag-for-another-with-jquery/2 e você vê que a diferença de velocidade não é mais tão grande. Sua solução é mais lenta porque você executa duas manipulações de DOM por elemento: unwrapremove o pai e adiciona os filhos à árvore, wrapdesanexa-os novamente e adiciona um novo pai.
— Felix Kling de

26

É correto que você obterá sempre o codeconteúdo do primeiro , pois $('code').html()sempre se referirá ao primeiro elemento, onde quer que o use.

Em vez disso, você pode usar .eachpara iterar todos os elementos e alterar cada um individualmente:

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

12

Experimente isto:

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

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

});

http://jsfiddle.net/mTGhV/


Uau. vocês chegaram com a mesma solução exata com 2 segundos de diferença. existem pequenas diferenças de formatação. Não tenho certeza de qual votar - eu realmente não gosto do espaço entre a função e () na resposta de Thomas e as 2 linhas de espaço vazio na resposta de kokos são bastante pontuais + deve haver um espaço entre () e o {
— Michael Bylstra

11

Que tal agora?

$('code').each(function () {
    $(this).replaceWith( "<pre>" + $(this).html() + "</pre>" );
});

6

Construindo a resposta de Felix.

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

Isso reproduzirá os atributos das codetags nas pretags de substituição .

Editar: Isso substituirá até mesmo as codetags que estão dentro innerHTMLde outras codetags.

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');

2
melhor resposta até agora. Os outros são praticamente todos iguais, o que é realmente estranho que as pessoas votem neles. Parabéns por ser o único que pensou nos atributos.
— Guilherme David da Costa


2

Se você estivesse usando o JavaScript vanilla, você:

  • Crie o novo elemento
  • Mova os filhos do elemento antigo para o novo elemento
  • Insira o novo elemento antes do antigo
  • Remova o elemento antigo

Aqui está o equivalente em jQuery deste processo:

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

Aqui está o URL do jsperf:
http://jsperf.com/substituting-one-tag-for-another-with-jquery/7

PS: Todas as soluções que usam .html()ou .innerHTMLsão destrutivas .



0
$('code').each(function(){
    $(this).replaceWith( "<pre>" + $(this).html()  + "</pre>" );
    });

Maneira melhor e limpa.


0

Você pode usar a função html do jQuery. Abaixo está um exemplo que substitui uma tag de código por uma tag pre, mantendo todos os atributos do código.

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

Isso poderia funcionar com qualquer conjunto de tags de elemento html que precisassem ser trocadas enquanto retinham todos os atributos da tag anterior.


0

jqueryPlugin feito , mantendo também atributos.

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

Uso:

$('code').renameTag('pre')

0

Todas as respostas fornecidas aqui presumem (como indica o exemplo da pergunta) que não há atributos na tag. Se a resposta aceita for executada neste:

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

se será substituído por

<pre>A</pre>

E se você quiser manter os atributos também - que é o que significaria substituir uma tag ...? Esta é a solução:

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

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

    $( this ).replaceWith( content );
} );

Eu sei que isso tem alguns anos, mas eu apenas pensei em mencionar ... você se esqueceu de manter o html do elemento anterior. Em seu snippet de código, você está apenas criando um novo elemento com os atributos sem copiar nenhum dos filhos também.
— Um amigo

isso seria feito adicionandocontent.html( this.html )
— patrick
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.