Использовать 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>'));
mishac
источник
2
См. Мой комментарий ниже ... изменение структуры документа для применения стиля - не лучший подход.
jrista
39
Разве это не уничтожит какие-либо атрибуты, которые могут быть у замененного вами элемента? Может привести к неожиданному поведению из-за удаленных атрибутов стиля, атрибутов данных и т. Д.
Хави
5
"<" + el.outerHTML.replace(/(^<\w+|\w+>$)/g, "H5") + ">";Или подключаемая функция jQuery: ссылка
василий
65

Вот расширение, которое сделает все это на таком количестве элементов и разными способами ...

Пример использования:

сохранить существующий класс и атрибуты:

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

или

Отменить существующий класс и атрибуты:

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

или даже

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

$('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);
        });
    }
});
Orwellophile
источник
2
Ага. И для записи: на самом деле существует множество очень веских причин, по которым вы можете захотеть изменить тег. например, если у вас есть теги DIV в SPAN, что, черт возьми, нестандартно. Я получил много пользы от этой функции, работая со строгими стандартами princexml для публикации pdb.
Orwellophile
1
Выглядит действительно красиво, хотя, к сожалению, теряет все события заменяемого элемента. Возможно, с этим тоже можно было бы справиться - было бы здорово!
NPC
@NPC - это жизнь в большом городе. если вы собираетесь заменять элементы, будут жертвы. Я уверен, что есть кто-то, кто знает соответствующий jquery для клонирования событий :)
Orwellophile
1
@FrankvanLuijn @orwellophile return node;фактически должен быть таким, return this;как показано в «старой версии» плагина. Это essentiall для построения цепочки событий вместе , как$("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>
jrista
источник
3
Даже в этом случае вам не следует изменять структуру документа. Если вам нужно отобразить ввод в ответ на нажатие кнопки редактирования, затем поместите ввод и закрепите на нем display: none или visibility: hidden. Скройте <h5> и покажите <input> в ответ на нажатие кнопки. Если вы постоянно изменяете структуру своего документа ... вы просто просите в будущем решить множество проблем со стилем и макетом.
jrista
1
Абсолютно. Ваш javascript встроен или связан, поэтому, если вас беспокоит безопасность, ваш подход к безопасности несколько ошибочен. Вы должны отображать содержимое вашего документа в соответствии с ролью пользователя ... смешивание содержимого для ролей не является безопасным способом решения проблемы. Если кто-то вошел в вашу систему как администратор, отобразите контент для администратора. Если они вошли в вашу систему как читатели, визуализируйте контент для читателя. Это полностью исключает контент, к которому нельзя получить доступ. После рендеринга содержимого используйте CSS для стилизации документа и отображения / скрытия материала.
jrista
2
Я согласен с вами и учел ваши рекомендации в проекте. Я буду использовать toggle () для отображения элементов администратора, которые отображаются только тогда, когда администратор вошел в систему. Хотя это не связано (напрямую) с исходным вопросом, это, вероятно, лучшее решение, чем то направление, в котором я изначально шел. Ура!
Кристофер Купер
1
Woo! Получил еще один кусок плохой безопасности! Победа и раунды для всех! (вставьте сюда значок пива)
jrista
1
Полагаться на клиентский javascript для обеспечения безопасности на самом деле ХУЖЕ, чем отсутствие защиты вообще. Зачем? Потому что вы думаете, что у вас есть безопасность, хотя на самом деле это не так.
BryanH
8

Я заметил, что первый ответ был не совсем тем, что мне нужно, поэтому я внес пару изменений и решил, что отправлю его сюда.

Улучшенный replaceTag(<tagName>)

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

Аргументы:

  • tagName: Строка
    • Имя тега, например, «div», «span» и т. Д.
  • withDataAndEvents: Boolean
    • «Логическое значение, указывающее, следует ли копировать обработчики событий вместе с элементами. Начиная с jQuery 1.4, данные элементов также будут скопированы». Информация
  • deepWithDataAndEvents: Boolean ,
    • Логическое значение, указывающее, следует ли копировать обработчики событий и данные для всех дочерних элементов клонированного элемента. По умолчанию его значение совпадает со значением первого аргумента (по умолчанию 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.
Orwellophile
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');

демонстрация

Shubanker
источник
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);
kevinweber
источник
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>

zie1ony
источник
0

Это быстрый способ изменить HTML-теги внутри вашей DOM с помощью jQuery. Я считаю эту функцию replaceWith () очень полезной.

   var text= $('p').text();
   $('#change').on('click', function() {
     target.replaceWith( "<h5>"+text+"</h5>" );
   });
Mahafuz
источник
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>, когда в другом месте страницы нажимается кнопка «Изменить». ,
Кристофер Купер