Obter o HTML externo do elemento selecionado

792

Estou tentando obter o HTML de um objeto selecionado com jQuery. Eu estou ciente da .html()função; o problema é que preciso do HTML, incluindo o objeto selecionado (neste caso, uma linha da tabela, onde .html()somente retorna as células dentro da linha).

Eu procurei e encontrei alguns métodos do tipo 'hackish' de clonar um objeto, adicionando-o a uma div recém criada, etc, etc, mas isso parece realmente sujo. Existe alguma maneira melhor ou a nova versão do jQuery (1.4.2) oferece algum tipo de outerHtmlfuncionalidade?

Ryan
fonte
89
É escandaloso que o jQuery não tenha meios para fazer isso. Eu também preciso disso.
Josef Sábl
9
Publiquei uma solicitação de recurso, com uma referência a este segmento, e a resposta inicial foi positiva. bugs.jquery.com/ticket/8142
mindplay.dk 02/02
11
Para poupar algumas pessoas, por alguns segundos, de experimentar a solução da Ulhas Tuscano, isso não funciona.
Dave
73
O que está acontecendo? $('div')[0].outerHTML.
Salman von Abbas
24
@Tuscan significava $ ("# selectorid"). Prop ("outerHTML")
guy mograbi

Respostas:

189

Edição de 2014: A pergunta e esta resposta são de 2010. Na época, nenhuma solução melhor estava amplamente disponível. Agora, muitas das outras respostas são melhores: Eric Hu ou Re Capcha, por exemplo.

Este site parece ter uma solução para você: jQuery: outerHTML | Yelotofu

jQuery.fn.outerHTML = function(s) {
    return s
        ? this.before(s).remove()
        : jQuery("<p>").append(this.eq(0).clone()).html();
};
David V.
fonte
4
Eu vi isso, mas estava tentando evitá-lo, porque parecia hackear e como deveria ter havido uma maneira melhor, mas funciona bem. Obrigado.
Ryan
359
$ ('[selector]') [0] .outerHTML
drogon
25
@drogon: Esteja ciente de que o outerHTMLFirefox é suportado apenas desde a versão 11 (março de 2012).
Blaise
8
@PavingWays: Em defesa do Firefox: outerHTMLé um atributo proprietário inventado pela Microsoft, não um padrão W3C. (Curiosidade: innerHTMLé padronizado apenas desde HTML5 )
Blaise
3
js puroel.outerHTML || document.createElement('div').appendChild( el.cloneNode( true ) ).parentNode.innerHTML
rab
675

Acredito que atualmente (1/5/2012), todos os principais navegadores suportam a função outerHTML. Parece-me que esse trecho é suficiente. Eu pessoalmente escolheria memorizar isso:

// Gives you the DOM element without the outside wrapper you want
$('.classSelector').html()

// Gives you the outside wrapper as well only for the first element
$('.classSelector')[0].outerHTML

// Gives you the outer HTML for all the selected elements
var html = '';
$('.classSelector').each(function () {
    html += this.outerHTML;
});

//Or if you need a one liner for the previous code
$('.classSelector').get().map(function(v){return v.outerHTML}).join('');

EDIT : estatísticas básicas de suporte paraelement.outerHTML

Eric Hu
fonte
14
O @SalmanPK FireFox não era compatível com esta propriedade até 11/11/2011. bugzilla.mozilla.org/show_bug.cgi?id=92264 Ainda existem muitos usuários presos no 3.6. Eu acho que este é realmente um exemplo perfeito de por que alguém escolheria usar o jQuery em vez da funcionalidade nativa.
Lucifer Sam
8
O @LuciferSam Firefox 3.6 possui ~ 6% de participação no mercado global, de acordo com gs.statcounter.com No entanto, filtrar os resultados nos últimos 6 meses (dez '11 a maio '12) e para os EUA retira da lista dos 12 melhores (abaixo de 3 %) Eu escolhi essa janela, pois este artigo sugere que o uso do FF 3.6 caiu significativamente após janeiro de 2012. Dados esses dados, mantenho a minha solução para um código mais simples sobre compatibilidade com versões anteriores.
Eric Hu
4
Não poderia concordar mais. Esta é a resposta certa aqui, não as outras coisas que as pessoas estão sugerindo. O elemento que eu seleciono possui atributos que eu quero manter e que são perdidos pelas outras respostas. Inferno, isso ainda funciona no IE!
Matthew Bonig
Não. O Firefox 11 não foi lançado até 13 de março de 2012 (corrigido agora), ou seja, há menos de um ano atrás. Um dos benefícios do jQuery é que ele suporta navegadores mais antigos. Eu acho que apoiar pelo menos um ano é razoável, e alguns sites obviamente vão querer mais (lembre-se, o jQuery suporta o IE6).
Matthew Flaschen
7
O @EricHu statcounter também afirma que o IE8 possui 9,3% do compartilhamento global do navegador. No entanto, alguns dos meus sites estão perto da marca de 40%. É tudo relativo e varia enormemente de site para site, o Firefox 3.6 ainda é responsável por aproximadamente 10% em alguns dos meus sites. Participação no mercado global não significa nada. É tudo sobre o público do seu site.
George Reith
343

