Obtener el HTML externo del elemento seleccionado

792

Estoy tratando de obtener el HTML de un objeto seleccionado con jQuery. Soy consciente de la .html()función; El problema es que necesito el HTML que incluye el objeto seleccionado (una fila de tabla en este caso, donde .html()solo devuelve las celdas dentro de la fila).

He buscado alrededor y he encontrado algunos métodos de tipo muy 'hack' para clonar un objeto, agregarlo a un div recién creado, etc., etc., pero esto parece realmente sucio. ¿Hay alguna manera mejor, o la nueva versión de jQuery (1.4.2) ofrece algún tipo de outerHtmlfuncionalidad?

Ryan
fuente
89
Es indignante que jQuery no tenga medios para hacer tal cosa. Yo también necesito esto.
Josef Sábl
99
He publicado una solicitud de función, con una referencia a este hilo, y la respuesta inicial fue positiva. bugs.jquery.com/ticket/8142
mindplay.dk
11
Para ahorrarle a algunas personas unos segundos de su tiempo de probar la solución de Ulhas Tuscano, no funciona.
Dave
73
Uh, que está pasando. $('div')[0].outerHTML.
Salman von Abbas
24
@Tuscan significaba $ ("# selectorid"). Prop ("exteriorHTML")
guy mograbi

Respuestas:

189

Edición de 2014: la pregunta y esta respuesta son de 2010. En ese momento, no había una solución mejor disponible. Ahora, muchas de las otras respuestas son mejores: las de Eric Hu o Re Capcha, por ejemplo.

Este sitio parece tener una solución para usted: jQuery: outsideHTML | Yelotofu

jQuery.fn.outerHTML = function(s) {
    return s
        ? this.before(s).remove()
        : jQuery("<p>").append(this.eq(0).clone()).html();
};
David V.
fuente
44
Vi esto pero estaba tratando de evitarlo porque parecía hackear y parecía que debería haber una mejor manera, pero funciona bien. Gracias.
Ryan
359
$ ('[selector]') [0] .outerHTML
drogon
25
@drogon: Tenga en cuenta que solo outerHTMLes compatible con Firefox desde la versión 11 (marzo de 2012).
Blaise
8
@PavingWays: En defensa de Firefox: outerHTMLes un atributo patentado inventado por Microsoft, no un estándar W3C. (Dato curioso: innerHTMLestá estandarizado solo desde HTML5 )
Blaise
3
js puroel.outerHTML || document.createElement('div').appendChild( el.cloneNode( true ) ).parentNode.innerHTML
rab
675

Creo que actualmente (5/1/2012), todos los principales navegadores admiten la función externalHTML. Me parece que este fragmento es suficiente. Yo personalmente elegiría memorizar esto:

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

EDITAR : estadísticas básicas de soporte paraelement.outerHTML

Eric Hu
fuente
14
@SalmanPK FireFox no admitió esta propiedad hasta 2011-11-11. bugzilla.mozilla.org/show_bug.cgi?id=92264 Todavía hay muchos usuarios atascados en 3.6. Creo que este es realmente un ejemplo perfecto de por qué uno elegiría usar jQuery sobre la funcionalidad nativa.
Lucifer Sam
8
@LuciferSam Firefox 3.6 tiene una participación de mercado global de ~ 6% de acuerdo con gs.statcounter.com Sin embargo, filtrar los resultados de los últimos 6 meses (diciembre '11-mayo '12) y EE. UU. Lo elimina de su lista de los 12 principales (debajo de 3 %) Elegí esta ventana ya que este artículo sugiere que el uso de FF 3.6 se redujo significativamente después de enero de 2012. Teniendo en cuenta estos datos, defiendo mi solución para obtener un código más simple sobre la compatibilidad con versiones anteriores.
Eric Hu
44
No podría estar más de acuerdo. Esta es la respuesta correcta aquí, no las otras cosas que la gente sugiere. El elemento que selecciono tiene atributos que quiero conservar que se pierden con las otras respuestas. Demonios, ¡esto incluso funciona en IE!
Matthew Bonig
No. Firefox 11 no se lanzó hasta el 13 de marzo de 2012 (corregido ahora), es decir, hace menos de un año a partir de este escrito. Uno de los beneficios de jQuery es que es compatible con navegadores antiguos. Creo que apoyar al menos un año es razonable, y algunos sitios obviamente van a querer más (recuerde, jQuery es compatible con IE6).
Matthew Flaschen el
77
@EricHu statcounter también afirma que IE8 tiene el 9.3% de la cuota global del navegador. Sin embargo, algunos de mis sitios web están cerca de la marca del 40%. Todo es relativo y varía enormemente de un sitio web a otro, Firefox 3.6 todavía representa aproximadamente el 10% en algunos de mis sitios web. La cuota de mercado global no significa nada. Se trata de la audiencia de su sitio web.
George Reith
343

