Verwenden Sie jQuery, um ein HTML-Tag zu ändern?

130

Ist das möglich?

Beispiel:

$('a.change').click(function(){
//code to change p tag to h5 tag
});


<p>Hello!</p>
<a id="change">change</a>

Wenn Sie also auf den Änderungsanker klicken, sollte sich der <p>Hello!</p>Abschnitt (als Beispiel) in ein h5-Tag ändern, sodass Sie <h5>Hello!</h5>nach dem Klicken einen erhalten. Mir ist klar, dass Sie das p-Tag löschen und durch ein h5 ersetzen können, aber gibt es trotzdem eine Möglichkeit, ein HTML-Tag tatsächlich zu ändern?

Christopher Cooper
quelle

Antworten:

211

Sobald ein dom-Element erstellt wurde, ist das Tag meiner Meinung nach unveränderlich. Sie müssten so etwas tun:

$(this).replaceWith($('<h5>' + this.innerHTML + '</h5>'));
Mischac
quelle
2
Bitte beachten Sie meinen Kommentar unten ... Das Ändern der Dokumentstruktur zum Anwenden des Stils ist nicht der beste Ansatz.
jrista
38
Würde dies nicht irgendwelche Attribute zerstören, die sich möglicherweise auf dem Element befinden, das Sie ersetzt haben? Könnte zu unerwartetem Verhalten aufgrund gelöschter Stilattribute, Datenattribute usw. führen.
Xavi
5
"<" + el.outerHTML.replace(/(^<\w+|\w+>$)/g, "H5") + ">";Oder steckbare jQuery-Funktion: Link
Basilikum
65

Hier ist eine Erweiterung, die alles für so viele Elemente auf so viele Arten erledigt ...

Anwendungsbeispiel:

Behalten Sie vorhandene Klassen und Attribute bei:

$('div#change').replaceTag('<span>', true);

oder

Verwerfen Sie vorhandene Klassen und Attribute:

$('div#change').replaceTag('<span class=newclass>', false);

oder auch

Ersetzen Sie alle Divs durch Bereiche, kopieren Sie Klassen und Attribute und fügen Sie einen zusätzlichen Klassennamen hinzu

$('div').replaceTag($('<span>').addClass('wasDiv'), true);

Plugin Quelle:

$.extend({
    replaceTag: function (currentElem, newTagObj, keepProps) {
        var $currentElem = $(currentElem);
        var i, $newTag = $(newTagObj).clone();
        if (keepProps) {//{{{
            newTag = $newTag[0];
            newTag.className = currentElem.className;
            $.extend(newTag.classList, currentElem.classList);
            $.extend(newTag.attributes, currentElem.attributes);
        }//}}}
        $currentElem.wrapAll($newTag);
        $currentElem.contents().unwrap();
        // return node; (Error spotted by Frank van Luijn)
        return this; // Suggested by ColeLawrence
    }
});

$.fn.extend({
    replaceTag: function (newTagObj, keepProps) {
        // "return" suggested by ColeLawrence
        return this.each(function() {
            jQuery.replaceTag(this, newTagObj, keepProps);
        });
    }
});
Orwellophil
quelle
2
Jep. Und für die Aufzeichnung gibt es tatsächlich viele sehr gültige Gründe, warum Sie ein Tag ändern möchten. zB wenn Sie DIV-Tags in einem SPAN hatten, was hella nicht standardmäßig ist. Ich habe viel von dieser Funktion Gebrauch gemacht, als ich mit den strengen Standards von princexml für das PDF-Publishing gearbeitet habe.
Orwellophile
1
Sieht wirklich gut aus, verliert aber leider alle Ereignisse des ersetzten Elements. Vielleicht könnte das auch gehandhabt werden - wäre großartig!
NPC
@NPC das ist das Leben in der Großstadt. Wenn Sie Elemente ersetzen, gibt es Verluste. Ich bin sicher, es gibt jemanden da draußen, der die relevante Abfrage kennt, um die Ereignisse zu klonen :)
Orwellophile
1
@FrankvanLuijn @orwellophile das return node;sollte eigentlich so sein return this;wie in der "alten Version" des Plugins gezeigt. Dies ist im Wesentlichen für die Verkettung von Ereignissen wie$("tr:first").find("td").clone().replaceTag("li").appendTo("ul#list")
Cole Lawrence
1
Ich verstehe nicht, warum brauchst du 2 Funktionen? Benötigen Sie beides? Entschuldigung, ich bin verloren
João Pimentel Ferreira
12

