comment changer un type d'élément en utilisant jquery


Réponses:


137

Voici une façon de le faire avec jQuery:

var attrs = { };

$.each($("b")[0].attributes, function(idx, attr) {
    attrs[attr.nodeName] = attr.nodeValue;
});


$("b").replaceWith(function () {
    return $("<h1 />", attrs).append($(this).contents());
});

Exemple: http://jsfiddle.net/yapHk/

Mise à jour , voici un plugin:

(function($) {
    $.fn.changeElementType = function(newType) {
        var attrs = {};

        $.each(this[0].attributes, function(idx, attr) {
            attrs[attr.nodeName] = attr.nodeValue;
        });

        this.replaceWith(function() {
            return $("<" + newType + "/>", attrs).append($(this).contents());
        });
    };
})(jQuery);

Exemple: http://jsfiddle.net/mmNNJ/


2
@FelixKling: Merci, ça childrenn'a pas marché mais ça l'a contentsfait.
Andrew Whitaker

1
@Andrew Whitaker WOW !!! vous êtes doué! Donc, juste pour être sûr que j'utilise b.class ou b.xyzxterms (xyzxterms étant le nom de la classe)
bammab

5
@AndrewWhitaker: Si je ne me trompe pas, dans votre plugin, les attributs du premier élément correspondant seront appliqués à tous les éléments correspondants. Ce n'est pas nécessairement ce que nous voulons. Une erreur est également déclenchée lorsqu'il n'y a pas d'élément correspondant dans l'ensemble. Voici une version modifiée de votre plugin qui garde ses propres attributs pour chaque élément correspondant et ne déclenche pas d'erreur sur un ensemble vide: gist.github.com/2934516
Etienne