No es necesario generar una función para ello. Solo hazlo así:

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

(La consola de su navegador mostrará lo que está registrado, por cierto. La mayoría de los navegadores más recientes desde alrededor de 2009 tienen esta característica).

La magia es esta al final:

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

El clon significa que en realidad no estás molestando al DOM. Ejecútalo sin él y verásp etiquetas insertadas antes / después de todos los hipervínculos (en este ejemplo), lo que no es deseable. Entonces, sí, usa.clone() .

La forma en que funciona es que toma cada aetiqueta, hace un clon de la misma en la RAM, la envuelve con las petiquetas, obtiene la matriz (es decir, la petiqueta) y luego obtiene la etiquetainnerHTML propiedad de la misma.

EDITAR : tomó consejos y cambiódiv etiquetas a petiquetas porque es menos tipeado y funciona igual.

Volomike
fuente
82
Me pregunto por qué el equipo de jQuery no agrega un método externo (HTML).
Donny V.
1
@Derek, eso no importaría. Estoy usando DIV como envoltorio para obtener algo dentro.
Volomike
11
.clone (). wrap ('<p>') .parent (). html (); es más corto
Uğur Gümüşhan
1
Sí, menos pulsaciones de teclas, y logra el mismo efecto.
Volomike
14
Es mejor usar DIV en lugar de P para una solución general: no todos los elementos se pueden incluir en P como HTML válido.
Blazemonger
149

¿Qué pasa con prop('outerHTML'):?

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

Y para configurar:

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

Funcionó para mi.

PD : Esto se agrega en jQuery 1.6 .

Re Captcha
fuente
44
Código muy ordenado y pequeño en comparación con las otras respuestas. P: ¿Tiene esto las mismas restricciones externas de HTML que se indican en otras respuestas? ¿Funciona en FF <11?
MacroMan
3
Funciona bien, esta podría ser la mejor solución aquí. En lo que respecta a los navegadores, esto debería ser tan compatible como externalHTLM. El método prop () básicamente solo obtiene la propiedad externalHTML.
Tom Tom
2
Esta solución es mejor, sin embargo, Jquery 1.6.1 se lanzó en 2011. La pregunta (y mi respuesta) son de 2010.
David V.
1
Para mí "$ ('[selector]') [0] .outerHTML;" no funcionó en ningún caso, pero "$ ('# item-to-be-select'). prop ('externalHTML');" ¡si!
Eduardo Lucio
2
$ ('# elemento a ser seleccionado'). attr ('externalHTML'); // ** Para jQuery's anteriores
Meetai.com
91

Extienda jQuery:

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

Y úsalo así: $("#myTableRow").outerHTML();

jessica
fuente
8
Pequeño problema con esta solución: debe clonar () antes de ajustar (), de lo contrario, dejará el ajuste adicional <div> en el documento.
mindplay.dk
1
Gracias, mindplay.dk: edité el código para incorporar su sugerencia ... buena captura. :)
jessica
2
¿Qué hay de revertir eso? return $('<div>').append(this.clone()).html();Es solo un poco más al grano.
Justin Warkentin
2
Primero debe verificar si hay externalHTML y solo usarlo para los navegadores que lo admiten
James Westgate el
Esto es ideal para personas como yo a quienes les gusta construir HTML en respuestas AJAX usando objetos jQuery y las funciones .appendTo () y .append (). .outerHTML no funciona para esas instancias por lo que vi en mis pruebas. Es posible que alguien más quiera comprobarlo más, pero no tengo tiempo.
Sean Kendle
43