Não há necessidade de gerar uma função para ele. Apenas faça assim:

$('a').each(function(){
    var s = $(this).clone().wrap('<p>').parent().html();
    console.log(s);
});

(A propósito, o console do seu navegador mostrará o que é registrado. A maioria dos navegadores mais recentes desde 2009 tem esse recurso.)

A mágica é esta no final:

.clone().wrap('<p>').parent().html();

O clone significa que você não está realmente perturbando o DOM. Execute-o sem ele e você verá as ptags inseridas antes / depois de todos os hiperlinks (neste exemplo), o que é indesejável. Então, sim, use.clone() .

O modo como funciona é que ele pega cada atag, cria um clone na RAM, envolve petiquetas, obtém o pai dela (ou seja, a ptag) e, em seguida, obtém sua innerHTMLpropriedade.

EDIT : aconselhou e mudou divtags para ptags porque é menos digitado e funciona da mesma maneira.

Volomike
fonte
82
Gostaria de saber por que a equipe jQuery não adiciona um método outerHtml ()?
quer
1
@ Derek, isso não importa. Estou usando o DIV como invólucro para obter algo dentro dele.
Volomike
11
.clone (). wrap ('<p>') .parent (). html (); é mais curto
Uğur Gümüşhan
1
Sim, menos pressionamentos de tecla e obtém o mesmo efeito.
Volomike 04/04
14
Melhor usar o DIV em vez de P para uma solução geral - nem todos os elementos podem ser agrupados em P como HTML válido.
Blazemonger
149

Que tal prop('outerHTML'):?

var outerHTML_text = $('#item-to-be-selected').prop('outerHTML');

E para definir:

$('#item-to-be-selected').prop('outerHTML', outerHTML_text);

Funcionou para mim.

PS : Isso é adicionado no jQuery 1.6 .

Re Captcha
fonte
4
Código muito elegante e pequeno em comparação com as outras respostas. P: Isso tem as mesmas restrições deHTML externas, conforme observado em outras respostas? Funciona em FF <11?
MacroMan
3
Funciona bem, isso pode ser apenas a melhor solução aqui. Tanto quanto os navegadores, isso deve ser tão compatível quanto o outerHTLM. O método prop () está basicamente obtendo a propriedade outerHTML.
Tom Tom
2
Esta solução é melhor, no entanto, o Jquery 1.6.1 foi lançado em 2011. A questão (e a minha resposta) são de 2010. #
1077 David V.
1
Para mim "$ ('[selector]') [0] .outerHTML;" não funcionou em nenhum caso, mas "$ ('# item a ser selecionado'). prop ('outerHTML');" sim!
Eduardo Lucio
2
$ ('# item a ser selecionado'). attr ('outerHTML'); // ** Para jQuery's anteriores
Meetai.com 03/03
91

Estenda o jQuery:

(function($) {
  $.fn.outerHTML = function() {
    return $(this).clone().wrap('<div></div>').parent().html();
  };
})(jQuery);

E use-o assim: $("#myTableRow").outerHTML();