Anstatt den Tag-Typ zu ändern, sollten Sie den Stil des Tags (oder vielmehr das Tag mit einer bestimmten ID) ändern. Es empfiehlt sich nicht, die Elemente Ihres Dokuments zu ändern, um stilistische Änderungen anzuwenden. Versuche dies:

$('a.change').click(function() {
    $('p#changed').css("font-weight", "bold");
});

<p id="changed">Hello!</p>
<a id="change">change</a>
jrista
quelle
3
Auch in diesem Fall sollten Sie Ihre Dokumentstruktur nicht ändern. Wenn Sie eine Eingabe als Reaktion auf das Klicken auf einen Bearbeitungsknopf anzeigen müssen, geben Sie die Eingabe ein und halten Sie die Anzeige: keine oder Sichtbarkeit: darauf versteckt. Blenden Sie das <h5> aus und zeigen Sie das <Eingang> als Reaktion auf den Klick auf die Schaltfläche an. Wenn Sie Ihre Dokumentstruktur ständig ändern, fragen Sie einfach nach einer Fülle von Stil- und Layoutproblemen.
jrista
1
Absolut. Ihr Javascript ist eingebettet oder verknüpft. Wenn Sie also Sicherheitsbedenken haben, ist Ihr Sicherheitsansatz etwas fehlerhaft. Sie sollten den Inhalt Ihres Dokuments entsprechend der Rolle des Benutzers rendern. Das Mischen von Inhalten für Rollen ist kein sicherer Weg, um das Problem anzugehen. Wenn jemand als Administrator bei Ihrem System angemeldet ist, rendern Sie den Inhalt für einen Administrator. Wenn sie als Leser in Ihrem System angemeldet sind, rendern Sie den Inhalt für einen Leser. Dadurch werden Inhalte, auf die nicht zugegriffen werden sollte, vollständig eliminiert. Verwenden Sie nach dem Rendern des Inhalts CSS, um Ihr Dokument zu formatieren und Inhalte anzuzeigen / auszublenden.
jrista
2
Ich stimme Ihnen zu und habe Ihre Empfehlungen in das Projekt aufgenommen. Ich werde toggle () verwenden, um Admin-Elemente anzuzeigen, die nur gerendert werden, wenn ein Admin angemeldet ist. Obwohl dies nicht (direkt) mit der ursprünglichen Frage zusammenhängt, ist dies wahrscheinlich eine bessere Lösung als die Richtung, in die ich ursprünglich gegangen bin. Prost!
Christopher Cooper
1
Umwerben! Sackte einen weiteren Schlag schlechter Sicherheit ein! Ein Sieg und Runden für alle! (Bier Symbol hier einfügen)
jrista
1
Sich aus Sicherheitsgründen auf clientseitiges Javascript zu verlassen, ist SCHLECHTER als gar keine Sicherheit. Warum? Weil Sie denken, Sie haben Sicherheit, obwohl Sie dies nicht tun.
BryanH
8

Ich bemerkte, dass die erste Antwort nicht ganz das war, was ich brauchte, also nahm ich ein paar Änderungen vor und dachte, ich würde sie hier zurück posten.

Verbessert replaceTag(<tagName>)

replaceTag(<tagName>, [withDataAndEvents], [withDataAndEvents])

Argumente:

  • tagName: String
    • Der Tag-Name zB "div", "span" usw.
  • withDataAndEvents: Boolean
    • "Ein Boolescher Wert, der angibt, ob Ereignishandler zusammen mit den Elementen kopiert werden sollen. Ab jQuery 1.4 werden auch Elementdaten kopiert." die Info
  • deepWithDataAndEvents: Boolean ,
    • Ein Boolescher Wert, der angibt, ob Ereignishandler und Daten für alle untergeordneten Elemente des geklonten Elements kopiert werden sollen. Standardmäßig entspricht der Wert dem Wert des ersten Arguments (standardmäßig false). " Info

Kehrt zurück:

Ein neu erstelltes jQuery-Element

Okay, ich weiß, dass es hier jetzt ein paar Antworten gibt, aber ich habe es auf mich genommen, dies noch einmal zu schreiben.

Hier können wir das Tag auf die gleiche Weise ersetzen, wie wir das Klonen verwenden. Wir verfolgen die gleiche Syntax wie .clone () mit der withDataAndEventsund deepWithDataAndEventsdas Kopieren Sie die Kind - Knoten Daten und Ereignisse , wenn verwendet.

Beispiel:

$tableRow.find("td").each(function() {
  $(this).clone().replaceTag("li").appendTo("ul#table-row-as-list");
});