Estoy de acuerdo con Arpan (Dec 13 '10 5:59).

Su forma de hacerlo es en realidad una forma MUCHO mejor de hacerlo, ya que no usas clon. El método de clonación consume mucho tiempo, si tiene elementos secundarios, y a nadie más parece importarle que IE TENGA elouterHTML atributo (sí, IE en realidad tiene ALGUNOS trucos útiles bajo la manga).

Pero probablemente crearía su guión un poco 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
fuente
2
Esto funcionó perfectamente para mí. Debido a un error con clone()y textarea's, necesitaba una solución no clonada, y esto fue perfecto.
Shpigford el
55
+1 para usar nativo outerHTMLdonde esté disponible, ya que es compatible con Chrome además de Internet Explorer.
Andy E
99
alerta de if (! ('externalHTML' en $ t [0])) ('maldita sea, actualiza tu navegador');
psycho brm
19

Para ser verdaderamente jQuery-esque, es posible que desee outerHTML()ser un getter y un setter y que su comportamiento sea lo más similar html()posible:

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

Demostración de trabajo: http://jsfiddle.net/AndyE/WLKAa/

Esto nos permite pasar un argumento a outerHTML, que puede ser

  • una función cancelable function (index, oldOuterHTML) { }- donde el valor de retorno se convertirá en el nuevo HTML para el elemento (a menos que falsese devuelva).
  • una cadena, que se establecerá en lugar del HTML de cada elemento.

Para obtener más información, consulte los documentos de jQuery para html().

Andy E
fuente
Esto debería agregarse a jQuery core para que las personas no necesiten pensar en ello. Mi única pregunta es si wrap () / unwrap () es probable que tenga un rendimiento mejor o peor que clone ().
IMSoP
1
IMSoP: Generalmente, el ajuste / desenvoltura será más rápido porque el clon tiene que copiar todos los elementos secundarios y atributos del elemento. wrap () solo crea un único elemento, y unwrap () lo destruye, todos los demás elementos simplemente se mueven, lo cual es una operación bastante rápida la mayor parte del tiempo.
Andy E
16

También puede usar get (recuperar los elementos DOM que coinciden con el objeto jQuery).

p.ej:

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

Como método de extensión:

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

O

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

Opción múltiple y devolver el html externo de todos los elementos coincidentes.

$('input').outerHTML()

regreso:

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

Para crear un complemento jQuery COMPLETO como .outerHTML, agregue el siguiente script a cualquier archivo js e incluya después de jQuery en su encabezado:

actualización ¡La nueva versión tiene un mejor control y un servicio más amigable con 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);

¡Esto le permitirá no solo obtener el HTML externo de un elemento, sino incluso obtener una matriz de retorno de varios elementos a la vez! y se puede usar en ambos estilos estándar de jQuery como tales:

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

Para elementos múltiples

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

Ejemplos de fragmentos:

SpYk3HH
fuente
9

también puedes hacerlo de esta manera

document.getElementById(id).outerHTML

donde id es el id del elemento que estás buscando

Andy
fuente
44
$("#" + id).attr("id")Es increíblemente redundante. Si ya tiene la identificación en una variable, ¿por qué está usando un selector jquery para extraer el elemento del dom y luego consultar su atributo ID?
Sam Dufel
7

Usé la solución de Jessica (que fue editada por Josh) para hacer que externalHTML funcionara en Firefox. Sin embargo, el problema es que mi código se estaba rompiendo porque su solución envolvió el elemento en un DIV. Agregar una línea más de código resolvió ese problema.

El siguiente código le proporciona el HTML externo dejando el árbol DOM sin cambios.

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

Y úselo así: $ ("# myDiv"). ExternalHTML ();

¡Espero que alguien lo encuentre útil!

Arpan Dhandhania
fuente
1
Simplemente use .clone como @mindplay sugiere en su comentario, es más fácil
Yarin
4

Si el escenario agrega una nueva fila dinámicamente, puede usar esto:

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

.myrowes el nombre de clase de la <tr>. Hace una copia de la última fila y la inserta como una última última fila. Esto también funciona en IE7 , mientras que el [0].outerHTMLmétodo no permite asignaciones en ie7

Stefan Bookholt
fuente
3

node.cloneNode () difícilmente parece un hack. Puede clonar el nodo y agregarlo a cualquier elemento padre deseado, y también manipularlo manipulando propiedades individuales, en lugar de tener que, por ejemplo, ejecutar expresiones regulares en él o agregarlo al DOM, y luego manipularlo después.

Dicho esto, también puede iterar sobre los atributos del elemento para construir una representación de cadena HTML del mismo. Parece probable que así es como se implementaría cualquier función externalHTML si jQuery añadiera una.

Ben Regenspan
fuente
3

He usado la solución de Volomike actualizada por Jessica. Solo agregué un cheque para ver si el elemento existe, y lo volví en blanco en caso de que no exista.

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

Por supuesto, úsalo como:

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

Puede encontrar una buena opción .outerHTML () aquí https://github.com/darlesson/jquery-outerhtml .

A diferencia de .html () que solo devuelve el contenido HTML del elemento, esta versión de .outerHTML () devuelve el elemento seleccionado y su contenido HTML o lo reemplaza como método .replaceWith () pero con la diferencia que permite que el HTML reemplazado sea heredado por El encadenamiento.

También se pueden ver ejemplos en la URL anterior.

Darlesson
fuente
2

Tenga en cuenta que la solución de Josh solo funciona para un único elemento.

Podría decirse que HTML "externo" solo tiene sentido cuando tiene un solo elemento, pero hay situaciones en las que tiene sentido tomar una lista de elementos HTML y convertirlos en marcas.

Ampliando la solución de Josh, este manejará múltiples 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);

