библиотека jQuery: как изменить имя тега?

библиотека jQuery: как изменить имя тега?

например:

<tr>
    
</tr>

мне нужно

<div>
    
</div>

Да, я могу

  1. создать элемент DOM
  2. копировать содержимое tr в div
  3. удалить tr из dom
  4. но могу ли я сделать это напрямую?

    PS:

        $(tr).get(0).tagName = "div"; 
    

    результаты DOMException.

16 ответов


вы можете заменить любую разметку HTML с помощью jQuery .replaceWith() метод.

пример:http://jsfiddle.net/JHmaV/

Ref.: .replaceWith

Если вы хотите сохранить существующую разметку, вы можете использовать такой код:

$('#target').replaceWith('<newTag>' + $('target').html() +'</newTag>')

нет, это невозможно в соответствии со спецификацией W3C: "tagName типа DOMString, только для чтения"

http://www.w3.org/TR/DOM-Level-2-Core/core.html


где метод DOM renameNode ()?

сегодня (2014) ни один браузер не понимает новый метод renameNode DOM3 (см. также консорциума W3C) проверьте, работает ли ваш Боузер:http://jsfiddle.net/k2jSm/1/

Итак, решение DOM уродливо, и я не понимаю почему (??) jQuery не реализовал обходной путь?

чистый алгоритм DOM

  1. createElement(new_name)
  2. скопировать все содержимое новый элемент;
  3. заменить старое на новое на replaceChild()

- это что-то вроде этого,

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

... ждите обзора и jsfiddle ...

алгоритм jQuery

алгоритм @ilpoldo является хорошей отправной точкой,

   $from.replaceWith($('<'+newname+'/>').html($from.html()));

как прокомментировали другие, ему нужна копия атрибута ... ждать родовой ...

характерные для class, сохранение атрибута см. http://jsfiddle.net/cDgpS/

см. также https://stackoverflow.com/a/9468280/287948


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

короткий ответ: (теряет атрибуты)

$("p").wrapInner("<div/>").children(0).unwrap();

более длинный ответ: (атрибуты копий)

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

возиться с вложенными привязками

было бы здорово скопировать любые привязки из одновременно, но получение текущего привязки у меня не получилось.


для сохранения внутреннего содержимого тега можно использовать аксессоры .html() в сочетании с .replaceWith()

раздвоенный пример:http://jsfiddle.net/WVb2Q/1/


вы могли бы пойти немного basic. Работать на меня.

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;

для замены внутреннего содержимого несколько теги, каждый со своим оригинальным контентом, вы должны использовать .replaceWith() и .html() иначе:

http://jsfiddle.net/kcrca/VYxxG/


JS, чтобы изменить имя тега

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

связанная скрипка находится в этом ссылке


просто изменение значений свойств не сделает этого (как говорили другие, некоторые HTMLElement свойства доступны только для чтения; также некоторые содержат прототипный контекст для более примитивных элементов). Самое близкое, что вы можете получить, чтобы имитировать API DOM, - это имитировать также процесс прототипного наследования в JavaScript.

"настройка" на прототипе объекта через __proto__ обычно хмурится. Кроме того, вы можете подумать, почему вам нужно дублировать весь элемент DOM в первом место. Но вот:

// 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"

все элементы DOM работают таким образом. Например: <div></div> произведен HTMLDivElement, который простирается HTMLElement, что, в свою очередь, расширяет Element, что, в свою очередь, расширяет Object.


С replaceWith() не работал для меня на элементной основе (возможно, потому, что я использовал его внутри map()), Я сделал это, создав новый элемент и скопировав атрибуты по мере необходимости.

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

возьмите его за слово

принятые на вопрос "как изменить имя тега?"Я бы предложил такое решение:
Если это имеет смысл или нет, это должно решаться в каждом конкретном случае.

мой пример будет "переименовывать" все A-теги с гиперссылками для SMS с тегами span. Сохранение всех атрибутов и содержимого:

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

поскольку нет никакого смысла иметь тег span с атрибутом href, я удаляю это тоже. Это пуленепробиваемое и совместимые со всеми браузерами, которые поддерживаются jquery. Есть и другие способы, которыми люди пытаются скопировать все атрибуты в новый элемент, но они не совместимы со всеми браузерами.

хотя я думаю, что это довольно дорого, чтобы сделать это таким образом.


плагин Jquery, чтобы сделать" tagName " редактируемым:

(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);

см.:http://jsfiddle.net/03gcnx9v/3/


еще один скрипт для изменения имени узла

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/

он скопирует атрибуты и внутренний html в новый элемент, а затем заменит старый.


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

вы можете использовать эту функцию

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

пример кода

renameTag($(tr),'div');

вдохновленный ericP ответ, отформатированный и преобразованный в плагин jQuery:

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

использование:

$('div').replaceWithTag('span')