Użyć jQuery do zmiany tagu HTML?

130

czy to możliwe?

przykład:

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


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

Zatem kliknięcie zakotwiczenia zmiany powinno spowodować zmianę <p>Hello!</p>sekcji (na przykład) na tag h5, tak abyś znalazł się <h5>Hello!</h5>po kliknięciu. Zdaję sobie sprawę, że możesz usunąć znacznik p i zamienić go na h5, ale czy w ogóle istnieje możliwość zmodyfikowania znacznika HTML?

Christopher Cooper
źródło

Odpowiedzi:

212

Uważam, że po utworzeniu elementu dom znacznik jest niezmienny. Musiałbyś zrobić coś takiego:

$(this).replaceWith($('<h5>' + this.innerHTML + '</h5>'));
mishac
źródło
2
Zobacz mój komentarz poniżej ... zmiana struktury dokumentu w celu zastosowania stylu nie jest najlepszym podejściem.
jrista
39
Czy to nie zniweczy żadnych atrybutów, które mogą znajdować się na elemencie, który wymieniłeś? Może prowadzić do nieoczekiwanego zachowania z powodu usuniętych atrybutów stylu, atrybutów danych itp ...
Xavi,
5
"<" + el.outerHTML.replace(/(^<\w+|\w+>$)/g, "H5") + ">";Lub podłączana funkcja jQuery: link
bazylia
65

Oto rozszerzenie, które zrobi to wszystko, na jak największej liczbie elementów na wiele sposobów ...

Przykładowe użycie:

zachowaj istniejącą klasę i atrybuty:

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

lub

Odrzuć istniejącą klasę i atrybuty:

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

lub nawet

zamień wszystkie elementy div na rozpiętości, skopiuj klasy i atrybuty, dodaj dodatkową nazwę klasy

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

Źródło wtyczki:

$.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);
        });
    }
});
Orwellophile
źródło
2
Tak. Tak naprawdę, istnieje wiele bardzo ważnych powodów, dla których warto zmienić tag. np. jeśli masz tagi DIV w zakresie SPAN, co jest bardzo niestandardowe. Ta funkcja przydała mi się podczas pracy z surowymi standardami princexml dla publikacji pdb.
Orwellophile
1
Wygląda naprawdę ładnie, choć niestety traci wszystkie zdarzenia wymienionego elementu. Może to też dałoby się załatwić - byłoby wspaniale!
NPC
@NPC to życie w wielkim mieście. jeśli zamierzasz wymienić elementy, będą ofiary. jestem pewien, że jest ktoś, kto zna odpowiednie jquery do sklonowania wydarzeń :)
Orwellophile
1
@FrankvanLuijn @orwellophile return node;powinno faktycznie wyglądać return this;tak, jak pokazano w „starej wersji” wtyczki. Jest to niezbędne do łączenia wydarzeń w łańcuch, takich jak$("tr:first").find("td").clone().replaceTag("li").appendTo("ul#list")
Cole Lawrence,
1
Nie rozumiem, dlaczego potrzebujesz 2 funkcji? Czy potrzebujesz obu? Przepraszam, zgubiłem się
João Pimentel Ferreira
12

Zamiast zmieniać typ tagu, powinieneś zmienić styl tagu (a raczej taga z określonym identyfikatorem). Nie jest dobrą praktyką zmienianie elementów dokumentu w celu wprowadzenia zmian stylistycznych. Spróbuj tego:

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

<p id="changed">Hello!</p>
<a id="change">change</a>
jrista
źródło
3
Nawet w tym przypadku nie powinieneś modyfikować struktury dokumentu. Jeśli potrzebujesz wyświetlić dane wejściowe w odpowiedzi na kliknięcie przycisku edycji, umieść wejście i przytrzymaj wyświetlacz: brak lub widoczność: ukryty. Ukryj <h5> i pokaż <input> w odpowiedzi na kliknięcie przycisku. Jeśli ciągle modyfikujesz strukturę swojego dokumentu ... po prostu prosisz o całe mnóstwo problemów ze stylem i układem.
jrista
1
Absolutnie. Twój javascript jest osadzony lub linkowany, więc jeśli Twoim problemem jest bezpieczeństwo, Twoje podejście do bezpieczeństwa jest nieco błędne. Powinieneś renderować zawartość swojego dokumentu zgodnie z rolą użytkownika ... mieszanie treści dla ról nie jest bezpiecznym sposobem rozwiązania problemu. Jeśli ktoś jest zalogowany w systemie jako administrator, wyrenderuj zawartość dla administratora. Jeśli są zalogowani do systemu jako czytelnicy, wyrenderuj zawartość dla czytelnika. To całkowicie eliminuje treści, do których nie należy uzyskiwać dostępu. Po wyrenderowaniu treści użyj CSS, aby stylizować dokument i pokazać / ukryć rzeczy.
jrista
2
Zgadzam się z Tobą i uwzględniam Twoje zalecenia w projekcie. Będę używał toggle (), aby pokazać elementy administratora, które są renderowane tylko wtedy, gdy administrator jest zalogowany. Chociaż nie jest to związane (bezpośrednio) z pierwotnym pytaniem, jest to prawdopodobnie lepsze rozwiązanie niż kierunek, w którym pierwotnie zmierzałem. Twoje zdrowie!
Christopher Cooper
1
Zabiegać! Mam kolejną klapę złego zabezpieczenia! Zwycięstwo i rundy dla wszystkich! (wstaw tutaj ikonę piwa)
jrista
1
Poleganie na javascript po stronie klienta w celu zapewnienia bezpieczeństwa jest w rzeczywistości gorsze niż brak zabezpieczeń. Czemu? Ponieważ myślisz, że masz bezpieczeństwo, podczas gdy w rzeczywistości nie.
BryanH,
8

