วิธีเปลี่ยนประเภทองค์ประกอบโดยใช้ jquery


105

ฉันมีรหัสต่อไปนี้

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

ฉันจะเปลี่ยนbแท็กเป็นh1แท็กได้อย่างไร แต่เก็บแอตทริบิวต์และข้อมูลอื่น ๆ ไว้ทั้งหมด



@beanland: สิ่งนี้ไม่ได้เก็บคุณลักษณะไว้
Felix Kling

คำตอบ:


138

นี่เป็นวิธีหนึ่งที่คุณสามารถทำได้ด้วย jQuery:

var attrs = { };

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


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

ตัวอย่าง: http://jsfiddle.net/yapHk/

อัปเดตนี่คือปลั๊กอิน:

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

ตัวอย่าง: http://jsfiddle.net/mmNNJ/


2
@FelixKling: ขอบคุณchildrenไม่ได้ผล แต่contentsทำได้
Andrew Whitaker

1
@ แอนดรูว์วิทเทเกอร์ว้าว !!! สบายดีนะ! ดังนั้นเพื่อให้แน่ใจว่าฉันใช้ b.class หรือ b.xyzxterms (xyzxterms เป็นชื่อของคลาส)
bammab

5
@AndrewWhitaker: ถ้าฉันไม่ผิดในปลั๊กอินของคุณแอตทริบิวต์ขององค์ประกอบแรกที่ตรงกันจะถูกนำไปใช้กับองค์ประกอบที่ตรงกันทั้งหมด ไม่จำเป็นต้องเป็นอย่างที่เราต้องการ นอกจากนี้ยังมีข้อผิดพลาดเพิ่มขึ้นเมื่อไม่มีองค์ประกอบที่ตรงกันในชุด นี่คือปลั๊กอินเวอร์ชันที่แก้ไขแล้วซึ่งจะเก็บแอตทริบิวต์ของตัวเองสำหรับแต่ละองค์ประกอบที่ตรงกันและไม่ทำให้เกิดข้อผิดพลาดในชุดว่าง: gist.github.com/2934516
Etienne

