使用.text()仅检索未嵌套在子标记中的文本

时间:2010-08-09 17:07:24

标签: jquery text tags

如果我有这样的HTML:

<li id="listItem">
    This is some text
    <span id="firstSpan">First span text</span>
    <span id="secondSpan">Second span text</span>
</li>

我正在尝试使用.text()来检索字符串“这是一些文本”,但如果我要说$('#list-item').text(),我会得到“这是一些textFirst span text secondSecond span text”

是否有办法获取(并可能通过.text("")之类的内容删除标签内的自由文本,而不是其子标签中的文字?

HTML不是我写的,所以这就是我必须要处理的。我知道在编写html时将文本包装在标签中会很简单,但同样,html是预先编写的。

26 个答案:

答案 0 :(得分:481)

我喜欢这个基于找到hereclone()方法的可重用实现,只获取父元素中的文本。

提供代码以便于参考:

$("#foo")
    .clone()    //clone the element
    .children() //select all the children
    .remove()   //remove all the children
    .end()  //again go back to selected element
    .text();

答案 1 :(得分:334)

简单回答:

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

答案 2 :(得分:128)

这似乎是一个过度使用jquery的情况。以下内容将获取忽略其他节点的文本:

document.getElementById("listItem").childNodes[0];

你需要修剪它,但它可以在一条简单的线条中找到你想要的东西。

修改

以上将获得文本节点。要获取实际文本,请使用:

document.getElementById("listItem").childNodes[0].nodeValue;

答案 3 :(得分:57)

更轻松,更快捷:

$("#listItem").contents().get(0).nodeValue

答案 4 :(得分:26)

与接受的答案类似,但没有克隆:

$("#foo").contents().not($("#foo").children()).text();

这是一个用于此目的的jQuery插件:

$.fn.immediateText = function() {
    return this.contents().not(this.children()).text();
};

以下是如何使用此插件:

$("#foo").immediateText(); // get the text without children

答案 5 :(得分:8)

试试这个:

$('#listItem').not($('#listItem').children()).text()

答案 6 :(得分:7)

不是代码:

var text  =  $('#listItem').clone().children().remove().end().text();

为了jQuery而成为jQuery的缘故?当简单的操作涉及许多链式命令&amp;那么多(不必要的)处理,也许是编写jQuery扩展的时候了:

(function ($) {
    function elementText(el, separator) {
        var textContents = [];
        for(var chld = el.firstChild; chld; chld = chld.nextSibling) {
            if (chld.nodeType == 3) { 
                textContents.push(chld.nodeValue);
            }
        }
        return textContents.join(separator);
    }
    $.fn.textNotChild = function(elementSeparator, nodeSeparator) {
    if (arguments.length<2){nodeSeparator="";}
    if (arguments.length<1){elementSeparator="";}
        return $.map(this, function(el){
            return elementText(el,nodeSeparator);
        }).join(elementSeparator);
    }
} (jQuery));

致电:

var text = $('#listItem').textNotChild();

参数用于遇到不同的场景,例如

<li>some text<a>more text</a>again more</li>
<li>second text<a>more text</a>again more</li>

var text = $("li").textNotChild(".....","<break>");

文字将有价值:

some text<break>again more.....second text<break>again more

答案 7 :(得分:6)

它需要根据需要量身定制,这取决于您所呈现的结构。对于您提供的示例,这有效:

$(document).ready(function(){
     var $tmp = $('#listItem').children().remove();
     $('#listItem').text('').append($tmp);
});

演示:http://jquery.nodnod.net/cases/2385/run

但它完全依赖于标记与您发布的内容类似。

答案 8 :(得分:4)

$($('#listItem').contents()[0]).text()

Stuart answer.

的简短变体

get()

$($('#listItem').contents().get(0)).text()

答案 9 :(得分:3)

jQuery.fn.ownText = function () {
    return $(this).contents().filter(function () {
        return this.nodeType === Node.TEXT_NODE;
    }).text();
};

答案 10 :(得分:2)

这是一个老问题,但最重要的答案效率很低。这是一个更好的解决方案:

$.fn.myText = function() {
    var str = '';

    this.contents().each(function() {
        if (this.nodeType == 3) {
            str += this.textContent || this.innerText || '';
        }
    });

    return str;
};

就这样做:

$("#foo").myText();

答案 11 :(得分:2)

我认为这也是一个很好的解决方案 - 如果你想获得所有文本节点的内容,它们是所选元素的直接子节点。

$(selector).contents().filter(function(){ return this.nodeType == 3; }).text();

注意:jQuery文档使用类似的代码来解释内容函数:https://api.jquery.com/contents/

P.S。还有一些更丑陋的方法可以做到这一点,但这更深入地展示了工作原理,并允许文本节点之间的自定义分隔符(可能你想在那里换行)

$(selector).contents().filter(function(){ return this.nodeType == 3; }).map(function() { return this.nodeValue; }).toArray().join("");

答案 12 :(得分:1)

不确定要涵盖的灵活性或数量,但是在您的示例中,如果文本始终位于第一个HTML标记之前–为什么不将内部html拆分为第一个标记并采用前一个标记:< / p>

$('#listItem').html().split('<span')[0]; 

如果您需要更宽的范围,可能只是

$('#listItem').html().split('<')[0]; 

,如果您需要两个标记之间的文本(例如在一件事之后但又在另一件事之前),则可以执行(未测试)之类的操作,并使用if语句使其具有足够的灵活性以包含开始标记或结束标记或同时使用两者,同时避免空引用错误:

var startMarker = '';// put any starting marker here
var endMarker = '<';// put the end marker here
var myText = String( $('#listItem').html() );
// if the start marker is found, take the string after it
myText = myText.split(startMarker)[1];        
// if the end marker is found, take the string before it
myText = myText.split(endMarker)[0];
console.log(myText); // output text between the first occurrence of the markers, assuming both markers exist.  If they don't this will throw an error, so some if statements to check params is probably in order...

我通常使实用程序函数用于诸如此类的有用的事情,使它们无错误,然后可靠地频繁使用它们,而不是总是重写这种类型的字符串操作并冒空引用等的危险。这样,您可以在许多项目中使用该函数,而不必再浪费时间在调试字符串引用为何具有未定义的引用错误的原因上。可能不是有史以来最短的1行代码,但是拥有实用程序功能后,此后就是一行。注意,大多数代码只是在处理是否存在参数,以避免出现错误:)