jessica
fonte
8
Pequeno problema com esta solução: você precisa clonar () antes de quebrar (), caso contrário, você está deixando o invólucro extra <div> no documento.
mindplay.dk
1
Obrigado, mindplay.dk - editei o código para incorporar sua sugestão. Boa captura. :)
jessica
2
Que tal reverter isso: return $('<div>').append(this.clone()).html();é apenas um pouco mais direto ao ponto.
Justin Warkentin
2
Você deve verificar para outerHTML primeiro e usar apenas que para os navegadores que suportam isso
James Westgate
Isso é ótimo para pessoas como eu que gostam de criar HTML em respostas AJAX usando objetos jQuery e as funções .appendTo () e .append (). .outerHTML não funciona para essas instâncias pelo que vi nos meus testes. Outra pessoa pode querer verificar mais isso, mas não tenho tempo.
21815 Sean O'Neill,
43

Eu concordo com Arpan (13 de dezembro de 10 5:59).

Sua maneira de fazer isso é realmente uma maneira MUITO melhor de fazê-lo, já que você não usa clone. O método clone consome muito tempo, se você tiver elementos filhos, e ninguém mais parecia se importar com o fato de o IE ter oouterHTML IE ter atributo (sim, o IE realmente tem alguns truques úteis na manga).

Mas eu provavelmente criaria o script dele um pouco diferente:

$.fn.outerHTML = function() {
    var $t = $(this);
    if ($t[0].outerHTML !== undefined) {
        return $t[0].outerHTML;
    } else {
        var content = $t.wrap('<div/>').parent().html();
        $t.unwrap();
        return content;
    }
};
Tokimon
fonte
2
Isso funcionou perfeitamente para mim. Devido a um erro com clone()e textarea, eu precisava de uma solução não-clone, e isso estava certo.
Shpigford 6/07
5
+1 para usar o nativo, outerHTMLquando disponível, pois é compatível com o Chrome, além do Internet Explorer.
Andy E
9
if (! ('outerHTML' em $ t [0])) alert ('caramba, atualize seu navegador');
Psycho brm
19

Para ser verdadeiramente jQuery-esque, convém outerHTML()ser um getter e um setter e ter seu comportamento o mais semelhante html()possível:

$.fn.outerHTML = function (arg) {
    var ret;

    // If no items in the collection, return
    if (!this.length)
        return typeof arg == "undefined" ? this : null;
    // Getter overload (no argument passed)
    if (!arg) {
        return this[0].outerHTML || 
            (ret = this.wrap('<div>').parent().html(), this.unwrap(), ret);
    }
    // Setter overload
    $.each(this, function (i, el) {
        var fnRet, 
            pass = el,
            inOrOut = el.outerHTML ? "outerHTML" : "innerHTML";

        if (!el.outerHTML)
            el = $(el).wrap('<div>').parent()[0];

        if (jQuery.isFunction(arg)) { 
            if ((fnRet = arg.call(pass, i, el[inOrOut])) !== false)
                el[inOrOut] = fnRet;
        }
        else
            el[inOrOut] = arg;

        if (!el.outerHTML)
            $(el).children().unwrap();
    });

    return this;
}

Demonstração de trabalho: http://jsfiddle.net/AndyE/WLKAa/

Isso nos permite passar um argumento para outerHTML, que pode ser

  • uma função cancelável - function (index, oldOuterHTML) { }- onde o valor retornado se tornará o novo HTML para o elemento (a menos que falseseja retornado).
  • uma string, que será definida no lugar do HTML de cada elemento.

Para obter mais informações, consulte os documentos do jQuery para html().

Andy E
fonte
Isso deve ser adicionado ao núcleo do jQuery para que as pessoas não precisem pensar sobre isso. Minha única pergunta é se é provável que o wrap () / desembrulhe () seja melhor ou pior que o clone ()?
IMSoP
1
IMSoP: Geralmente, o wrap / desembrulhar será mais rápido porque o clone precisará copiar todos os elementos filho e atributos do elemento. O wrap () cria apenas um elemento e o desembrulha () o destrói; todos os outros elementos são movidos, o que é uma operação bastante rápida na maioria das vezes.
Andy E
16

Você também pode usar get (Recupere os elementos DOM correspondentes ao objeto jQuery.).

por exemplo:

$('div').get(0).outerHTML;//return "<div></div>"

Como método de extensão:

jQuery.fn.outerHTML = function () {
  return this.get().map(function (v) {
    return v.outerHTML
  }).join()
};

Ou