2
งานนี้เหมือนมีเสน่ห์! ยกเว้นว่าเมื่อตัวเลือกไม่พบองค์ประกอบที่ตรงกันก็จะส่งข้อความแสดงข้อผิดพลาดไปยังคอนโซลเนื่องจาก [0] นี้ไม่ได้กำหนดแอตทริบิวต์การเข้าถึงที่แตก การเพิ่มเงื่อนไขจะช่วยแก้ไขได้: if (this.length! = 0) {...
ciuncan

1
@ciuncan: ขอบคุณสำหรับคำติชม! มันควรจะอยู่ใน.eachบล็อคเหมือนที่คำตอบด้านล่างแสดงด้วย
Andrew Whitaker

14

ไม่แน่ใจเกี่ยวกับ jQuery ด้วย JavaScript ธรรมดาคุณสามารถทำได้:

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

การสาธิต

ไม่แน่ใจว่าสิ่งนี้เข้ากันได้กับข้ามเบราว์เซอร์อย่างไร

รูปแบบอาจเป็น:

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

สำหรับข้อมูลเพิ่มเติมโปรดดูที่[MDN]Node.attributes


ประสิทธิภาพการทำงานของรหัสของคุณจะดีกว่า jQuery "บริสุทธิ์" (อดีต. รหัสแอนดรู) แต่มีปัญหาเล็ก ๆ น้อย ๆ ที่มีแท็กภายในดูตัวเอียงในตัวอย่างนี้มีรหัสของคุณและอ้างอิงตัวอย่างเช่น
Peter Krauss

หากคุณแก้ไขคุณสามารถกำหนด"ปลั๊กอิน jquery ในอุดมคติ"ได้โดยเรียกฟังก์ชันของคุณโดยใช้ jquery-plugin-template
Peter Krauss

แก้ไขแล้ว. ปัญหาคือหลังจากคัดลอกลูกคนแรกแล้วก็ไม่มีพี่น้องคนถัดไปอีกต่อไปจึงwhile(child = child.nextSibling)ล้มเหลว ขอบคุณ!
Felix Kling

9

@jakov และ @Andrew Whitaker

นี่คือการปรับปรุงเพิ่มเติมเพื่อให้สามารถจัดการหลายองค์ประกอบพร้อมกันได้

$.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 ส่งคืนอ็อบเจ็กต์ jQuery ที่มีอาร์เรย์ของอ็อบเจ็กต์ jQuery ซึ่งไม่สามารถ chainable ได้ ฉันได้เปลี่ยนแปลงเพื่อให้ส่งคืนวัตถุที่คล้ายกับที่ $. แต่ละคนจะได้คืน:

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

(ทำการล้างโค้ดบางอย่างด้วยเพื่อให้ผ่าน jslint)


ดูเหมือนจะเป็นตัวเลือกที่ดีที่สุด สิ่งเดียวที่ฉันไม่ได้รับคือสาเหตุที่คุณย้ายการประกาศ var สำหรับ attrs ออกจากสิ่งนี้แต่ละ () มันใช้งานได้ดีเมื่อทิ้งไว้ที่นั่น: jsfiddle.net/9c0k82sr/1
Jacob C. กล่าวว่า Reinstate Monica

ฉันจัดกลุ่ม vars เนื่องจาก jslint: "(ยังทำการล้างโค้ดบางอย่างเพื่อให้ผ่าน jslint)" แนวคิดเบื้องหลังคือทำให้โค้ดเร็วขึ้นฉันคิดว่า (ไม่ต้องประกาศ vars ซ้ำในแต่ละeachลูป)
fiskhandlarn

2

วิธีเดียวที่ฉันคิดได้คือการคัดลอกทุกอย่างด้วยตนเอง: ตัวอย่าง 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

@ แอนดรูว์วิเทเกอร์: ฉันเสนอการเปลี่ยนแปลงนี้:

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

จากนั้นคุณสามารถทำสิ่งต่างๆเช่น: $('<div>blah</div>').changeElementType('pre').addClass('myclass');


2

ฉันชอบความคิดของ @AndrewWhitaker และคนอื่น ๆ ในการใช้ปลั๊กอิน jQuery - เพื่อเพิ่มchangeElementType()วิธีการ แต่ปลั๊กอินก็เหมือนกล่องดำไม่มีวัสดุเกี่ยวกับโค้ดถ้ามันสว่างและใช้งานได้ดี ... ดังนั้นประสิทธิภาพจึงจำเป็นและสำคัญที่สุดกว่าโค้ด

"จาวาสคริปต์แท้" มีประสิทธิภาพที่ดีกว่า jQuery: ฉันคิดว่าโค้ดของ @FelixKling มีประสิทธิภาพที่ดีกว่าของ @ AndrewWhitaker และอื่น ๆ


รหัส "Javavascript บริสุทธิ์" (และ "pure DOM") ซึ่งรวมอยู่ในปลั๊กอิน 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

นี่คือวิธีที่ฉันใช้เพื่อแทนที่แท็ก html ใน 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

ด้วยjQuery โดยไม่ต้องทำซ้ำมากกว่าคุณลักษณะ:

replaceElemวิธีการดังต่อไปนี้ยอมรับold Tag, new Tagและcontextและดำเนินการเปลี่ยนเรียบร้อยแล้ว:


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>

โชคดี...


1
ฉันชอบคำตอบของคุณ! ทำไม? เนื่องจากคำตอบอื่น ๆ ทั้งหมดจะล้มเหลวในการพยายามทำสิ่งง่ายๆเช่นการแปลงจุดยึดเป็นป้ายกำกับ ดังกล่าวโปรดพิจารณาการแก้ไข / การแก้ไขต่อไปนี้สำหรับคำตอบของคุณ: A) รหัสของคุณใช้ไม่ได้กับตัวเลือก B) รหัสของคุณต้องใช้ regex ที่ไม่คำนึงถึงขนาดตัวพิมพ์ ที่กล่าวว่านี่คือการแก้ไขที่แนะนำของฉัน: regexOpeningTag = RegExp ใหม่ ('^ <' + $ (el) .get (0) .tagName, 'i'); regexClosingTag = RegExp ใหม่ ($ (el) .get (0) .tagName + '> $', 'i');
zax

การแทนที่ HTML ธรรมดาเช่นนี้จะทำให้คุณสูญเสียผู้ฟังเหตุการณ์ที่แนบมากับวัตถุ
José Yanez

1

โซลูชัน Javascript

คัดลอกแอตทริบิวต์ขององค์ประกอบเก่าไปยังองค์ประกอบใหม่

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

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

แทนที่องค์ประกอบเก่าด้วยองค์ประกอบใหม่

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

mapforEachสร้างอาร์เรย์ที่ไม่ได้ใช้ใหม่ก็จะถูกแทนที่ด้วย
Orkhan Alikhanov

1

นี่คือเวอร์ชันของฉัน โดยพื้นฐานแล้วเป็นเวอร์ชันของ @ fiskhandlarn แต่แทนที่จะสร้างวัตถุ jQuery ใหม่มันจะเขียนทับองค์ประกอบเก่าด้วยองค์ประกอบที่สร้างขึ้นใหม่ดังนั้นจึงไม่จำเป็นต้องมีการรวมเข้าด้วยกัน
การสาธิต: 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;
};
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.