jquery kullanarak bir öğe türü nasıl değiştirilir


Yanıtlar:


137

İşte jQuery ile yapmanın bir yolu:

var attrs = { };

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


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

Örnek: http://jsfiddle.net/yapHk/

Güncelleme , işte bir eklenti:

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

Örnek: http://jsfiddle.net/mmNNJ/


2
@FelixKling: Teşekkürler, childrenişe yaramadı ama contentsyaptı.
Andrew Whitaker

1
@Andrew Whitaker WOW !!! İyisin! Bu yüzden b.class veya b.xyzxterms (sınıfın adı xyzxterms) kullandığımdan emin olmak için
bammab

5
@AndrewWhitaker: Yanılmıyorsam, eklentinizde, ilk eşleşen öğenin nitelikleri tüm eşleşen öğelere uygulanacaktır. Bizim istediğimiz bu olmak zorunda değil. Ayrıca kümede eşleşen öğe olmadığında da bir hata oluşur. İşte eklentinizin, eşleşen her öğe için kendi özniteliklerini tutan ve boş kümede bir hatayı tetiklemeyen değiştirilmiş bir sürümü: gist.github.com/2934516
Etienne

2
Bu bir cazibe gibi çalışıyor! Seçici herhangi bir eşleşen elemanı bulamadığında konsola bir hata mesajı atar çünkü bu [0] tanımsız erişim özniteliklerine son verir. Bir koşul eklemek sorunu düzeltir: if (this.length! = 0) {...
ciuncan

1
@ciuncan: Geri bildirim için teşekkürler! .eachAşağıdaki yanıtın da gösterdiği gibi , gerçekten bir bloğa sarılmalıdır .
Andrew Whitaker

14

JQuery hakkında emin değilim. Düz JavaScript ile şunları yapabilirsiniz:

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

Ancak bunun tarayıcılar arası ne kadar uyumlu olduğundan emin değilim.

Bir varyasyon şunlar olabilir:

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

Daha fazla bilgi için Node.attributes [MDN] konusuna bakın .


Kodunuzun performansı "saf jQuery" den (örn. Andrew'un kodu) daha iyidir, ancak iç etiketlerle ilgili küçük bir sorun var, bu örnekte kodunuz ve referans örneğiyle italik bakın .
Peter Krauss

Eğer düzeltirseniz, bir "eklentisi İdeal jquery" jquery-eklenti-şablona göre işlevini çağırarak, tanımlanabilir.
Peter Krauss

Sabit. Sorun şu ki, ilk çocuk üzerine kopyalandıktan sonra, artık bir sonraki kardeşi kalmadı, bu yüzden while(child = child.nextSibling)başarısız oldu. Teşekkürler!
Felix Kling

9

@jakov ve @Andrew Whitaker

Burada, aynı anda birden fazla öğeyi işleyebilmesi için daha fazla iyileştirme var.

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

@ Jazzbo'nun yanıtı, zincirlenebilir olmayan bir dizi jQuery nesnesi içeren bir jQuery nesnesi döndürdü. Bunu, $ .each'in döndürdüğüne daha benzer bir nesne döndürmesi için değiştirdim:

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

(Ayrıca jslint'i geçmesi için bazı kod temizleme yaptı.)


Bu en güzel seçenek gibi görünüyor. Anlamadığım tek şey, attr'ler için var bildirimini neden this.each () öğesinin dışına taşıdığınızdır. Orada bırakıldığında gayet iyi çalışıyor: jsfiddle.net/9c0k82sr/1
Jacob C.,

Değişkenleri jslint nedeniyle gruplandırdım: "(Ayrıca jslint'i geçmesi için bazı kod temizleme işlemleri yaptım.)". Bunun arkasındaki fikir, bence kodu daha hızlı yapmaktır (her eachdöngüde değişkenleri yeniden bildirmek zorunda kalmadan ).
fiskhandlarn

2

Aklıma gelen tek yol, her şeyi manuel olarak kopyalamak: örnek 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: Bu değişikliği öneriyorum:

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

O zaman aşağıdaki gibi şeyler yapabilirsiniz: $('<div>blah</div>').changeElementType('pre').addClass('myclass');


2

changeElementType()Yöntemi eklemek için @AndrewWhitaker ve diğerlerinin bir jQuery eklentisi kullanma fikrini seviyorum . Ancak bir eklenti bir kara kutu gibidir, kodla ilgili bir konu yoktur, eğer küçükse ve iyi çalışıyorsa ... Bu nedenle, performans gereklidir ve koddan en önemlisidir.

"Saf javascript" sahip iyi performans jQuery daha: Ben FelixKling koduna @ AndrewWhitaker en ve diğerleri @ daha iyi bir performansa sahip olduğunu düşünüyorum.


Burada, bir jQuery eklentisine kapsüllenmiş "saf Javavascript" (ve "saf DOM") kodu :

 (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

İşte jquery'de html etiketlerini değiştirmek için kullandığım bir yöntem:

// 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

İle jQuery olmaksızın özelliklerini yineleme:

replaceElemYöntem aşağıda kabul old Tag, new Tagve contextve başarılı bir şekilde yerine yürütür:


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>

İyi şanslar...


1
Cevabını beğendim! Neden? Çünkü diğer yanıtların TÜMÜ, bir çapayı bir etikete dönüştürmek gibi basit bir şey yapma girişiminde başarısız olacaktır. Bununla birlikte, lütfen cevabınız için aşağıdaki düzeltmeleri / revizyonları göz önünde bulundurun: A). Kodunuz seçicilerle çalışmayacaktır. B) Kodunuzun büyük / küçük harfe duyarlı olmayan normal ifadeler gerçekleştirmesi gerekir. Bununla birlikte, işte benim önerdiğim düzeltmeler: regexOpeningTag = new RegExp ('^ <' + $ (el) .get (0) .tagName, 'i'); regexClosingTag = new RegExp ($ (el) .get (0) .tagName + '> $', 'i');
zax

Düz HTML'yi bu şekilde değiştirmek, nesnelere eklenmiş herhangi bir olay dinleyicisini de kaybetmenize neden olur.
José Yánez

1

Javascript çözümü

Eski elemanın niteliklerini yeni elemana kopyalayın

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

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

Eski elemanı yeni elemanla değiştirin

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

mapkullanılmayan yeni bir dizi yaratırsa, ile değiştirilebilir forEach.
Orkhan Alikhanov

1

İşte benim versiyonum. Temelde @ fiskhandlarn'ın sürümüdür, ancak yeni bir jQuery nesnesi oluşturmak yerine, yeni oluşturulanların eski öğelerin üzerine yazar, dolayısıyla birleştirme gerekmez.
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;
};
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.