Quelle:

$.extend({
    replaceTag: function (element, tagName, withDataAndEvents, deepWithDataAndEvents) {
        var newTag = $("<" + tagName + ">")[0];
        // From [Stackoverflow: Copy all Attributes](http://stackoverflow.com/a/6753486/2096729)
        $.each(element.attributes, function() {
            newTag.setAttribute(this.name, this.value);
        });
        $(element).children().clone(withDataAndEvents, deepWithDataAndEvents).appendTo(newTag);
        return newTag;
    }
})
$.fn.extend({
    replaceTag: function (tagName, withDataAndEvents, deepWithDataAndEvents) {
        // Use map to reconstruct the selector with newly created elements
        return this.map(function() {
            return jQuery.replaceTag(this, tagName, withDataAndEvents, deepWithDataAndEvents);
        })
    }
})

Beachten Sie, dass dies das ausgewählte Element nicht ersetzt , sondern das neu erstellte zurückgibt.

Cole Lawrence
quelle
2
Beachten Sie, dass .children()keine reinen Textknoten enthalten sind. Vielleicht möchten Sie .contents()IIRC ausprobieren .
Orwellophile
5

Die Idee ist, das Element zu verpacken und den Inhalt auszupacken:

function renameElement($element,newElement){

    $element.wrap("<"+newElement+">");
    $newElement = $element.parent();

    //Copying Attributes
    $.each($element.prop('attributes'), function() {
        $newElement.attr(this.name,this.value);
    });

    $element.contents().unwrap();       

    return $newElement;
}

Beispielnutzung:

renameElement($('p'),'h5');

Demo

Shubanker
quelle
0

Ich habe einen Ansatz entwickelt, bei dem Sie eine Zeichenfolgendarstellung Ihres jQuery-Objekts verwenden und den Tag-Namen durch reguläre Ausdrücke und grundlegendes JavaScript ersetzen. Sie verlieren keinen Inhalt und müssen nicht jedes Attribut / jede Eigenschaft durchlaufen.

/*
 * replaceTag
 * @return {$object} a new object with replaced opening and closing tag
 */
function replaceTag($element, newTagName) {

  // Identify opening and closing tag
  var oldTagName = $element[0].nodeName,
    elementString = $element[0].outerHTML,
    openingRegex = new RegExp("^(<" + oldTagName + " )", "i"),
    openingTag = elementString.match(openingRegex),
    closingRegex = new RegExp("(<\/" + oldTagName + ">)$", "i"),
    closingTag = elementString.match(closingRegex);

  if (openingTag && closingTag && newTagName) {
    // Remove opening tag
    elementString = elementString.slice(openingTag[0].length);
    // Remove closing tag
    elementString = elementString.slice(0, -(closingTag[0].length));
    // Add new tags
    elementString = "<" + newTagName + " " + elementString + "</" + newTagName + ">";
  }

  return $(elementString);
}

Schließlich können Sie das vorhandene Objekt / den vorhandenen Knoten wie folgt ersetzen:

var $newElement = replaceTag($rankingSubmit, 'a');
$('#not-an-a-element').replaceWith($newElement);
Kevinweber
quelle
0

Das ist meine Lösung. Es ermöglicht das Umschalten zwischen Tags.

<!DOCTYPE html>
<html>
<head>
	<title></title>

<script src="https://code.jquery.com/jquery-1.11.3.js"></script>
<script type="text/javascript">

function wrapClass(klass){
	return 'to-' + klass;
}

function replaceTag(fromTag, toTag){
	
	/** Create selector for all elements you want to change.
	  * These should be in form: <fromTag class="to-toTag"></fromTag>
	  */
	var currentSelector = fromTag + '.' + wrapClass(toTag);

	/** Select all elements */
	var $selected = $(currentSelector);

	/** If you found something then do the magic. */
	if($selected.size() > 0){

		/** Replace all selected elements */
		$selected.each(function(){

			/** jQuery current element. */
			var $this = $(this);

			/** Remove class "to-toTag". It is no longer needed. */
			$this.removeClass(wrapClass(toTag));

			/** Create elements that will be places instead of current one. */
			var $newElem = $('<' + toTag + '>');

			/** Copy all attributes from old element to new one. */
			var attributes = $this.prop("attributes");
			$.each(attributes, function(){
				$newElem.attr(this.name, this.value);
			});

			/** Add class "to-fromTag" so you can remember it. */
			$newElem.addClass(wrapClass(fromTag));

			/** Place content of current element to new element. */
			$newElem.html($this.html());

			/** Replace old with new. */
			$this.replaceWith($newElem);
		});

		/** It is possible that current element has desired elements inside.
		  * If so you need to look again for them.
		  */
		replaceTag(fromTag, toTag);
	}
}


