bagaimana mengubah tipe elemen menggunakan jquery

104

Saya memiliki kode berikut

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

Bagaimana cara mengganti btag ke h1tag tetapi tetap mempertahankan semua atribut dan informasi lainnya?

bammab
sumber
@beanland: Ini tidak menyimpan atribut.
Felix Kling

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/

Andrew Whitaker
sumber
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] .

Felix Kling
sumber
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);
};
Jazzbo
sumber
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.)

fiskhandlarn
sumber
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);
});
kasdega
sumber
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');

jakov
sumber
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);
Peter Krauss
sumber
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());
  });

});
Seth McCauley
sumber
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...

Akash
sumber
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)
svnm
sumber
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;
};
biziclop
sumber