如何在JavaScript中获取没有子元素的元素文本?

21

如何获取元素的文本内容而不包括其子元素?
似乎 element.textContentelement.innerText 都无法正常工作。

HTML:

<body>
<h1>Test Heading</h1>
<div>
Awesome video and music. Thumbs way up. Love it. Happy weekend to you and your family. Love, Sasha
</div>
</body>
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.6.4/jquery.min.js"></script>
<script type="text/javascript">
    fool("body");
</script>

这里是 fool 函数:

jQuery.fn.justtext = function(text) {
    return $(this).clone()
    .children()
    .remove()
    .end()
    .text();
};

function fool(el) { 

    reverse(el);

    function reverse(el) {
        $(el).children().each(function() {
            if($(this).children().length > 0) {
                reverse(this);
                if($(this).justtext() != "")
                    reverseText(this);
            } else {
               reverseText(this)
            }
        });
    }

    function reverseText(el){
        var text = el.textContent;
        var frag = text.toString().split(/ /);
        var foo = "";
        var punctation_marks = [".",",","?","!"," ",":",";"];
        for(i in frag){
            if(punctation_marks.indexOf(frag[i]) == -1)
                foo += actualReverse(frag[i],punctation_marks) + " ";
        }
        el.textContent = foo;
    }

    function actualReverse(text,punctation_marks) {
        return (punctation_marks.indexOf(text.split("")[text.split("").length-1]) != -1)?text.split("").slice(0,text.split("").length-1).reverse().join("") + text.split("")[text.split("").length-1] : text.split("").reverse().join("");
    }
}
编辑: 使用node.nodeType并不能真正解决问题,原因如下: 想象一下以下的HTML代码。
<td class="gensmall">
    Last visit was: Sat Mar 31, 2012 10:50 am
    <br>
    <a href="./search.php?search_id=unanswered">View unanswered posts</a> | <a href="./search.php?search_id=active_topics">View active topics</a>
</td>

如果我使用nodeType,只有a元素的文本会改变,而不是td本身(“上次访问...”)。

有代码吗?你的选择器可能是错误的,当.textContentinnerText为空时,element不包含任何内容。 - Rob W
你说的“without children”具体是什么意思? - Pointy
@Pointy 我只想要(与上一个例子相关的 - td单元格)“最后访问时间是:2012年3月31日上午10:50”而不带锚点中的文本。 - Nik
所以您想要节点的文本内容以及其所有后代节点吗?看到“without children”这部分让我想到您想要跳过后代节点。 - Pointy
是的,但您想要后代中的文本,对吗? - Pointy
显示剩余2条评论
4个回答

30

只需找到文本节点:

var element = document.getElementById('whatever'), text = '';
for (var i = 0; i < element.childNodes.length; ++i)
  if (element.childNodes[i].nodeType === Node.TEXT_NODE)
    text += element.childNodes[i].textContent;

编辑 — 如果你希望获取子节点中的文本,而且(正如现在所见)你在使用jQuery:

$.fn.allText = function() {
  var text = '';
  this.each(function() {
    $(this).contents().each(function() {
      if (this.nodeType == Node.TEXT_NODE)
        text += this.textContent;
      else if (this.nodeType == Node.ELEMENT_NODE)
        text += $(this).allText();
    });
  });
  return text;
};

稍等,我会测试一下 :-) (好像可以运行)


5
我建议使用 Node.TEXT_NODE 而不是 "3",因为它更易读。 - Johannes Egger
1
可能还需要递归遍历非文本节点以查找它们包含的文本节点。(例如:表格单元格) - David-SkyMesh
@David-SkyMesh: 这正是我的问题。我已经编辑了我的问题。 - Nik
@Pointy 的答案基本正确。编写一个名为 getText() 的函数,执行他所写的操作(FOR 和 IF),但在 IF 中添加一个 ELSE 情况,该情况对 elements.childNodes[i] 调用getText() 递归。 - David-SkyMesh
1
如果非文本节点的元素为文本提供结构(例如:表格行),您可能还希望解释这些元素(例如:在结果文本中插入“\n”)。 - David-SkyMesh
显示剩余2条评论

7

这段代码以更加表达性和函数化的方式实现了与其他两个答案相同的结果。在所有现代浏览器(IE9及以上版本)中都支持filtermap数组方法。

由于其他答案已经有些过时,因此我在这里加上这一点。

var content = Array.prototype.filter.call(element.childNodes, function (element) {
    return element.nodeType === Node.TEXT_NODE;
}).map(function (element) {
    return element.textContent;
}).join("");

1
使用箭头函数:Array.prototype.filter.call(ELEMENT.childNodes, e => e.nodeType === Node.TEXT_NODE).map(e => e.textContent).join(''); - Mateusz Budzisz

6

元素的文本也是一个独立的节点。 考虑下面这段代码:

<span>
    Some text
    <span>Inner text</span>
    More text
    <span>More inner text</span>
    Even more text
</span>

当你说想要元素的文本时,现在你的意思是什么?只需要直接的孩子元素吗?

那么这段代码可能会有帮助:

for (var element in elements) {
    if (element.nodeType == Node.TEXT_NODE) {
        // do something
    }
}

2
除了像Pointy这样的答案外,处理换行符<br/>的方法可以如下所示:
txt = '';
for (var i = 0; i < element.childNodes.length; ++i)
    if (element.childNodes[i].nodeType == 3) {
        txt += element.childNodes[i].textContent;
    } else if (element.childNodes[i].nodeType == 1) {
        name = element.childNodes[i].nodeName || element.childNodes[i].tagName || '';
        if (name.toUpperCase() == 'BR') {
            txt += '\n';
        }
    }
return txt;

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