</script>

<style type="text/css">
	
	section {
		background-color: yellow;
	}

	div {
		background-color: red;
	}

	.big {
		font-size: 40px;
	}

</style>
</head>
<body>

<button onclick="replaceTag('div', 'section');">Section -> Div</button>
<button onclick="replaceTag('section', 'div');">Div -> Section</button>

<div class="to-section">
	<p>Matrix has you!</p>
	<div class="to-section big">
		<p>Matrix has you inside!</p>
	</div>
</div>

<div class="to-section big">
	<p>Matrix has me too!</p>
</div>

</body>
</html>

zie1ony
quelle
0

Dies ist der schnelle Weg, um HTML-Tags in Ihrem DOM mithilfe von jQuery zu ändern. Ich finde diese Funktion replaceWith () sehr nützlich.

   var text= $('p').text();
   $('#change').on('click', function() {
     target.replaceWith( "<h5>"+text+"</h5>" );
   });
Mahafuz
quelle
0

Sie können mit Hilfe von jQuery durch ein solches data-*Attribut erreichen data-replace="replaceTarget,replaceBy", dass Sie nach dem Abrufen von Werten replaceTarget& replaceByvalue by .split()method erhalten und dann .replaceWith()method verwenden.
Diese data-*Attributtechnik zum einfachen Verwalten des Ersetzens von Tags, ohne diese zu ändern (allgemeiner Code für das Ersetzen aller Tags).

Ich hoffe, dass das folgende Snippet Ihnen sehr helfen wird.

$(document).on('click', '[data-replace]', function(){
  var replaceTarget = $(this).attr('data-replace').split(',')[0];
  var replaceBy = $(this).attr('data-replace').split(',')[1];
  $(replaceTarget).replaceWith($(replaceBy).html($(replaceTarget).html()));
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>

<p id="abc">Hello World #1</p>
<a href="#" data-replace="#abc,<h1/>">P change with H1 tag</a>
<hr>
<h2 id="xyz">Hello World #2</h2>
<a href="#" data-replace="#xyz,<p/>">H1 change with P tag</a>
<hr>
<b id="bold">Hello World #2</b><br>
<a href="#" data-replace="#bold,<i/>">B change with I tag</a>
<hr>
<i id="italic">Hello World #2</i><br>
<a href="#" data-replace="#italic,<b/>">I change with B tag</a>

Raeesh Alam
quelle
0

Die folgende Funktion erledigt den Trick und behält alle Attribute bei. Sie verwenden es zum Beispiel so:changeTag("div", "p")

function changeTag(originTag, destTag) {
  while($(originTag).length) {
    $(originTag).replaceWith (function () {
      var attributes = $(this).prop("attributes");
      var $newEl = $(`<${destTag}>`)
      $.each(attributes, function() {
        $newEl.attr(this.name, this.value);
      });  
      return $newEl.html($(this).html())
    })
  }
}

Überprüfen Sie das folgende Beispiel, um sicherzustellen, dass es funktioniert

function changeTag(originTag, destTag) {
  while($(originTag).length) {
    $(originTag).replaceWith (function () {
      var attributes = $(this).prop("attributes");
      var $newEl = $(`<${destTag}>`)
      $.each(attributes, function() {
        $newEl.attr(this.name, this.value);
      });  
      return $newEl.html($(this).html())
    })
  }
}

changeTag("div", "p")

console.log($("body").html())
<body>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>

<div class="A" style="font-size:1em">
  <div class="B" style="font-size:1.1em">A</div>
</div>
<div class="C" style="font-size:1.2em">
  B
</div>
</body>

João Pimentel Ferreira
quelle
-1

Gibt es einen bestimmten Grund, warum Sie das Tag ändern müssen? Wenn Sie den Text nur vergrößern möchten, ist es besser, die CSS-Klasse des p-Tags zu ändern.

Etwas wie das:

$('#change').click(function(){
  $('p').addClass('emphasis');
});
Dave Ward
quelle
Der Grund, warum ich das Element / Tag ändern möchte, ist, dass ich versuche, ein Tag (ein <h5>, obwohl der Typ irrelevant ist) in ein <Eingabe> zu ändern, wenn an anderer Stelle auf der Seite auf die Schaltfläche "Bearbeiten" geklickt wird .
Christopher Cooper