Використовувати jQuery, щоб змінити тег HTML?


130

Чи можливо це?

приклад:

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


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

Якщо натиснути якір зміни, це повинно призвести <p>Hello!</p>до зміни розділу (як приклад) тегу h5, щоб ви закінчилися <h5>Hello!</h5>після натискання. Я усвідомлюю, що ви можете видалити тег p та замінити його на h5, але чи все-таки можна змінити тег HTML?

Відповіді:


211

Після створення елемента dom, я вважаю, що тег є незмінним. Вам доведеться зробити щось подібне:

$(this).replaceWith($('<h5>' + this.innerHTML + '</h5>'));

2
Будь ласка, дивіться мій коментар нижче ... зміна структури документа для застосування стилю - не найкращий підхід.
jrista

39
Чи не був би цей клобер атрибутами, які могли б бути на заміненому вами елементі? Це може призвести до несподіваної поведінки через видалені атрибути стилю, атрибути даних тощо ...
Xavi

5
"<" + el.outerHTML.replace(/(^<\w+|\w+>$)/g, "H5") + ">";Або підключається функція jQuery: посилання
базилік

65

Ось розширення, яке зробить це все, на якомога більшій кількості елементів ...

Приклад використання:

зберегти існуючий клас та атрибути:

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

або

Відмовтеся від існуючого класу та атрибутів:

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

або навіть

замініть всі знаки на проміжки, скопіюйте класи та атрибути, додайте додаткову назву класу

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

Джерело плагіна:

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

2
Так. І для запису, насправді існує дуже багато поважних причин, за якими ви можете змінити тег. наприклад, якщо у вас було тегів DIV в межах SPAN, що є нестандартним. Я отримав велику користь від цієї функції, працюючи із суворими стандартами princexml для публікації на pdb.
Орвелофіл

1
Виглядає дуже приємно, хоча, на жаль, він втрачає всі події заміненого елемента. Можливо, і з цим можна було б впоратися - було б приголомшливо!
NPC

@NPC - це життя у великому місті. якщо ви збираєтеся замінити елементи, то будуть жертви. Я впевнений, що є хтось там, хто знає відповідний jquery для клонування подій :)
Orwellophile

1
@FrankvanLuijn @orwellophile return node;фактично має бути return this;таким, як показано у "старій версії" плагіна. Це дуже важливо для поєднання подій на кшталт$("tr:first").find("td").clone().replaceTag("li").appendTo("ul#list")
Коул Лоуренс

1
Я не розумію, навіщо вам потрібні 2 функції? Вам потрібно обоє? Вибачте, я загубився
Жоао Піментел Феррейра

12

Замість того, щоб змінити тип тегу, вам слід змінити стиль тегу (а точніше, тег із певним ідентифікатором). Це не є хорошою практикою змінювати елементи вашого документа, щоб застосувати стилістичні зміни. Спробуйте це:

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

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

3
Навіть у цьому випадку ви не повинні змінювати структуру документа. Якщо вам потрібно відобразити ввід у відповідь на натискання редагування, але натисніть на нього та вставте дисплей: немає або видимість: приховано на ньому. Схойте <h5> і покажіть <input> у відповідь на натискання кнопки. Якщо ви постійно змінюєте структуру свого документа ... ви просто запитуєте про грубі проблеми стилю та макета вниз.
jrista

1
Абсолютно. Ваш JavaScript вбудований або зв'язаний, тому, якщо ви турбуєтесь про безпеку, то ваш підхід до безпеки дещо недосконалий. Ви повинні візуалізувати вміст свого документа відповідно до ролі користувача ... змішування вмісту для ролей не є безпечним способом наближення до проблеми. Якщо хтось увійшов у вашу систему як адміністратор, виведіть вміст для адміністратора. Якщо вони увійшли до вашої системи як зчитувач, надайте вміст для читача. Це повністю виключає вміст, до якого не можна отримати доступ. Після того, як вміст буде надано, використовуйте CSS для стилізації документа та показу / приховування матеріалів.
jrista

