【问题标题】:How can I change an element's text without changing its child elements?如何在不更改子元素的情况下更改元素的文本?
【发布时间】:2011-05-05 15:25:34
【问题描述】:

我想动态更新元素的文本:

<div>
   **text to change**
   <someChild>
       text that should not change
   </someChild>
   <someChild>
       text that should not change
   </someChild>
</div>

我是 jQuery 新手,所以这个任务对我来说似乎很有挑战性。 有人可以指出我要使用的函数/选择器吗?

如果可能的话,我想在不为我需要更改的文本添加新容器的情况下这样做。

【问题讨论】:

  • “如果可能的话,我想在不为我需要更改的文本添加新容器的情况下这样做。” - 真的?因为里面有一个容器会容易得多。
  • 伙计们,我查看了原始问题,我认为 OP 没有说任何关于子元素的内容......
  • 根据 W3 标准,div 甚至不能有文本节点(如果我没记错的话)。应添加

    等文本容器。

  • @Mark:可能在 (X)HTML Strict 中,但不再是。 (HTML5 现在就在这里。)
  • @Matt Ball:在实际的 html 中,有 span 标签而不是 someChild。

标签: javascript html jquery


【解决方案1】:

Mark’s got a better solution using jQuery,但您也可以在常规 JavaScript 中执行此操作。

在 Javascript 中,childNodes 属性为您提供元素的所有子节点,包括文本节点。

因此,如果您知道要更改的文本始终是元素中的第一件事,那么给出例如这个 HTML:

<div id="your_div">
   **text to change**
   <p>
       text that should not change
   </p>
   <p>
       text that should not change
   </p>
</div>

你可以这样做:

var your_div = document.getElementById('your_div');

var text_to_change = your_div.childNodes[0];

text_to_change.nodeValue = 'new text';

当然,您仍然可以首先使用 jQuery 选择&lt;div&gt;(即var your_div = $('your_div').get(0);)。

【讨论】:

  • 无需替换文本节点。只需更改现有的 datanodeValue 属性即可。
  • @Tim:啊,我想一定有更简单的方法。在 jQuery 出现之前从来没有做过太多的 JavaScript。干杯,我会相应地编辑答案。
  • 所以这个答案的更新实现是$('#yourDivId')[0].childNodes[0].nodeValue = 'New Text';
  • "你也可以用普通的 javascript 做到这一点"
  • @duhaime 我打算添加一些类似的东西,但你的是我的男人!
【解决方案2】:

2018 年更新

由于这是一个非常受欢迎的答案,我决定通过将 textnode 选择器作为插件添加到 jQuery 来更新和美化它。

在下面的 sn-p 中,您可以看到我定义了一个新的 jQuery 函数,它获取所有(且仅)文本节点。您也可以使用 first() 函数链接此函数。 我对文本节点进行修剪并检查修剪后它是否不为空,因为空格、制表符、换行符等也被识别为文本节点。如果您也需要这些节点,那么只需从 jQuery 函数的 if 语句中删除它即可。

我添加了一个如何替换第一个文本节点以及如何替换所有文本节点的示例。

这种方法使代码更易于阅读,并且更易于多次用于不同目的。

如果您愿意,2017 年更新 (adrach) 应该仍然可以正常工作。

作为 jQuery 扩展

//Add a jQuery extension so it can be used on any jQuery object
jQuery.fn.textNodes = function() {
  return this.contents().filter(function() {
    return (this.nodeType === Node.TEXT_NODE && this.nodeValue.trim() !== "");
  });
}