Editar: otro problema con la solución de Josh solucionado, ver comentario arriba.

mindplay.dk
fuente
1
La mayoría de los métodos "getter" de jQuery devuelven datos solo para el primer elemento, por lo que tendría más sentido hacer coincidir este comportamiento.
Andy E
Creo que dije claramente por qué funciona de esta manera? Sería un código feo / complicado cuando tienes una lista de elementos; si por alguna razón quieres el marcado solo para el primer elemento, solo usa: primero en tu selector.
mindplay.dk
Claro, al igual que podría usar el mapa con la solución de todos los demás para obtener el HTML de múltiples elementos. Todo lo que estaba diciendo es que es más consistente hacer coincidir el comportamiento de los métodos estándar de jQuery.
Andy E
2

He hecho esta prueba simple con externalHTML como solución de tokimon (sin clon), y externalHTML2 como solución de 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");

y el resultado en mi navegador de cromo (Versión 20.0.1132.57 (0)) fue

externalHTML: 81ms
externalHTML2: 439ms

pero si usamos la solución de tokimon sin la función externa externa HTML (que ahora es compatible con casi todos los navegadores)

obtenemos

externalHTML: 594ms
externalHTML2: 332ms

y habrá más bucles y elementos en ejemplos del mundo real, por lo que la combinación perfecta sería

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

por lo que el método de clonación es realmente más rápido que el método de ajuste / desempaquetado
(jquery 1.7.2)

Petardo
fuente
2

Aquí hay un plugin externalHTML muy optimizado para jquery: ( http://jsperf.com/outerhtml-vs-jquery-clone-hack/5 => los otros 2 fragmentos de código rápido no son compatibles con algunos 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 => No estoy de acuerdo contigo. outsideHMTL no necesita un captador Y un definidor: jQuery ya nos da 'replaceWith' ...

@mindplay => ¿Por qué te unes a todos los HTML externos? jquery.html devuelve solo el contenido HTML del PRIMER elemento.

(Lo siento, no tengo suficiente reputación para escribir comentarios)

gtournie
fuente
2

Corto y dulce.

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

o evento más dulce con la ayuda de las funciones de flecha

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

o sin jQuery en absoluto

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

o si no te gusta este enfoque, verifica que

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

Esto es bastante simple con JavaScript vainilla ...

document.querySelector('#selector')
Acebo
fuente
1

Esto es ideal para cambiar elementos en el dom, pero NO funciona, es decir, al pasar una cadena html a jquery de esta manera:

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

Después de alguna manipulación, he creado una función que permite que lo anterior funcione, es decir, para cadenas html:

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

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

evandrix
fuente
0

Encontré esto mientras buscaba una respuesta a mi problema, que era que estaba tratando de eliminar una fila de la tabla y luego volver a agregarla en la parte inferior de la tabla (porque estaba creando dinámicamente filas de datos pero quería mostrar un 'Agregar nuevo Registro 'tipo fila en la parte inferior).

Tuve el mismo problema, ya que estaba devolviendo el innerHtml, por lo que me faltaban las etiquetas TR, que contenían la ID de esa fila y significaban que era imposible repetir el procedimiento.

La respuesta que encontré fue que la remove()función jquery en realidad devuelve el elemento, que elimina, como un objeto. Entonces, para eliminar y volver a agregar una fila, era tan simple como esto ...

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

Si no está eliminando el objeto pero desea copiarlo en otro lugar, use la clone()función en su lugar.

sospechoso
fuente
0

Complemento jQuery como abreviatura para obtener directamente el elemento HTML completo:

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

Y úsalo así: $(".element").outerHTML();

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

Donde 'x' es el número de nodo, comenzando con 0 como el primero, debe obtener el nodo correcto que desea, si está intentando obtener uno específico. Sin embargo, si tiene nodos secundarios, realmente debería poner una ID en el que desea, sin embargo, para centrarse en ese. Usar esa metodología y no 'x' funcionó bien para mí.

vapcguy
fuente
1
Las personas que votan en contra, ¿quieren dejar un comentario? Estoy haciendo que el código suba al PADRE, luego obtenga el HTML de los contenidos, no solo haciendo un .html()elemento en el elemento dado. ESTO FUNCIONA y me gustaría una explicación de por qué no funciona.
vapcguy
-4

Solución simple.

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

Quizás no entiendo su pregunta correctamente, pero esto obtendrá el html del elemento padre del elemento seleccionado.

¿Es eso lo que buscas?

entintado
fuente
25
En realidad, no, porque si ese padre tiene otros hijos, también obtendrá ese html.
David V.
1
...lo que dijo. Estoy buscando el elemento en sí, no él y todos los demás hijos de sus padres. ¿Cómo obtuvo esto dos votos?
Ryan