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.