如果我有这样的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 textSecond span文本”。

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

HTML不是我写的,所以这是我必须与工作。我知道这将是简单的,只是包装标签的文本时编写的html,但再次,html是预先编写的。


当前回答

我建议使用createTreeWalker来查找所有没有附加到html元素的文本元素(这个函数可以用来扩展jQuery):

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

其他回答

使用简单的JavaScript在IE 9+兼容语法在短短几行:

const childNodes = document.querySelector('#listItem').childNodes;

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

这是一个老问题,但上面的答案效率很低。这里有一个更好的解决方案:

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

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

    return str;
};

然后这样做:

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

就像问题一样,我试图提取文本,以便对文本进行一些正则表达式替换,但在我的内部元素(即:< I >, <div>, <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),它将只对这些元素应用regex替换。

这。textContent = text部分只是替换替换的文本,在我的情况下,我正在寻找像[[min.val]], [[max.]]这样的标记。val]]等。

这段简短的代码摘录将帮助任何人试图做什么问题是问…再多一点。

在2022年获取一个元素中的所有文本而没有任何子元素中的文本似乎仍然不是简单的事情。 但是不需要jQuery。

获取所有原始文本节点(s)内容:

const getElementTextWithoutChildElements = (el) =>
  Array.from(el.childNodes)               // iterator to array
    .filter(node => node.nodeType === 3)  // only text nodes
    .map(node => node.textContent)        // get text
    .join('')                             // stick together
;

或者类似的,使用reduce:

const getElementTextWithoutChildElements = (el) =>
  [].reduce.call(
    el.childNodes, 
    (a, b) => a + (b.nodeType === 3 ? b.textContent : ''),
    ''
  );

应该这样做:

<div>
  you get this
  <b>not this</b>
  you get this   too
</div>

将返回:


  you get this

  you get this   too

元素之间的空白可能很棘手,建议使用.trim()和/或规范化所有空白。 对于调试和记录快速识别元素,我发现这通常是足够的:

getElementTextWithoutChildElements(...).replace(/\s+/g, ' ').trim();
// 'you get this you get this too'

尽管您可能希望以不同的方式调整空白,但可以在reduce()函数本身中处理每个节点的空白。

例如,每个节点的空格处理:

const getElementTextWithoutChildElements_2 = (el) =>
  Array.from(el.childNodes)
    .filter(node => node.nodeType === 3)
    .map(node => node.textContent.trim()) // added .trim()
    .join(',')                            // added ','
;

以上内容的快速测试:

document.body.innerHTML = `
  you get this
  <b>not this</b>
  you get this   too
`;
// '\n  you get this\n  <b>not this</b>\n  you get this   too\n'

getElementTextWithoutChildElements(document.body);
// '\n  you get this\n  \n  you get this   too\n'

getElementTextWithoutChildElements(document.body).replace(/\s+/g, ' ').trim();
// 'you get this you get this too'

getElementTextWithoutChildElements_2(document.body);
// 'you get this,you get this   too'

我不是一个jquery专家,但如何,

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