JS. 如何使用字符串表示法替换HTML元素为另一个元素/文本?

44

我在替换HTML元素方面遇到了问题。

例如,这里有一个表格:

<table>
    <tr>
        <td id="idTABLE">0</td>
        <td>END</td>
    </tr>
</table>

(可以是div、span或任何标签)

JavaScript中的字符串:

var str = '<td>1</td><td>2</td>';

(它可以是任何东西,123 文本<span>123 元素</span> 456<tr><td>123</td> 或其他任何内容)

我如何用 str 替换元素 idTABLE

所以:

<table>
    <tr>
        <td id="idTABLE">0</td>
        <td>END</td>
    </tr>
</table>

成为:

<table>
    <tr>
        <td>1</td>
        <td>2</td>
        <td>END</td>
    </tr>
</table> 
<!-- str = '<td>1</td><td>2</td>'; -->

<table>
    <tr>
        123 text
        <td>END</td>
    </tr>
</table>
<!-- str = '123 text' -->

<table>
    <tr> 
        <td>123</td> 
        <td>END</td>
    </tr>
</table>
<!-- str = '<td>123</td>' -->

我尝试过使用createElementreplaceChildcloneNode,但是都没有任何结果=(


我不知道你的意思,但你可以非常简单地使用createElement创建一个div,然后设置它的innerHTML属性。如果可以的话,我建议使用jquery来完成这个任务。例如:$('<table></table>').append($('<tr><td>1</td><td>2</td></tr>'))等等。在DOM操作中,你有很大的灵活性。 - Eli Gassert
并非总是可行的。例如,当创建一个 div 并将其 innerHTML 设置为 '<td>123</td>' 时,这个 div 就变成了 '<div>123</div>'(js 会丢弃不适当的 td 标签)。 - el Dude
海报没有提到jQuery,也不需要这样做。 - Jonathan Cross
7个回答

69

由于JQuery的replaceWith()代码过于庞大、棘手和复杂,所以这是我的解决方案。=)

最好的方法是使用outerHTML属性,但它还没有兼容所有浏览器,所以我用了一些技巧,虽然有点奇怪,但简单。

下面是代码:

    var str = '<a href="http://www.com">item to replace</a>'; //it can be anything
    var Obj = document.getElementById('TargetObject'); //any element to be fully replaced
    if(Obj.outerHTML) { //if outerHTML is supported
        Obj.outerHTML=str; ///it's simple replacement of whole element with contents of str var
    }
    else { //if outerHTML is not supported, there is a weird but crossbrowsered trick
        var tmpObj=document.createElement("div");
        tmpObj.innerHTML='<!--THIS DATA SHOULD BE REPLACED-->';
        ObjParent=Obj.parentNode; //Okey, element should be parented
        ObjParent.replaceChild(tmpObj,Obj); //here we placing our temporary data instead of our target, so we can find it then and replace it into whatever we want to replace to
        ObjParent.innerHTML=ObjParent.innerHTML.replace('<div><!--THIS DATA SHOULD BE REPLACED--></div>',str);
    }

就是这样


10
我相信对于大多数现代应用程序,你现在可以安全地使用 outerHTML:https://caniuse.com/#search=outerHTML - theFreedomBanana
1
同意,我们可以安全地省略 outerHTMLif 语句。相关文章:如何使用原生JS替换元素及其内容 - Adam Johnson

11
使用jQuery可以做到这一点:
var str = '<td>1</td><td>2</td>';
$('#__TABLE__').replaceWith(str);

http://jsfiddle.net/hZBeW/4/

或者使用纯javascript:

var str = '<td>1</td><td>2</td>';
var tdElement = document.getElementById('__TABLE__');
var trElement = tdElement.parentNode;
trElement.removeChild(tdElement);
trElement.innerHTML = str + trElement.innerHTML;

http://jsfiddle.net/hZBeW/1/


第一眼看起来好像它能工作 =)。谢谢,我会尝试你的示例。 - el Dude
但它只适用于第一个元素。在<table><tr><td>start</td><td id="__TABLE__">0</td><td>END</td></tr></table>中,它的工作不正确。 - el Dude
1
这是正确的。在那种情况下,纯JavaScript方法行不通。jQuery版本可以。我认为pebbl的答案#13388745看起来像一个很好的纯JavaScript解决方案。 - 3dgoo
@EL2002,听起来你在某些情况下尝试实现的目标实际上是不可能的(我已经相应地更新了我的答案)......如果你试图添加非法的HTML代码,那么这就是我所假设的。感谢3dgoo,你的答案对于最初给出的示例是完全正确的解决方案 :) - Pebbl
@3dgoo:好的,如果你说JQ可以做到,我会尝试从JQ库中提取replaceWith()函数。感谢你的帮助。 - el Dude

11

因为你在谈论替换任何东西,而且是在元素的子级中间进行替换,所以比仅仅插入单个元素或直接删除和添加要复杂得多:

function replaceTargetWith( targetID, html ){
  /// find our target
  var i, tmp, elm, last, target = document.getElementById(targetID);
  /// create a temporary div or tr (to support tds)
  tmp = document.createElement(html.indexOf('<td')!=-1?'tr':'div'));
  /// fill that div with our html, this generates our children
  tmp.innerHTML = html;
  /// step through the temporary div's children and insertBefore our target
  i = tmp.childNodes.length;
  /// the insertBefore method was more complicated than I first thought so I 
  /// have improved it. Have to be careful when dealing with child lists as  
  /// they are counted as live lists and so will update as and when you make
  /// changes. This is why it is best to work backwards when moving children 
  /// around, and why I'm assigning the elements I'm working with to `elm` 
  /// and `last`
  last = target;
  while(i--){
    target.parentNode.insertBefore((elm = tmp.childNodes[i]), last);
    last = elm;
  }
  /// remove the target.
  target.parentNode.removeChild(target);
}