jQuery.fn.outerHTML = function () {
  return $.map(this.get(), function (v) {
    return v.outerHTML
  }).join()
};

Escolha múltipla e retorne o html externo de todos os elementos correspondentes.

$('input').outerHTML()

Retorna:

'<input id="input1" type="text"><input id="input2" type="text">'
MJ Vakili
fonte
11

Para criar um plug-in jQuery COMPLETO como .outerHTML, adicione o seguinte script a qualquer arquivo js e inclua após o jQuery em seu cabeçalho:

atualizar Nova versão tem melhor controle, além de um serviço mais amigável ao jQuery Selector! :)

;(function($) {
    $.extend({
        outerHTML: function() {
            var $ele = arguments[0],
                args = Array.prototype.slice.call(arguments, 1)
            if ($ele && !($ele instanceof jQuery) && (typeof $ele == 'string' || $ele instanceof HTMLCollection || $ele instanceof Array)) $ele = $($ele);
            if ($ele.length) {
                if ($ele.length == 1) return $ele[0].outerHTML;
                else return $.map($("div"), function(ele,i) { return ele.outerHTML; });
            }
            throw new Error("Invalid Selector");
        }
    })
    $.fn.extend({
        outerHTML: function() {
            var args = [this];
            if (arguments.length) for (x in arguments) args.push(arguments[x]);
            return $.outerHTML.apply($, args);
        }
    });
})(jQuery);

Isso permitirá que você não apenas obtenha o outerHTML de um elemento, mas também receba um retorno de vários elementos ao mesmo tempo! e pode ser usado nos dois estilos padrão do jQuery:

$.outerHTML($("#eleID")); // will return outerHTML of that element and is 
// same as
$("#eleID").outerHTML();
// or
$.outerHTML("#eleID");
// or
$.outerHTML(document.getElementById("eleID"));

Para vários elementos

$("#firstEle, .someElesByClassname, tag").outerHTML();

Exemplos de trechos:

SpYk3HH
fonte
9

você também pode fazer dessa maneira

document.getElementById(id).outerHTML

onde id é o id do elemento que você está procurando

Andy
fonte
4
$("#" + id).attr("id")é incrivelmente redundante. Se você já possui o ID em uma variável, por que está usando um seletor jquery para extrair o elemento do dom e consultando seu atributo ID?
Sam Dufel
7

Usei a solução de Jessica (que foi editada por Josh) para fazer com que o outerHTML funcionasse no Firefox. O problema, porém, é que meu código estava quebrando porque a solução dela envolveu o elemento em um DIV. A adição de mais uma linha de código resolveu esse problema.

O código a seguir fornece o outerHTML, deixando a árvore DOM inalterada.

$jq.fn.outerHTML = function() {
    if ($jq(this).attr('outerHTML'))
        return $jq(this).attr('outerHTML');
    else
    {
    var content = $jq(this).wrap('<div></div>').parent().html();
        $jq(this).unwrap();
        return content;
    }
}

E use-o assim: $ ("# myDiv"). OuterHTML ();

Espero que alguém ache útil!

Arpan Dhandhania
fonte
1
Basta usar .clone como @mindplay sugere em seu comment- é mais fácil
Yarin
6
// no cloning necessary    
var x = $('#xxx').wrapAll('<div></div>').parent().html(); 
alert(x);

Violino aqui: http://jsfiddle.net/ezmilhouse/Mv76a/

Abdennour TOUMI
fonte
4

Se o cenário estiver anexando uma nova linha dinamicamente, você poderá usar este:

var row = $(".myRow").last().clone();
$(".myRow").last().after(row);

.myrowé o nome da classe do <tr>. Ele faz uma cópia da última linha e a insere como uma nova última linha. Isso também funciona no IE7 , enquanto o [0].outerHTMLmétodo não permite atribuições no ie7

Stefan Bookholt
fonte
3

node.cloneNode () dificilmente parece um hack. Você pode clonar o nó e anexá-lo a qualquer elemento pai desejado e também manipulá-lo, manipulando propriedades individuais, em vez de ter que, por exemplo, executar expressões regulares nele ou adicioná-lo ao DOM e manipulá-lo depois.

Dito isto, você também pode iterar sobre os atributos do elemento para construir uma representação em string HTML dele. Parece provável que é assim que qualquer função outerHTML seria implementada se o jQuery adicionasse uma.