//Use the jQuery extension
$(document).ready(function(){
  $('#replaceAll').on('click', () => {
    $('#testSubject').textNodes().replaceWith('Replaced');
  });

  $('#replaceFirst').on('click', () => {
    $('#testSubject').textNodes().first().replaceWith('Replaced First');
  });
});
p {
  margin: 0px;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="testSubject">
   **text to change**
   <p>text that should not change</p>
   <p>text that should not change</p>
   **also text to change**
   <p>text that should not change</p>
   <p>text that should not change</p>
   **last text to change**
</div>
<button id="replaceFirst">Replace First</button>
<button id="replaceAll">Replace All</button>

Javascript (ES) 等效

//Add a new function to the HTMLElement object so it cna be used on any HTMLElement
HTMLElement.prototype.textNodes = function() {
  return [...this.childNodes].filter((node) => {
    return (node.nodeType === Node.TEXT_NODE && node.nodeValue.trim() !== "");
  });
}

//Use the new HTMLElement function
document.addEventListener('DOMContentLoaded', () => {
  document.querySelector('#replaceAll').addEventListener('click', () => {
    document.querySelector('#testSubject').textNodes().forEach((node) => {
      node.textContent = 'Replaced';
    });
  });

  document.querySelector('#replaceFirst').addEventListener('click', function() {
    document.querySelector('#testSubject').textNodes()[0].textContent = 'Replaced First';
  });
});
p {
  margin: 0px;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="testSubject">
  **text to change**
  <p>text that should not change</p>
  <p>text that should not change</p>
  **also text to change**
  <p>text that should not change</p>
  <p>text that should not change</p>
  **last text to change**
</div>
<button id="replaceFirst">Replace First</button>
<button id="replaceAll">Replace All</button>

2017 年更新(adrach):

自发布此消息以来,似乎有几处发生了变化。这是一个更新的版本

$("div").contents().filter(function(){ return this.nodeType == 3; }).first().replaceWith("change text");

原始答案(不适用于当前版本)

$("div").contents().filter(function(){ return this.nodeType == 3; })
.filter(':first').text("change text");

来源:http://api.jquery.com/contents/

【讨论】:

  • 啊哈!我知道某处会有一个聪明的 jQuery 函数。您编写的解决方案的唯一问题是每个文本节点都会获得下一个文本(例如,包括子元素中的文本)。我想限制它不会太难吧?
  • 我在使用 .filter(':first') 时遇到了一些问题,但使用 .first() 反而对我有用。谢谢!
  • 这不适用于.text()(参见this jsfiddle),但适用于.replaceWith()jsfiddle here)。
  • 这对我有用,丑陋,因为它是 textObject = $(myNode).contents().filter(function(){ return this.nodeType == 3; })[0] $(textObject ).replaceWith("我的文字");
  • 任何对 nodeType=3 感兴趣的人,它是“TEXT”的均值过滤器节点类型,w3schools.com/jsref/prop_node_nodetype.asp 了解更多信息
【解决方案3】:

See In action

标记:

$(function() {
  $('input[type=button]').one('click', function() {
    var cache = $('#parent').children();
    $('#parent').text('Altered Text').append(cache);
  });
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="parent">Some text
  <div>Child1</div>
  <div>Child2</div>
  <div>Child3</div>
  <div>Child4</div>
</div>
<input type="button" value="alter text" />

【讨论】:

  • 迄今为止我遇到的最好的解决方案。优雅而简单。
  • 然而,这不会保留节点的顺序。例如如果文本首先位于元素的末尾,那么它现在将位于开头。
  • 它不会保留顺序,但在大多数情况下,您希望文本作为第一个或最后一个节点。所以如果 append() 没有得到想要的结果,如果你想让现有的子元素出现在文本前面,请尝试 prepend()。
  • 迄今为止最短最简单的解决方案 - stackoverflow.com/a/54365288/4769218
【解决方案4】:

只需将要更改的文本用要选择的类包装在跨度中即可。

不一定回答我知道的您的问题,但可能是更好的编码实践。保持干净和简单

<div id="header">
   <span class="my-text">**text to change**</span>
   <div>
       text that should not change
   </div>
   <div>
       text that should not change
   </div>
</div>

瞧!

$('#header .mytext').text('New text here')

【讨论】:

    【解决方案5】:
    <div id="divtochange">
        **text to change**
        <div>text that should not change</div>
        <div>text that should not change</div>
    </div>
    
    $(document).ready(function() {
        $("#divtochange").contents().filter(function() {
                return this.nodeType == 3;
            })
            .replaceWith("changed text");
    });
    

    这只会改变第一个文本节点

    【讨论】:

      【解决方案6】:

      对于你提到的具体情况:

      <div id="foo">
         **text to change**
         <someChild>
             text that should not change
         </someChild>
         <someChild>
             text that should not change
         </someChild>
      </div>
      

      ...这很容易:

      var div = document.getElementById("foo");
      div.firstChild.data = "New text";
      

      你没有说明你想如何概括这一点。例如,如果您想更改 &lt;div&gt; 中第一个文本节点的文本,您可以执行以下操作:

      var child = div.firstChild;
      while (child) {
          if (child.nodeType == 3) {
              child.data = "New text";
              break;
          }
          child = child.nextSibling;
      }
      

      【讨论】:

        【解决方案7】:

        $.fn.textPreserveChildren = function(text) {
          return this.each(function() {
            return $(this).contents().filter(function() {
              return this.nodeType == 3;
            }).first().replaceWith(text);
          })
        }
        
        setTimeout(function() {
          $('.target').textPreserveChildren('Modified');
        }, 2000);
        .blue {
          background: #77f;
        }
        .green {
          background: #7f7;
        }
        <script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.0/jquery.min.js"></script>
        
        <div class="target blue">Outer text
          <div>Nested element</div>
        </div>
        
        <div class="target green">Another outer text
          <div>Another nested element</div>
        </div>

        【讨论】:

          【解决方案8】:

          简单回答:

          $("div").contents().filter(function(){ 
            return this.nodeType == 3; 
          })[0].nodeValue = "The text you want to replace with"
          

          【讨论】:

            【解决方案9】:

            这是还有另一种方法:http://jsfiddle.net/qYUBp/7/

            HTML

            <div id="header">
               **text to change**
               <div>
                   text that should not change
               </div>
               <div>
                   text that should not change
               </div>
            </div>
            

            JQUERY

            var tmp=$("#header>div").html();
            $("#header").text("its thursday").append(tmp);
            

            【讨论】:

              【解决方案10】:

              这里有很多很棒的答案,但它们只处理一个带有子节点的文本节点。在我的情况下,我需要对所有文本节点进行操作并忽略 html 子节点但保留顺序。

              如果我们遇到这样的情况:

              <div id="parent"> Some text
                  <div>Child1</div>
                  <div>Child2</div>
                  and some other text
                  <div>Child3</div>
                  <div>Child4</div>
                  and here we are again
              </div>
              

              我们可以使用以下代码仅修改文本并保留顺序

                  $('#parent').contents().filter(function() {
                      return this.nodeType == Node.TEXT_NODE && this.nodeValue.trim() != '';
                  }).each(function() {
                  		//You can ignore the span class info I added for my particular application.
                      $(this).replaceWith(this.nodeValue.replace(/(\w+)/g,"<span class='IIIclassIII$1' onclick='_mc(this)' onmouseover='_mr(this);' onmouseout='_mt(this);'>$1X</span>"));
              	});
              <script src="https://code.jquery.com/jquery-3.0.0.min.js"></script>
              <div id="parent"> Some text
                  <div>Child1</div>
                  <div>Child2</div>
                  and some other text
                  <div>Child3</div>
                  <div>Child4</div>
                  and here we are again
              </div>

              这是它的jsfiddle 工作

              【讨论】:

                【解决方案11】:

                我认为您正在寻找 .prependTo()。

                http://api.jquery.com/prependTo/

                我们也可以在 页面并将其插入另一个页面:

                $('h2').prependTo($('.container'));

                如果以这种方式选择的元素是 插入其他地方,它将被移动 进入目标(未克隆):

                <div class="container">  
                  <h2>Greetings</h2>
                  <div class="inner">Hello</div>
                  <div class="inner">Goodbye</div> 
                </div>
                

                如果有多个目标 元素,但是,克隆的副本 将创建插入的元素 第一个目标之后的每个目标。

                【讨论】:

                • 我认为不是。听起来 OP 正在寻找一种方法来更改文本,而不是添加新文本。
                【解决方案12】:

                马克回答的问题是你也得到了空的文本节点。 jQuery插件解决方案:

                $.fn.textnodes = function () {
                    return this.contents().filter(function (i,n) {
                        return n.nodeType == 3 && n.textContent.trim() !== "";
                    });
                };
                
                $("div").textnodes()[0] = "changed text";
                

                【讨论】:

                  【解决方案13】:

                  这是一个老问题,但您可以制作这样一个简单的函数来让您的生活更轻松:

                  $.fn.toText = function(str) {
                      var cache = this.children();
                      this.text(str).append(cache);
                  }
                  

                  例子:

                  <div id="my-div">
                     **text to change**
                     <p>
                         text that should not change
                     </p>
                     <p>
                         text that should not change
                     </p>
                  </div>
                  

                  用法:

                  $("#my-div").toText("helloworld");
                  

                  【讨论】:

                    【解决方案14】:

                    2019 版 - 短而简单

                    document.querySelector('#your-div-id').childNodes[0].nodeValue = 'new text';
                    

                    解释

                    document.querySelector('#your-div-id') 用于选择父元素(您要更改文本的元素)

                    .childNodes[0]选择文本节点

                    .nodeValue = 'new text' 将文本节点值设置为“新文本”


                    这个答案可能是受到 Dean Martin 评论的启发。不能肯定地说,因为我多年来一直在使用这个解决方案。只是想我应该在这里发布这个概率,因为有些人更关心它而不是这是最好的解决方案。

                    【讨论】:

                    • 您刚刚复制了 Dean Martin 2014 年的评论,并声称这是您 2019 年的解决方案。还要使用 jQuery 和纯 Javascript 的不必要组合,在我看来,这对于良好的可读性来说是不好的做法。最后,您没有提供有关您的解决方案如何工作的任何详细信息。这不是最复杂的,但也不是最复杂的问题,所以可能是读过这篇文章的新手程序员可以使用一些额外的解释,例如通过访问数组索引从 jQuery 对象获取本机 DOM 节点。
                    • @MarkBaijens 我认为你可能是对的,Dean Martin 的评论可能是我多年前得到这个 sn-p 的地方。无论如何,从那以后我就一直在使用它,并在一月份从我的个人代码仓库(我列出了有用的脚本)中复制了它。添加了更详细的解释并删除了不必要的jQuery。
                    • 这是迄今为止最简单的解决方案,它确实有效,人们应该使用它,尽管你不会因为不感谢 Dean Martin 而把它当成自己的东西而获得任何荣誉。我也同意 Mark Ba​​ijens 的观点,在这种情况下纯 Vanilla JS 实现比混合 jQuery 和 Vanilla JS 更好。不仅是为了更好的可读性,也是为了更好的性能,因为 jQuery 减慢了速度。
                    • @Miqi180 - 正如我上面已经说过的,这是可能的,我不记得我第一次得到这个解决方案的地方。多年来,我一直在工作中使用它。在答案中添加了注释。希望它可以帮助像您这样不关心 SO 上的最佳解决方案的人:
                    【解决方案15】:

                    Javascript 方法。选择父div,我们可以使用firstChild.textContent

                    let myDiv = document.getElementById("parentDiv");
                    myDiv.firstChild.textContent = "** New Text **"
                    

                    【讨论】:

                    • 这只有在 html 元素中已经存在文本时才有效
                    猜你喜欢
                    • 2020-09-13
                    • 2017-01-29
                    • 1970-01-01
                    • 1970-01-01
                    • 2011-10-30
                    • 1970-01-01
                    • 2016-05-20
                    • 1970-01-01
                    相关资源
                    最近更新 更多