示例用法:

replaceTargetWith( 'idTABLE', 'I <b>can</b> be <div>anything</div>' );

示例:

通过使用临时div的.innerHTML,这将生成我们需要插入的TextNodesElements而无需费力。但与其插入临时div本身--这会给我们带来不想要的标记--我们只需扫描并插入其子元素。

...或者考虑使用jQuery及其replaceWith方法。

jQuery('#idTABLE').replaceWith('<blink>Why this tag??</blink>');


更新 2012/11/15

针对 EL 2002 上面的评论作出回应:

  

这并非总是可能的。例如,当使用 createElement('div') 并将其 innerHTML 设置为 <td>123</td> 时,此 div 就会变成 <div>123</div> (js 会丢弃不适当的 td 标签)。

以上问题显然也否定了我的解决方案 - 我已相应地更新了上面的代码(至少对于 td 问题)。但是对于某些 HTML,无论您做什么,都会发生这种情况。所有用户代理程序都通过其自己的解析规则解释 HTML,但几乎所有用户代理程序都会尝试自动纠正错误的 HTML。实现您所说的内容的唯一方法 (在您的一些示例中) 是将 HTML 完全从 DOM 中删除,并将其作为字符串进行操作。这将是实现具有以下特征的标记字符串的唯一方法 (jQuery 也无法解决此问题)

<table><tr>123 text<td>END</td></tr></table>

如果您将此字符串注入到DOM中,根据浏览器的不同,您将获得以下内容:

123 text<table><tr><td>END</td></tr></table>

<table><tr><td>END</td></tr></table>

唯一的问题是为什么你首先想要实现破碎的HTML呢? :)


3

这并非总是可行的。例如,当创建一个元素为<div>并将其innerHTML设置为'<td>123</td>'时,此div会变成'<div>123</div>'(js会丢弃不合适的td标签)。 - el Dude
如果您可以使用jQuery,那么.append函数将不会像您描述的那样工作。我会添加到答案中,但是我理解您可能无法使用它。 - Martin Lyne

1
如果您需要实际替换您从DOM中选择的td,则需要先转到parentNode,然后用表示您想要的新html字符串替换innerHTML。诀窍是将第一个表格单元格转换为字符串,以便您可以在字符串替换方法中使用它。
我添加了一个fiddle示例:http://jsfiddle.net/vzUF4/
<table><tr><td id="first-table-cell">0</td><td>END</td></tr></table>

<script>
  var firstTableCell = document.getElementById('first-table-cell');
  var tableRow = firstTableCell.parentNode;
  // Create a separate node used to convert node into string.
  var renderingNode = document.createElement('tr');
  renderingNode.appendChild(firstTableCell.cloneNode(true));
  // Do a simple string replace on the html
  var stringVersionOfFirstTableCell = renderingNode.innerHTML;
  tableRow.innerHTML = tableRow.innerHTML.replace(stringVersionOfFirstTableCell,
    '<td>0</td><td>1</td>');
</script>

这里的复杂性在于您混合使用了DOM方法和字符串方法。 如果DOM方法适用于您的应用程序,最好使用它们。 您也可以使用纯DOM方法(document.createElement、removeChild、appendChild)来完成此操作,但需要更多的代码行数,而且您的问题明确表示您想使用字符串。


结果是:<table><tr><td>0</td><td>1</td></tr></table>和<td>END</td>将会丢失。 - el Dude
啊,是的,谢谢EL 2002。我没明白我们想要保留END,所以我们要把一个两列的表格变成三列的。我会更新示例。 - Jonathan Cross

1

在这种情况下,您的输入过于模糊。您的代码必须知道它是应该将文本原样插入还是解析一些HTML标记(或以其他方式得到不良HTML)。这是您可以通过调整提供的输入来避免的不必要的复杂性。

如果无法避免混乱的输入,则没有一些复杂的解析(最好是在单独的函数中),您可能会得到一些不良的HTML(就像您在第二个示例中所做的那样...这是不好的,对吧?)。

我猜您想要一个将列插入1行表格的函数。在这种情况下,您的内容应作为数组传递(不带table、tr、td标记)。每个数组元素将是一列。

HTML

<table id="__TABLE__"><tr><td></td></tr></table>

JS

使用jQuery来简化代码...

function insert_columns (columns)
{
    var $row = $('<tr></tr>');

    for (var i = 0; i < columns.length; i++)
        $row.append('<td>'+columns[i]+'</td>');

    $('#__TABLE__').empty(); // remove everything inside

    $('#__TABLE__').append($row);
}

那么...

insert_columns(['hello', 'there', 'world']);

结果

<table id="__TABLE__"><tr><td>hello</td><td>there</td><td>world</td></tr></table>

-2

使用属性 "innerHTML"

以某种方式选择表格:

var a = document.getElementById('table, div, whatever node, id')
a.innerHTML = your_text

3
我意思是替换整个元素,而不是它的innerHTML。 - el Dude

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接