Ben Regenspan
fonte
3

Eu usei a solução da Volomike atualizada por Jessica. Basta adicionar uma verificação para ver se o elemento existe e retornar em branco caso não exista.

jQuery.fn.outerHTML = function() {
return $(this).length > 0 ? $(this).clone().wrap('<div />').parent().html() : '';
};

Obviamente, use-o como:

$('table#buttons').outerHTML();
Ivan Chaer
fonte
3

Você pode encontrar uma boa opção .outerHTML () aqui https://github.com/darlesson/jquery-outerhtml .

Ao contrário de .html () que retorna apenas o conteúdo HTML do elemento, esta versão de .outerHTML () retorna o elemento selecionado e seu conteúdo HTML ou o substitui como método .replaceWith (), mas com a diferença que permite que o HTML substituto seja herdado por o encadeamento.

Exemplos também podem ser vistos no URL acima.

Darlesson
fonte
2

Observe que a solução de Josh funciona apenas para um único elemento.

Indiscutivelmente, o HTML "externo" só faz sentido quando você tem um único elemento, mas há situações em que faz sentido pegar uma lista de elementos HTML e transformá-los em marcação.

Estendendo a solução de Josh, este manipulará vários elementos:

(function($) {
  $.fn.outerHTML = function() {
    var $this = $(this);
    if ($this.length>1)
      return $.map($this, function(el){ return $(el).outerHTML(); }).join('');
    return $this.clone().wrap('<div/>').parent().html();
  }
})(jQuery);

Edit: outro problema com a solução de Josh corrigida, veja o comentário acima.

mindplay.dk
fonte
1
A maioria dos métodos "getter" do jQuery retorna dados apenas para o primeiro elemento, portanto, faria mais sentido corresponder a esse comportamento.
Andy E
Eu acho que afirmei claramente por que funciona dessa maneira? Seria um código feio / complicado quando você tiver uma lista de elementos - se, por algum motivo, você quiser a marcação apenas para o primeiro elemento, use: first no seu seletor.
mindplay.dk
Claro, assim como você pode usar o mapa com a solução de todos os outros para obter o HTML de vários elementos. Tudo o que eu estava dizendo é que é mais consistente corresponder ao comportamento dos métodos jQuery padrão.
Andy E
2

Eu fiz esse teste simples com outerHTML sendo a solução tokimon (sem clone) e outerHTML2 sendo a solução jessica (clone)

console.time("outerHTML");
for(i=0;i<1000;i++)
 {                 
  var html = $("<span style='padding:50px; margin:50px; display:block'><input type='text' title='test' /></span>").outerHTML();
 }                 
console.timeEnd("outerHTML");

console.time("outerHTML2");

 for(i=0;i<1000;i++)
 {                 
   var html = $("<span style='padding:50px; margin:50px; display:block'><input type='text' title='test' /></span>").outerHTML2();
  }                 
  console.timeEnd("outerHTML2");

e o resultado no meu navegador chromium (versão 20.0.1132.57 (0)) foi

outerHTML: 81ms
outerHTML2: 439ms

mas se usarmos a solução tokimon sem a função outerHTML nativa (que agora é suportada provavelmente em quase todos os navegadores)

Nós temos

outerHTML: 594ms
outerHTML2: 332ms

e haverá mais loops e elementos em exemplos do mundo real, então a combinação perfeita seria

$.fn.outerHTML = function() 
{
  $t = $(this);
  if( "outerHTML" in $t[0] ) return $t[0].outerHTML; 
  else return $t.clone().wrap('<p>').parent().html(); 
}

O método clone é realmente mais rápido que o método wrap / desembrulhar
(jquery 1.7.2)

Petar
fonte
2