2
Ça fonctionne super bien! Sauf que lorsque le sélecteur ne parvient pas à trouver un élément correspondant, il envoie un message d'erreur à la console car ce [0] n'est pas défini. L'ajout d'une condition le corrige: if (this.length! = 0) {...
ciuncan

1
@ciuncan: Merci pour les commentaires! Il devrait vraiment être enveloppé dans un .eachbloc comme le montre une réponse ci-dessous.
Andrew Whitaker

14

Pas sûr de jQuery. Avec JavaScript brut, vous pouvez faire:

var new_element = document.createElement('h1'),
    old_attributes = element.attributes,
    new_attributes = new_element.attributes;

// copy attributes
for(var i = 0, len = old_attributes.length; i < len; i++) {
    new_attributes.setNamedItem(old_attributes.item(i).cloneNode());
}

// copy child nodes
do {
    new_element.appendChild(element.firstChild);
} 
while(element.firstChild);

// replace element
element.parentNode.replaceChild(new_element, element);

DEMO

Je ne sais pas à quel point cela est compatible avec tous les navigateurs.

Une variation pourrait être:

for(var i = 0, len = old_attributes.length; i < len; i++) {
    new_element.setAttribute(old_attributes[i].name, old_attributes[i].value);
}

Pour plus d'informations, voir Node.attributes [MDN] .


Les performances de votre code sont meilleures que le "pur jQuery" (par exemple le code d'Andrew), mais vous avez un petit problème avec les balises internes, voyez l'italique dans cet exemple avec votre code et l' exemple de référence .
Peter Krauss

Si vous corrigez, un "plugin jquery idéal" peut être défini, en appelant votre fonction par le jquery-plugin-template.
Peter Krauss

Fixé. Le problème était qu'après la copie sur le premier enfant, il n'avait plus de frère suivant, donc while(child = child.nextSibling)échoué. Merci!
Felix Kling

9

@jakov et @Andrew Whitaker

Voici une amélioration supplémentaire pour qu'il puisse gérer plusieurs éléments à la fois.

$.fn.changeElementType = function(newType) {
    var newElements = [];

    $(this).each(function() {
        var attrs = {};

        $.each(this.attributes, function(idx, attr) {
            attrs[attr.nodeName] = attr.nodeValue;
        });

        var newElement = $("<" + newType + "/>", attrs).append($(this).contents());

        $(this).replaceWith(newElement);

        newElements.push(newElement);
    });

    return $(newElements);
};

3

La réponse de @ Jazzbo a renvoyé un objet jQuery contenant un tableau d'objets jQuery, qui n'étaient pas chaînables. Je l'ai changé pour qu'il renvoie un objet plus similaire à ce que $ .each aurait renvoyé:

    $.fn.changeElementType = function (newType) {
        var newElements,
            attrs,
            newElement;

        this.each(function () {
            attrs = {};

            $.each(this.attributes, function () {
                attrs[this.nodeName] = this.nodeValue;
            });

            newElement = $("<" + newType + "/>", attrs).append($(this).contents());

            $(this).replaceWith(newElement);

            if (!newElements) {
                newElements = newElement;
            } else {
                $.merge(newElements, newElement);
            }
        });

        return $(newElements);
    };

(J'ai également nettoyé le code pour qu'il passe jslint.)


Cela semble être la meilleure option. La seule chose que je ne comprends pas, c'est pourquoi vous avez déplacé la déclaration var pour attrs hors de this.each (). Cela fonctionne bien avec cela laissé là: jsfiddle.net/9c0k82sr/1
Jacob C. dit Réintégrer Monica

J'ai regroupé les vars à cause de jslint: "(J'ai également fait du nettoyage de code pour qu'il passe jslint.)". L'idée derrière cela est de rendre le code plus rapide, je pense (ne pas avoir à redéclarer les variables dans chaqueeach boucle).
fiskhandlarn

2

La seule façon dont je peux penser est de tout copier manuellement: exemple jsfiddle

HTML

<b class="xyzxterms" style="cursor: default; ">bryant keil bio</b>

Jquery / Javascript

$(document).ready(function() {
    var me = $("b");
    var newMe = $("<h1>");
    for(var i=0; i<me[0].attributes.length; i++) {
        var myAttr = me[0].attributes[i].nodeName;
        var myAttrVal = me[0].attributes[i].nodeValue;
        newMe.attr(myAttr, myAttrVal);
    }
    newMe.html(me.html());
    me.replaceWith(newMe);
});

2

@Andrew Whitaker: Je propose ce changement:

$.fn.changeElementType = function(newType) {
    var attrs = {};

    $.each(this[0].attributes, function(idx, attr) {
        attrs[attr.nodeName] = attr.nodeValue;
    });

    var newelement = $("<" + newType + "/>", attrs).append($(this).contents());
    this.replaceWith(newelement);
    return newelement;
};

Ensuite, vous pouvez faire des choses comme: $('<div>blah</div>').changeElementType('pre').addClass('myclass');


2

J'aime l'idée de @AndrewWhitaker et d'autres, d'utiliser un plugin jQuery - pour ajouter le changeElementType() méthode. Mais un plugin est comme une boîte noire, peu importe le code, s'il est petit et fonctionne bien ... Donc, les performances sont requises, et sont plus importantes que le code.

"Pure javascript" a de meilleures performances que jQuery: je pense que le code de @ FelixKling a de meilleures performances que celui de @ AndrewWhitaker et d'autres.


Voici un code "pur Javavascript" (et "pur DOM"), encapsulé dans un plugin jQuery :

 (function($) {  // @FelixKling's code
    $.fn.changeElementType = function(newType) {
      for (var k=0;k<this.length; k++) {
       var e = this[k];
       var new_element = document.createElement(newType),
        old_attributes = e.attributes,
        new_attributes = new_element.attributes,
        child = e.firstChild;
       for(var i = 0, len = old_attributes.length; i < len; i++) {
        new_attributes.setNamedItem(old_attributes.item(i).cloneNode());
       }
       do {
        new_element.appendChild(e.firstChild);
       }
       while(e.firstChild);
       e.parentNode.replaceChild(new_element, e);
      }
      return this; // for chain... $(this)?  not working with multiple 
    }
 })(jQuery);

2

Voici une méthode que j'utilise pour remplacer les balises html dans jquery:

// Iterate over each element and replace the tag while maintaining attributes
$('b.xyzxterms').each(function() {

  // Create a new element and assign it attributes from the current element
  var NewElement = $("<h1 />");
  $.each(this.attributes, function(i, attrib){
    $(NewElement).attr(attrib.name, attrib.value);
  });

  // Replace the current element with the new one and carry over the contents
  $(this).replaceWith(function () {
    return $(NewElement).append($(this).contents());
  });

});

2

Avec jQuery sans itération sur les attributs:

La replaceElemméthode accepte ci - dessous old Tag, new Taget contextet exécute avec succès le remplacement:


replaceElem('h2', 'h1', '#test');

function replaceElem(oldElem, newElem, ctx) {
  oldElems = $(oldElem, ctx);
  //
  $.each(oldElems, function(idx, el) {
    var outerHTML, newOuterHTML, regexOpeningTag, regexClosingTag, tagName;
    // create RegExp dynamically for opening and closing tags
    tagName = $(el).get(0).tagName;
    regexOpeningTag = new RegExp('^<' + tagName, 'i'); 
    regexClosingTag = new RegExp(tagName + '>$', 'i');
    // fetch the outer elem with vanilla JS,
    outerHTML = el.outerHTML;
    // start replacing opening tag
    newOuterHTML = outerHTML.replace(regexOpeningTag, '<' + newElem);
    // continue replacing closing tag
    newOuterHTML = newOuterHTML.replace(regexClosingTag, newElem + '>');
    // replace the old elem with the new elem-string
    $(el).replaceWith(newOuterHTML);
  });

}
h1 {
  color: white;
  background-color: blue;
  position: relative;
}

h1:before {
  content: 'this is h1';
  position: absolute;
  top: 0;
  left: 50%;
  font-size: 5px;
  background-color: black;
  color: yellow;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>


<div id="test">
  <h2>Foo</h2>
  <h2>Bar</h2>
</div>

Bonne chance...


1
J'aime ta réponse! Pourquoi? Parce que TOUTES les autres réponses échoueront en essayant de faire quelque chose de simple comme convertir une ancre en étiquette. Cela dit, veuillez considérer les correctifs / révisions suivants de votre réponse: A). Votre code ne fonctionnera pas avec les sélecteurs. B) Votre code doit exécuter une expression régulière insensible à la casse. Cela dit, voici mes suggestions de correctifs: regexOpeningTag = new RegExp ('^ <' + $ (el) .get (0) .tagName, 'i'); regexClosingTag = new RegExp ($ (el) .get (0) .tagName + '> $', 'i');
zax

Le remplacement du HTML brut comme celui-ci vous fera également perdre tous les écouteurs d'événements attachés aux objets.
José Yánez

1

Solution Javascript

Copiez les attributs de l'ancien élément dans le nouvel élément

const $oldElem = document.querySelector('.old')
const $newElem = document.createElement('div')

Array.from($oldElem.attributes).map(a => {
  $newElem.setAttribute(a.name, a.value)
})

Remplacez l'ancien élément par le nouvel élément

$oldElem.parentNode.replaceChild($newElem, $oldElem)

mapcrée un nouveau tableau inutilisé, il pourrait être remplacé par forEach.
Orkhan Alikhanov

1

Voici ma version. Il s'agit essentiellement de la version de @ fiskhandlarn, mais au lieu de construire un nouvel objet jQuery, il écrase simplement les anciens éléments par ceux nouvellement créés, donc aucune fusion n'est nécessaire.
Démo: http://jsfiddle.net/0qa7wL1b/

$.fn.changeElementType = function( newType ){
  var $this = this;

  this.each( function( index ){

    var atts = {};
    $.each( this.attributes, function(){
      atts[ this.name ] = this.value;
    });

    var $old = $(this);
    var $new = $('<'+ newType +'/>', atts ).append( $old.contents() );
    $old.replaceWith( $new );

    $this[ index ] = $new[0];
  });

  return this;
};
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.