例如:

/**
* Get the text between two string markers.
**/
function textBetween(__string,__startMark,__endMark){
    var hasText = typeof __string !== 'undefined' && __string.length > 0;
    if(!hasText) return __string;
    var myText = String( __string );
    var hasStartMarker = typeof __startMark !== 'undefined' && __startMark.length > 0 && __string.indexOf(__startMark)>=0;
    var hasEndMarker =  typeof __endMark !== 'undefined' && __endMark.length > 0 && __string.indexOf(__endMark) > 0;
    if( hasStartMarker )  myText = myText.split(__startMark)[1];
    if( hasEndMarker )    myText = myText.split(__endMark)[0];
    return myText;
}

// now with 1 line from now on, and no jquery needed really, but to use your example:
var textWithNoHTML = textBetween( $('#listItem').html(), '', '<'); // should return text before first child HTML tag if the text is on page (use document ready etc)

答案 13 :(得分:1)

如果文本节点的位置index在其兄弟姐妹之间固定,则可以使用

$('parentselector').contents().eq(index).text()

答案 14 :(得分:0)

Live demo

<li id="listItem">
    This is some text
    <span id="firstSpan">First span text</span>
    <span id="secondSpan">Second span text</span>
</li>

<input id="input" style="width: 300px; margin-top: 10px;">

    <script type="text/javascript">
$("#input").val($("#listItem").clone().find("span").remove().end().text().trim());
    //use .trim() to remove any white space
    </script>

答案 15 :(得分:0)

仅几行使用IE 9+兼容语法中的纯JavaScript:

let children = document.querySelector('#listItem').childNodes;

if (children.length > 0) {
    childrenLoop:
    for (var i = 0; i < children.length; i++) {
        //only target text nodes (nodeType of 3)
        if (children[i].nodeType === 3) {
            //do not target any whitespace in the HTML
            if (children[i].nodeValue.trim().length > 0) {
                children[i].nodeValue = 'Replacement text';
                //optimized to break out of the loop once primary text node found
                break childrenLoop;
            }
        }
    }
}

答案 16 :(得分:0)

我想出了一个特定的解决方案,它应该比克隆和修改克隆更有效。此解决方案仅适用于以下两个保留,但应该比当前接受的解决方案更有效:

  1. 您只收到文字
  2. 要提取的文本位于子元素
  3. 之前

    话虽如此,这是代码:

    // 'element' is a jQuery element
    function getText(element) {
      var text = element.text();
      var childLength = element.children().text().length;
      return text.slice(0, text.length - childLength);
    }
    