Aqui está um plugin outerHTML muito otimizado para jquery: ( http://jsperf.com/outerhtml-vs-jquery-clone-hack/5 => os outros dois trechos de código rápido não são compatíveis com alguns navegadores como FF <11)

(function($) {

  var DIV = document.createElement("div"),
      outerHTML;

  if ('outerHTML' in DIV) {
    outerHTML = function(node) {
      return node.outerHTML;
    };
  } else {
    outerHTML = function(node) {
      var div = DIV.cloneNode();
      div.appendChild(node.cloneNode(true));
      return div.innerHTML;
    };
  }

  $.fn.outerHTML = function() {
    return this.length ? outerHTML(this[0]) : void(0);
  };

})(jQuery);

@ Andy E => Eu não concordo com você. outerHMTL não precisa de um getter E de um setter: o jQuery já nos fornece 'replaceWith' ...

@mindplay => Por que você está juntando todo o outerHTML? jquery.html retorna apenas o conteúdo HTML do PRIMEIRO elemento.

(Desculpe, não tem reputação suficiente para escrever comentários)

gtournie
fonte
2

Curto e grosso.

[].reduce($('.x'), function(i,v) {return i+v.outerHTML}, '')

ou evento mais doce com a ajuda das funções de seta

[].reduce.call($('.x'), (i,v) => i+v.outerHTML, '')

ou sem jQuery

[].reduce.call(document.querySelectorAll('.x'), (i,v) => i+v.outerHTML, '')

ou se você não gostar dessa abordagem, verifique se

$('.x').get().reduce((i,v) => i+v.outerHTML, '')
rolacja
fonte
2

Isso é bastante simples com JavaScript baunilha ...

document.querySelector('#selector')
Azevinho
fonte
1

Isso é ótimo para alterar elementos no dom, mas NÃO funciona, ou seja, ao passar uma string html para o jquery como este:

$('<div id="foo">Some <span id="blog">content</span></div>').find('#blog').outerHTML();

Após alguma manipulação, criei uma função que permite que o acima funcione, ou seja, para strings html:

$.fn.htmlStringOuterHTML = function() {     
    this.parent().find(this).wrap('<div/>');        
    return this.parent().html();
};
inspiraller
fonte
1

$.html = el => $("<div>"+el+"</div>").html().trim();

evandrix
fonte
0

Me deparei com isso enquanto procurava uma resposta para o meu problema, que era tentar remover uma linha da tabela e adicioná-la novamente na parte inferior da tabela (porque eu estava criando linhas de dados dinamicamente, mas queria mostrar um 'Adicionar novo Linha do tipo 'Record' na parte inferior).

Eu tive o mesmo problema, na medida em que estava retornando o innerHtml, perdendo as tags TR, que continham o ID dessa linha e significavam que era impossível repetir o procedimento.

A resposta que encontrei foi que a remove()função jquery realmente retorna o elemento que ele remove como um objeto. Então, para remover e adicionar novamente uma linha, era tão simples quanto isso ...

var a = $("#trRowToRemove").remove();            
$('#tblMyTable').append(a);  

Se você não estiver removendo o objeto, mas quiser copiá-lo em outro lugar, use a clone()função.

duvidoso
fonte
0

O plugin jQuery como uma abreviação para obter diretamente todo o elemento HTML:

jQuery.fn.outerHTML = function () {
    return jQuery('<div />').append(this.eq(0).clone()).html();
};

E use-o assim: $(".element").outerHTML();

Sky Yip
fonte
-2
$("#myNode").parent(x).html(); 

Onde 'x' é o número do nó, começando com 0 como o primeiro, deve obter o nó certo que você deseja, se estiver tentando obter um nó específico. Se você tem nós filhos, deve realmente colocar um ID no que deseja, para se concentrar apenas nele. Usar essa metodologia e nenhum 'x' funcionou bem para mim.

vapcguy
fonte
1
As pessoas que votam nisto, gostaria de deixar um comentário? Estou fazendo com que o código vá até o PAI, depois pegue o HTML do conteúdo - não apenas fazendo um .html()no elemento especificado. ISSO FUNCIONA e eu gostaria de uma explicação de por que não.
precisa saber é o seguinte
-4

Solução simples.

var myself = $('#div').children().parent();
Zeeshan
fonte
-12
$("#myTable").parent().html();

Talvez eu não esteja entendendo sua pergunta corretamente, mas isso obterá o html do elemento pai do elemento selecionado.

É isso que você procura?

inkedmn
fonte
25
Na verdade não, porque se esse pai tiver outros filhos, ele também receberá esse html.
David V.
1
...o que ele disse. Estou procurando o elemento em si, não ele e todos os outros filhos de seus pais. Como isso conseguiu dois votos positivos ???
Ryan