bagaimana mengubah tipe elemen menggunakan jquery


Jawaban:


137

Inilah salah satu cara Anda dapat melakukannya dengan jQuery:

var attrs = { };

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


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

Contoh: http://jsfiddle.net/yapHk/

Perbarui , inilah pluginnya:

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

Contoh: http://jsfiddle.net/mmNNJ/


2
@FelixKling: Terima kasih, childrentidak berhasil tetapi contentsberhasil.
Andrew Whitaker

1
@Andrew Whitaker WOW !!! kamu baik! Jadi untuk memastikan saya menggunakan b.class atau b.xyzxterms (xyzxterms adalah nama kelasnya)
bammab

5
@AndrewWhitaker: Jika saya tidak salah, di plugin Anda, atribut elemen pertama yang cocok akan diterapkan ke semua elemen yang cocok. Itu belum tentu yang kita inginkan. Juga kesalahan dimunculkan ketika tidak ada elemen yang cocok di set. Berikut adalah versi modifikasi dari plugin Anda yang menyimpan atribut sendiri untuk setiap elemen yang cocok dan tidak memicu kesalahan pada set kosong: gist.github.com/2934516
Etienne

2
Ini bekerja seperti pesona! Kecuali bahwa ketika pemilih gagal menemukan elemen yang cocok, itu melontarkan pesan kesalahan ke konsol karena [0] ini adalah atribut pengaksesan tidak terdefinisi rusak. Menambahkan kondisi akan memperbaikinya: if (this.length! = 0) {...
ciuncan

1
@ciuncan: Terima kasih atas tanggapannya! Itu benar-benar harus dibungkus dalam .eachblok seperti jawaban di bawah ini juga menunjukkan.
Andrew Whitaker

14

Tidak yakin tentang jQuery. Dengan JavaScript biasa, Anda dapat melakukan:

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

Tidak yakin seberapa kompatibel lintas-browser ini.

Variasinya bisa berupa:

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

Untuk informasi lebih lanjut lihat Node.attributes [MDN] .


Kinerja kode Anda lebih baik daripada "jQuery murni" (mis. Kode Andrew), tetapi memiliki sedikit masalah dengan tag bagian dalam, lihat miring pada contoh ini dengan kode Anda dan contoh referensi .
Peter Krauss

Jika Anda benar, "plugin jquery ideal" dapat didefinisikan, memanggil fungsi Anda dengan jquery-plugin-template.
Peter Krauss

Tetap. Masalahnya adalah setelah menyalin anak pertama, ia tidak memiliki saudara berikutnya lagi, jadi while(child = child.nextSibling)gagal. Terima kasih!
Felix Kling

9

@jakov dan @Andrew Whitaker

Berikut adalah penyempurnaan lebih lanjut sehingga bisa menangani banyak elemen sekaligus.

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

Jawaban @ Jazzbo mengembalikan objek jQuery yang berisi larik objek jQuery, yang tidak dapat dirantai. Saya telah mengubahnya sehingga mengembalikan objek yang lebih mirip dengan apa yang akan dikembalikan $ .each:

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

(Juga melakukan beberapa pembersihan kode sehingga melewati jslint.)


Ini sepertinya pilihan terbaik. Satu-satunya hal yang saya tidak mengerti adalah mengapa Anda memindahkan deklarasi var untuk attrs dari this.each (). Ini berfungsi dengan baik dengan meninggalkannya di sana: jsfiddle.net/9c0k82sr/1
Jacob C. mengatakan Reinstate Monica

Saya mengelompokkan vars karena jslint: "(Juga melakukan pembersihan kode sehingga lolos jslint.)". Ide di balik itu adalah untuk membuat kode lebih cepat, saya pikir (tidak harus mendeklarasikan ulang vars dalam setiap eachloop).
fiskhandlarn

2

Satu-satunya cara yang dapat saya pikirkan adalah menyalin semuanya secara manual: contoh 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: Saya mengusulkan perubahan ini:

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

Kemudian Anda dapat melakukan hal-hal seperti: $('<div>blah</div>').changeElementType('pre').addClass('myclass');


2

Saya suka ide @AndrewWhitaker dan lainnya, menggunakan plugin jQuery - untuk menambahkan changeElementType()metode. Tetapi sebuah plugin itu seperti kotak hitam, tanpa masalah tentang kodenya, jika itu litle dan berfungsi dengan baik ... Jadi, kinerja diperlukan, dan yang paling penting daripada kode.

"Pure javascript" memiliki kinerja yang lebih baik daripada jQuery: Saya pikir kode @ FelixKling memiliki kinerja yang lebih baik daripada @ AndrewWhitaker dan lainnya.


Berikut kode "Javavascript murni" (dan "DOM murni"), yang dikemas menjadi 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

Berikut adalah metode yang saya gunakan untuk mengganti tag html di 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

Dengan jQuery tanpa mengulang atribut:

The replaceElemmetode di bawah ini menerima old Tag, new Tagdan contextdan mengeksekusi penggantian berhasil:


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>

Semoga berhasil...


1
Saya suka jawaban Anda! Mengapa? Karena SEMUA jawaban lain akan gagal dalam mencoba melakukan sesuatu yang sederhana seperti mengubah jangkar menjadi label. Karena itu, harap pertimbangkan perbaikan / revisi berikut untuk jawaban Anda: A). Kode Anda tidak akan berfungsi dengan pemilih. B) Kode Anda perlu menjalankan regex case insensitive. Karena itu, berikut adalah perbaikan yang saya sarankan: regexOpeningTag = new RegExp ('^ <' + $ (el) .get (0) .tagName, 'i'); regexClosingTag = RegExp baru ($ (el) .get (0) .tagName + '> $', 'i');
zax

Mengganti HTML biasa seperti ini juga akan membuat Anda kehilangan semua event listener yang dilampirkan ke objek.
José Yánez

1

Solusi Javascript

Salin atribut elemen lama ke elemen baru

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

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

Ganti elemen lama dengan elemen baru

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

mapmembuat array baru yang tidak digunakan, itu bisa diganti dengan forEach.
Orkhan Alikhanov

1

Ini versi saya. Ini pada dasarnya adalah versi @ fiskhandlarn, tetapi alih-alih membuat objek jQuery baru, itu hanya menimpa elemen lama dengan yang baru dibuat, jadi tidak perlu penggabungan.
Demo: 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;
};
Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.