答案 17 :(得分:0)

只需将其放入<p><font>并抓取$('#listItem font')。text()

首先想到的是

<li id="listItem">
    <font>This is some text</font>
    <span id="firstSpan">First span text</span>
    <span id="secondSpan">Second span text</span>
</li>

答案 18 :(得分:0)

就像问题一样,我试图提取文本以便对文本进行一些正则表达式替换,但是我的内部元素(即:<i><div>,{{1也被删除了。

以下代码似乎运行良好并解决了我所有的问题。

它使用了此处提供的一些答案,但特别是,只有当元素为<span>时才会替换文本。

nodeType === 3

上面所做的是循环遍历给定$(el).contents().each(function() { console.log(" > Content: %s [%s]", this, (this.nodeType === 3)); if (this.nodeType === 3) { var text = this.textContent; console.log(" > Old : '%s'", text); regex = new RegExp("\\[\\[" + rule + "\\.val\\]\\]", "g"); text = text.replace(regex, value); regex = new RegExp("\\[\\[" + rule + "\\.act\\]\\]", "g"); text = text.replace(regex, actual); console.log(" > New : '%s'", text); this.textContent = text; } }); 的所有元素(简单地用el获得。对于每个内部元素,它基本上忽略它们。对于每个文本部分(如由$("div.my-class[name='some-name']");确定,它将仅对这些元素应用正则表达式替换。

if (this.nodeType === 3)部分只是替换替换文字,在我的情况下,我正在寻找像this.textContent = text[[min.val]]等标记。

这段简短的代码摘录将有助于任何人尝试做出问题所要求的......还有更多。

答案 19 :(得分:0)

我建议使用createTreeWalker查找未附加到html元素的所有文本元素(此函数可用于扩展jQuery):

&#13;
&#13;
function textNodesOnlyUnder(el) {
  var resultSet = [];
  var n = null;
  var treeWalker  = document.createTreeWalker(el, NodeFilter.SHOW_TEXT, function (node) {
    if (node.parentNode.id == el.id && node.textContent.trim().length != 0) {
      return NodeFilter.FILTER_ACCEPT;
    }
    return NodeFilter.FILTER_SKIP;
  }, false);
  while (n = treeWalker.nextNode()) {
    resultSet.push(n);
  }
  return resultSet;
}



window.onload = function() {
  var ele = document.getElementById('listItem');
  var textNodesOnly = textNodesOnlyUnder(ele);
  var resultingText = textNodesOnly.map(function(val, index, arr) {
    return 'Text element N. ' + index + ' --> ' + val.textContent.trim();
  }).join('\n');
  document.getElementById('txtArea').value = resultingText;
}
&#13;
<li id="listItem">
    This is some text
    <span id="firstSpan">First span text</span>
    <span id="secondSpan">Second span text</span>
</li>
<textarea id="txtArea" style="width: 400px;height: 200px;"></textarea>
&#13;
&#13;
&#13;

答案 20 :(得分:-1)

你可以试试这个

alert(document.getElementById('listItem').firstChild.data)

答案 21 :(得分:-1)

为了能够修剪结果,请使用DotNetWala,如下所示:

$("#foo")
    .clone()    //clone the element
    .children() //select all the children
    .remove()   //remove all the children
    .end()  //again go back to selected element
    .text()
    .trim();

我发现使用像document.getElementById("listItem").childNodes[0]这样的较短版本不能使用jQuery&#39的修饰()。

答案 22 :(得分:-1)

这对我来说是个好方法

   var text  =  $('#listItem').clone().children().remove().end().text();

答案 23 :(得分:-2)

使用额外条件检查innerHTML和innerText是否相同。仅在这些情况下,替换文本。

$(function() {
$('body *').each(function () {
    console.log($(this).html());
    console.log($(this).text());
    if($(this).text() === "Search" && $(this).html()===$(this).text())  {
        $(this).html("Find");
    }
})
})

http://jsfiddle.net/7RSGh/

答案 24 :(得分:-3)

我不是jquery专家,但是怎么样,

$('#listItem').children().first().text()

答案 25 :(得分:-4)

这是未经测试的,但我认为您可以尝试这样的事情:

 $('#listItem').not('span').text();

http://api.jquery.com/not/