2
Я погоджуюся з вами і взяв ваші рекомендації до проекту. Я буду використовувати toggle (), щоб показати адміністраторські елементи, які відображаються лише під час входу адміністратора. Хоча це не пов'язано (безпосередньо) з початковим запитанням, це, мабуть, краще рішення, ніж напрямок, в якому я спочатку йшов. Ура!
Крістофер Купер

1
Ву! Нарікав черговий блок поганої безпеки! Виграш і раунди для всіх! (вставити сюди значок пива)
jrista

1
Покладаючись на підтримку javascript на стороні клієнта, насправді БЕЗПЕЧНО, ніж взагалі ніякої безпеки. Чому? Тому що ти думаєш, що маєш безпеку, а насправді цього немає.
BryanH

8

Я помітив, що перша відповідь була не зовсім те, що мені потрібно, тому я зробив кілька модифікацій і подумав, що опублікую її тут.

Поліпшено replaceTag(<tagName>)

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

Аргументи:

  • tagName: Рядок
    • Назва тегу, наприклад, "div", "span" тощо.
  • withDataAndEvents: булева
    • "Булева інформація, яка вказує, чи слід копіювати обробники подій разом з елементами. З jQuery 1.4 також будуть скопійовані дані елементів." інформація
  • deepWithDataAndEvents: булева ,
    • Булева інформація, яка вказує, чи слід копіювати обробники подій та дані для всіх дітей клонованого елемента. За замовчуванням його значення відповідає значенню першого аргументу (який за замовчуванням відповідає false). " Info

Повернення:

Новостворений елемент jQuery

Гаразд, я знаю, що тут є кілька відповідей, але я взяв на себе, щоб написати це ще раз.

Тут ми можемо замінити тег так само, як ми використовуємо клонування. Ми дотримуємось того ж синтаксису, що і .clone (), що withDataAndEventsі deepWithDataAndEventsкопіює дані і події дочірніх вузлів, якщо вони використовуються.

Приклад:

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

Джерело:

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

Зауважте, що це не замінює обраний елемент, він повертає новостворений.


2
Майте на увазі, що .children()не буде містити жодних суто текстових вузлів. Ви можете спробувати .contents()IIRC.
Орвелофіл

5

Ідея полягає в обгортанні елемента і розгортанні вмісту:

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

Використання зразка:

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

Демо


0

Я придумав підхід, коли ви використовуєте рядовий подання об'єкта jQuery і замінюєте ім'я тега, використовуючи регулярні вирази та базовий JavaScript. Ви не втратите жодного вмісту, і вам не доведеться перебирати кожен атрибут / властивість.

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

Нарешті, ви можете замінити існуючий об’єкт / вузол наступним чином:

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

0

Це моє рішення. Це дозволяє перемикатися між тегами.

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


0

Це швидкий спосіб змінити теги HTML всередині вашого DOM за допомогою jQuery. Я вважаю, що ця функція substituWith () дуже корисна.

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

0

Ви можете досягти за таким data-*атрибутом data-replace="replaceTarget,replaceBy"за допомогою jQuery, щоб отримати replaceTarget& replaceByзначення .split()методом після отримання значень, а потім використовувати .replaceWith()метод.
Цей data-*метод атрибутів дозволяє легко керувати будь-якою заміною тегів без зміни нижче (загальний код для заміни всіх тегів).

Я сподіваюся, що нижче фрагмент допоможе вам багато.

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


0

Наступна функція виконує трюк і зберігає всі атрибути. Ви використовуєте його, наприклад, так: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())
    })
  }
}

Щоб переконатися, що він працює, перевірте наступний приклад

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>


-1

Чи є певна причина, що вам потрібно змінити тег? Якщо ви просто хочете зробити текст більшим, зміна класу CSS p тегів буде кращим способом зробити це.

Щось на зразок цього:

$('#change').click(function(){
  $('p').addClass('emphasis');
});

Причина, яку я прошу змінити елемент / тег, полягає в тому, що я намагаюся змінити тег (<h5>, хоча тип не має значення) на <input>, коли в іншому місці на сторінці натискається кнопка "редагувати". .
Крістофер Купер
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.