Zauważyłem, że pierwsza odpowiedź nie była tym, czego potrzebowałem, więc wprowadziłem kilka modyfikacji i pomyślałem, że wrzucę ją tutaj.

Ulepszony replaceTag(<tagName>)

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

Argumenty:

  • tagName: String
    • Nazwa tagu, np. „Div”, „span” itp.
  • withDataAndEvents: Boolean
    • „Wartość logiczna wskazująca, czy procedury obsługi zdarzeń powinny być kopiowane wraz z elementami. Od wersji jQuery 1.4 dane elementu również zostaną skopiowane”. info
  • deepWithDataAndEvents: Boolean ,
    • Wartość logiczna wskazująca, czy programy obsługi zdarzeń i dane dla wszystkich elementów podrzędnych sklonowanego elementu powinny zostać skopiowane. Domyślnie jego wartość jest zgodna z wartością pierwszego argumentu (domyślnie false). ” Info

Zwroty:

Nowo utworzony element jQuery

W porządku, wiem, że jest tu teraz kilka odpowiedzi, ale postanowiłem napisać to ponownie.

Tutaj możemy zastąpić tag w ten sam sposób, w jaki używamy klonowania. Jesteśmy po tej samej składni jak .clone () z withDataAndEventsi deepWithDataAndEventsktóry skopiuj dzieci- dane i wydarzenia węzłami, jeżeli są stosowane.

Przykład:

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

Źródło:

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

Zwróć uwagę, że nie zastępuje to wybranego elementu, ale zwraca nowo utworzony.

Cole Lawrence
źródło
2
Należy pamiętać, że .children()nie będzie to zawierać żadnych węzłów czysto tekstowych. Możesz spróbować .contents()IIRC.
Orwellophile
6

Pomysł polega na zawinięciu elementu i rozpakowaniu zawartości:

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

Przykładowe użycie:

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

Próbny

Shubanker
źródło
0

Wymyśliłem podejście, w którym używasz reprezentacji łańcuchowej swojego obiektu jQuery i zastępujesz nazwę tagu za pomocą wyrażeń regularnych i podstawowego JavaScript. Nie stracisz żadnej zawartości i nie będziesz musiał zapętlać się nad każdym atrybutem / właściwością.

/*
 * 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);
}

Na koniec możesz zastąpić istniejący obiekt / węzeł w następujący sposób:

var $newElement = replaceTag($rankingSubmit, 'a');
$('#not-an-a-element').replaceWith($newElement);
kevinweber
źródło
0

To jest moje rozwiązanie. Pozwala przełączać się między tagami.

<!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
źródło
0

To szybki sposób na zmianę tagów HTML wewnątrz DOM za pomocą jQuery. Uważam, że ta funkcja replaceWith () jest bardzo przydatna.

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

Możesz to osiągnąć za pomocą data-*atrybutu, data-replace="replaceTarget,replaceBy"tak jak to, za pomocą jQuery, aby uzyskać replaceTarget& replaceBywartość według .split()metody po uzyskaniu wartości, a następnie użyj .replaceWith()metody.
Ta data-*technika atrybutów do łatwego zarządzania wymianą tagów bez wprowadzania zmian poniżej (wspólny kod dla wszystkich zamian tagów).

Mam nadzieję, że poniższy fragment bardzo ci pomoże.

$(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
źródło
0

Następująca funkcja załatwia sprawę i zachowuje wszystkie atrybuty. Używasz go na przykład w ten sposób: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())
    })
  }
}

Aby upewnić się, że działa, sprawdź poniższy przykład

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
źródło
-1

Czy jest jakiś konkretny powód, dla którego musisz zmienić tag? Jeśli chcesz po prostu powiększyć tekst, lepszym sposobem będzie zmiana klasy CSS znacznika p.

Coś takiego:

$('#change').click(function(){
  $('p').addClass('emphasis');
});
Dave Ward
źródło
Powodem, dla którego proszę o zmianę elementu / tagu jest to, że próbuję zmienić tag (<h5>, chociaż typ jest nieistotny) na <input> po kliknięciu przycisku „Edytuj” w innym miejscu na stronie .
Christopher Cooper