问题
jQuery: how to change tag name?
For example:
<tr>
$1
</tr>
I need
<div>
$1
</div>
Yes, I can
- Create DOM element <div>
- Copy tr content to div
- Remove tr from dom
But can I make it directly?
PS:
$(tr).get(0).tagName = \"div\";
results in DOMException.
回答1:
You can replace any HTML markup by using jQuery's .replaceWith() method.
example: http://jsfiddle.net/JHmaV/
Ref.: .replaceWith
If you want to keep the existing markup, you could use code like this:
$('#target').replaceWith('<newTag>' + $('#target').html() +'</newTag>')
回答2:
No, it is not possible according to W3C specification: "tagName of type DOMString, readonly"
http://www.w3.org/TR/DOM-Level-2-Core/core.html
回答3:
Where the DOM renameNode() Method?
Today (2014) no browser understand the new DOM3 renameNode method (see also W3C) check if run at your bowser: http://jsfiddle.net/k2jSm/1/
So, a DOM solution is ugly and I not understand why (??) jQuery not implemented a workaround?
pure DOM algorithm
createElement(new_name)- copy all content to new element;
- replace old to new by
replaceChild()
is something like this,
function rename_element(node,name) {
var renamed = document.createElement(name);
foreach (node.attributes as a) {
renamed.setAttribute(a.nodeName, a.nodeValue);
}
while (node.firstChild) {
renamed.appendChild(node.firstChild);
}
return node.parentNode.replaceChild(renamed, node);
}
... wait review and jsfiddle ...
jQuery algorithm
The @ilpoldo algorithm is a good start point,
$from.replaceWith($('<'+newname+'/>').html($from.html()));
As others commented, it need a attribute copy ... wait generic ...
specific for class, preserving the attribute, see http://jsfiddle.net/cDgpS/
See also https://stackoverflow.com/a/9468280/287948
回答4:
The above solutions wipe out the existing element and re-create it from scratch, destroying any event bindings on children in the process.
short answer: (loses 's attributes)
$("p").wrapInner("<div/>").children(0).unwrap();
longer answer: (copies 's attributes)
$("p").each(function (o, elt) {
var newElt = $("<div class='p'/>");
Array.prototype.slice.call(elt.attributes).forEach(function(a) {
newElt.attr(a.name, a.value);
});
$(elt).wrapInner(newElt).children(0).unwrap();
});
fiddle with nested bindings
It would be cool to copy any bindings from the at the same time, but getting current bindings didn't work for me.
回答5:
To preserve the internal content of the tag you can use the accessor .html() in conjunction with .replaceWith()
forked example: http://jsfiddle.net/WVb2Q/1/
回答6:
You could go a little basic. Works for me.
var oNode = document.getElementsByTagName('tr')[0];
var inHTML = oNode.innerHTML;
oNode.innerHTML = '';
var outHTML = oNode.outerHTML;
outHTML = outHTML.replace(/tr/g, 'div');
oNode.outerHTML = outHTML;
oNode.innerHTML = inHTML;
回答7:
Inspired by ericP answer, formatted and converted to jQuery plugin:
$.fn.replaceWithTag = function(tagName) {
var result = [];
this.each(function() {
var newElem = $('<' + tagName + '>').get(0);
for (var i = 0; i < this.attributes.length; i++) {
newElem.setAttribute(
this.attributes[i].name, this.attributes[i].value
);
}
newElem = $(this).wrapInner(newElem).children(0).unwrap().get(0);
result.push(newElem);
});
return $(result);
};
Usage:
$('div').replaceWithTag('span')
回答8:
To replace the internal contents of multiple tags, each with their own original content, you have to use .replaceWith() and .html() differently:
http://jsfiddle.net/kcrca/VYxxG/
回答9:
JS to change the tag name
/**
* This function replaces the DOM elements's tag name with you desire
* Example:
* replaceElem('header','ram');
* replaceElem('div.header-one','ram');
*/
function replaceElem(targetId, replaceWith){
$(targetId).each(function(){
var attributes = concatHashToString(this.attributes);
var replacingStartTag = '<' + replaceWith + attributes +'>';
var replacingEndTag = '</' + replaceWith + '>';
$(this).replaceWith(replacingStartTag + $(this).html() + replacingEndTag);
});
}
replaceElem('div','span');
/**
* This function concats the attributes of old elements
*/
function concatHashToString(hash){
var emptyStr = '';
$.each(hash, function(index){
emptyStr += ' ' + hash[index].name + '="' + hash[index].value + '"';
});
return emptyStr;
}
Related fiddle is in this link
回答10:
Simply changing the property values won't do it (as others have said, some HTMLElement properties are read-only; also some hold prototypal context to more primitive elements). The closest thing you can get to mimicking the DOM API is to mimic also the process of prototypal inheritance in JavaScript.
'Setting' on an object's prototype via __proto__ is generally frowned upon. Also, you might consider why you think you need to duplicate the entire DOM element in the first place. But here goes:
// Define this at whatever scope you'll need to access it
// Most of these kinds of constructors are attached to the `window` object
window.HTMLBookElement = function() {
function HTMLBookElement() {
var book = document.createElement('book');
book.__proto__ = document.createElement('audio');
return book;
}
return new HTMLBookElement();
}
// Test your new element in a console (I'm assuming you have Chrome)
var harryPotter = new HTMLBookElement();
// You should have access to your new `HTMLBookElement` API as well as that
// of its prototype chain; since I prototyped `HTMLAudioElement`, you have
// some default properties like `volume` and `preload`:
console.log(harryPotter); // should log "<book></book>"
console.log(harryPotter.volume); // should log "1"
console.log(harryPotter.preload); // should log "auto"
All DOM elements work this way. For example:
<div></div> is produced by HTMLDivElement,
which extends HTMLElement,
which in turn extends Element,
which in turn extends Object.
回答11:
Since replaceWith() didn't work for me on an element basis (maybe because I used it inside map()), I did it by creating a new element and copying the attributes as needed.
$items = $('select option').map(function(){
var
$source = $(this),
$copy = $('<li></li>'),
title = $source.text().replace( /this/, 'that' );
$copy
.data( 'additional_info' , $source.val() )
.text(title);
return $copy;
});
$('ul').append($items);
回答12:
Take him by the word
Taken the Question by Word "how to change tag name?" I would suggest this solution:
If it makes sense or not has to be decided case by case.
My example will "rename" all a-Tags with hyperlinks for SMS with span tags. Maintaining all attributes and content:
$('a[href^="sms:"]').each(function(){
var $t=$(this);
var $new=$($t.wrap('<div>')
.parent()
.html()
.replace(/^\s*<\s*a/g,'<span')
.replace(/a\s*>\s*$/g,'span>')
).attr('href', null);
$t.unwrap().replaceWith($new);
});
As it does not make any sense to have a span tag with an href attribute I remove that too. Doing it this way is bulletproof and compatible with all browsers that are supported by jquery. There are other ways people try to copy all the Attributes to the new Element, but those are not compatible with all browsers.
Although I think it is quite expensive to do it this way.
回答13:
Jquery plugin to make "tagName" editable :
(function($){
var $newTag = null;
$.fn.tagName = function(newTag){
this.each(function(i, el){
var $el = $(el);
$newTag = $("<" + newTag + ">");
// attributes
$.each(el.attributes, function(i, attribute){
$newTag.attr(attribute.nodeName, attribute.nodeValue);
});
// content
$newTag.html($el.html());
$el.replaceWith($newTag);
});
return $newTag;
};
})(jQuery);
See : http://jsfiddle.net/03gcnx9v/3/
回答14:
Yet another script to change the node name
function switchElement() {
$element.each(function (index, oldElement) {
let $newElement = $('<' + nodeName + '/>');
_.each($element[0].attributes, function(attribute) {
$newElement.attr(attribute.name, attribute.value);
});
$element.wrapInner($newElement).children().first().unwrap();
});
}
http://jsfiddle.net/rc296owo/5/
It will copy over the attributes and inner html into a new element and then replace the old one.
回答15:
$(function(){
$('#switch').bind('click', function(){
$('p').each(function(){
$(this).replaceWith($('<div/>').html($(this).html()));
});
});
});
p {
background-color: red;
}
div {
background-color: yellow;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<p>Hello</p>
<p>Hello2</p>
<p>Hello3</p>
<button id="switch">replace</button>
回答16:
You can use this function
var renameTag = function renameTag($obj, new_tag) {
var obj = $obj.get(0);
var tag = obj.tagName.toLowerCase();
var tag_start = new RegExp('^<' + tag);
var tag_end = new RegExp('<\\/' + tag + '>$');
var new_html = obj.outerHTML.replace(tag_start, "<" + new_tag).replace(tag_end, '</' + new_tag + '>');
$obj.replaceWith(new_html);
};
ES6
const renameTag = function ($obj, new_tag) {
let obj = $obj.get(0);
let tag = obj.tagName.toLowerCase();
let tag_start = new RegExp('^<' + tag);
let tag_end = new RegExp('<\\/' + tag + '>$');
let new_html = obj.outerHTML.replace(tag_start, "<" + new_tag).replace(tag_end, '</' + new_tag + '>');
$obj.replaceWith(new_html);
};
Sample code
renameTag($(tr),'div');
回答17:
Working pure DOM algorithm
function rename_element(node, name) {
let renamed = document.createElement(name);
Array.from(node.attributes).forEach(attr => {
renamed.setAttribute(attr.name, attr.value);
})
while (node.firstChild) {
renamed.appendChild(node.firstChild);
}
node.parentNode.replaceChild(renamed, node);
return renamed;
}
来源:https://stackoverflow.com/questions/3435871/jquery-how-to-change-tag-name