Подтвердить что ты не робот

Как получить текстовый узел элемента?

<div class="title">
   I am text node
   <a class="edit">Edit</a>
</div>

Я хочу получить "Я текстовый узел", не хочу удалять тег "редактировать", и мне нужно решение для кросс-браузерной работы.

4b9b3361

Ответ 1

var text = $(".title").contents().filter(function() {
  return this.nodeType == Node.TEXT_NODE;
}).text();

Это получает contents выбранного элемента и применяет к нему функцию фильтра. Функция фильтра возвращает только текстовые узлы (т.е. Те узлы с nodeType == Node.TEXT_NODE).

Ответ 2

Вы можете получить nodeValue первого childNode, используя

$('.title')[0].childNodes[0].nodeValue

http://jsfiddle.net/TU4FB/

Ответ 3

Если вы хотите получить значение первого текста node в элементе, этот код будет работать:

var oDiv = document.getElementById("MyDiv");
var firstText = "";
for (var i = 0; i < oDiv.childNodes.length; i++) {
    var curNode = oDiv.childNodes[i];
    if (curNode.nodeName === "#text") {
        firstText = curNode.nodeValue;
        break;
    }
}

Вы можете увидеть это в действии здесь: http://jsfiddle.net/ZkjZJ/

Ответ 4

Другое нативное решение JS, которое может быть полезно для "сложных" или глубоко вложенных элементов, - это использование NodeIterator. Поместите NodeFilter.SHOW_TEXT в качестве второго аргумента ("whatToShow") и выполните итерации только для дочерних элементов текстового узла элемента.

var root = document.getElementById('...'),
    iter = document.createNodeIterator (root, NodeFilter.SHOW_TEXT),
    textnode;

while (textnode = iter.nextNode()) {
  // do something with the text node
}

Вы также можете использовать TreeWalker. Разница между ними заключается в том, что NodeIterator - это простой линейный итератор, а TreeWalker позволяет вам перемещаться и по TreeWalker братьям, и по предкам.

Ответ 5

.text() - for jquery

$('.title').clone()    //clone the element
.children() //select all the children
.remove()   //remove all the children
.end()  //again go back to selected element
.text();    //get the text of element

Ответ 6

Версия ES6, которая возвращает содержимое первого узла #text

const extract = (node) => {
  const text = Array.from(node.childNodes).find(child => child.NodeType === Node.TEXT_NODE);
  return text && text.textContent.trim();
}

Ответ 7

Чистый JavaScript: минималистский

Прежде всего, всегда имейте это в виду при поиске текста в DOM.

MDN - пробелы в DOM

Эта проблема заставит вас обратить внимание на структуру вашего XML/HTML.

В этом чистом примере JavaScript я учитываю возможность множественных текстовых узлов, которые могут чередоваться с другими видами узлов. Однако изначально я не делаю суждения о пробелах, оставляя эту задачу фильтрации другому коду.

В этой версии я NodeList из кода вызова/клиента.

/**
* Gets strings from text nodes. Minimalist. Non-robust. Pre-test loop version.
* Generic, cross platform solution. No string filtering or conditioning.
*
* @author Anthony Rutledge
* @param nodeList The child nodes of a Node, as in node.childNodes.
* @param target A positive whole number >= 1
* @return String The text you targeted.
*/
function getText(nodeList, target)
{
    var trueTarget = target - 1,
        length = nodeList.length; // Because you may have many child nodes.

    for (var i = 0; i < length; i++) {
        if ((nodeList[i].nodeType === Node.TEXT_NODE) && (i === trueTarget)) {
            return nodeList[i].nodeValue;  // Done! No need to keep going.
        }
    }

    return null;
}

Конечно, node.hasChildNodes() проверяя node.hasChildNodes(), нет необходимости использовать цикл предварительного тестирования.

/**
* Gets strings from text nodes. Minimalist. Non-robust. Post-test loop version.
* Generic, cross platform solution. No string filtering or conditioning.
*
* @author Anthony Rutledge
* @param nodeList The child nodes of a Node, as in node.childNodes.
* @param target A positive whole number >= 1
* @return String The text you targeted.
*/
function getText(nodeList, target)
{
    var trueTarget = target - 1,
        length = nodeList.length,
        i = 0;

    do {
        if ((nodeList[i].nodeType === Node.TEXT_NODE) && (i === trueTarget)) {
            return nodeList[i].nodeValue;  // Done! No need to keep going.
         }

        i++;
    } while (i < length);

    return null;
}

Чистый JavaScript: надежный

Здесь функция getTextById() использует две вспомогательные функции: getStringsFromChildren() и filterWhitespaceLines().


getStringsFromChildren()

/**
* Collects strings from child text nodes.
* Generic, cross platform solution. No string filtering or conditioning.
*
* @author Anthony Rutledge
* @version 6.0
* @param parentNode An instance of the Node interface, such as an Element. object.
* @return Array of strings, or null.
* @throws TypeError if the parentNode is not a Node object.
*/
function getStringsFromChildren(parentNode)
{
    var strings = [],
        nodeList.
        length;

    if (!parentNode instanceof Node) {
        throw new TypeError("The parentNode parameter expects an instance of a Node.");
    }

    if (!parentNode.hasChildNodes()) {
        return null; // We are done. Node may resemble <element></element>
    }

    nodeList = parentNode.childNodes;
    length = nodeList.length;

    for (var i = 0; i < length; i++) {
        if (nodeList[i].nodeType === Node.TEXT_NODE) {
            strings.push(nodeList[i].nodeValue);
        }
    }

    if (strings.length > 0) {
        return strings;
    }

    return null;
}

filterWhitespaceLines()

/**
* Filters an array of strings to remove whitespace lines.
* Generic, cross platform solution.
*
* @author Anthony Rutledge
* @version 6.0
* @param textArray a String associated with the id attribute of an Element.
* @return Array of strings that are not lines of whitespace, or null.
* @throws TypeError if the textArray param is not of type Array.
*/
function filterWhitespaceLines(textArray) 
{
    var filteredArray = [],
        whitespaceLine = /(?:^\s+$)/; // Non-capturing Regular Expression.

    if (!textArray instanceof Array) {
        throw new TypeError("The textArray parameter expects an instance of a Array.");
    }

    for (var i = 0; i < textArray.length; i++) {
        if (!whitespaceLine.test(textArray[i])) {  // If it is not a line of whitespace.
            filteredArray.push(textArray[i].trim());  // Trimming here is fine. 
        }
    }

    if (filteredArray.length > 0) {
        return filteredArray ; // Leave selecting and joining strings for a specific implementation. 
    }

    return null; // No text to return.
}

getTextById()

/**
* Gets strings from text nodes. Robust.
* Generic, cross platform solution.
*
* @author Anthony Rutledge
* @version 6.0
* @param id A String associated with the id property of an Element.
* @return Array of strings, or null.
* @throws TypeError if the id param is not of type String.
* @throws TypeError if the id param cannot be used to find a node by id.
*/
function getTextById(id) 
{
    var textArray = null;             // The hopeful output.
    var idDatatype = typeof id;       // Only used in an TypeError message.
    var node;                         // The parent node being examined.

    try {
        if (idDatatype !== "string") {
            throw new TypeError("The id argument must be of type String! Got " + idDatatype);
        }

        node = document.getElementById(id);

        if (node === null) {
            throw new TypeError("No element found with the id: " + id);
        }

        textArray = getStringsFromChildren(node);

        if (textArray === null) {
            return null; // No text nodes found. Example: <element></element>
        }

        textArray = filterWhitespaceLines(textArray);

        if (textArray.length > 0) {
            return textArray; // Leave selecting and joining strings for a specific implementation. 
        }
    } catch (e) {
        console.log(e.message);
    }

    return null; // No text to return.
}

Затем возвращаемое значение (Array или null) отправляется клиентскому коду, где оно должно быть обработано. Надеемся, что массив должен содержать строковые элементы реального текста, а не строки пробела.

Пустые строки ("") не возвращаются, потому что вам нужен текстовый узел, чтобы правильно указывать наличие действительного текста. Возвращение ("") может создать ложное впечатление о существовании текстового узла, что .nodeValue кого-то предположить, что он может изменить текст, изменив значение .nodeValue. Это ложно, потому что текстовый узел не существует в случае пустой строки.

Пример 1:

<p id="bio"></p> <!-- There is no text node here. Return null. -->

Пример 2:

<p id="bio">

</p> <!-- There are at least two text nodes ("\n"), here. -->

Проблема возникает, когда вы хотите, чтобы ваш HTML был легко читаем, разнося его. Теперь, несмотря на то, что не существует читаемого человеком допустимого текста, все еще есть текстовые узлы с символами новой строки ("\n") в их свойствах .nodeValue.

Люди видят примеры один и два как функционально эквивалентные - пустые элементы, ожидающие заполнения. DOM отличается от человеческого мышления. Вот почему функция getStringsFromChildren() должна определить, существуют ли текстовые узлы, и собрать значения .nodeValue в массив.

for (var i = 0; i < length; i++) {
    if (nodeList[i].nodeType === Node.TEXT_NODE) {
            textNodes.push(nodeList[i].nodeValue);
    }
}

Во .nodeValue примере два текстовых узла существуют, и getStringFromChildren() вернет .nodeValue их обоих ("\n"). Однако filterWhitespaceLines() использует регулярное выражение для отфильтровывания строк из чисто пробельных символов.

Возвращает ли null вместо символов новой строки ("\n") форму лжи клиенту/вызывающему коду? С человеческой точки зрения нет. С точки зрения DOM, да. Однако проблема заключается в получении текста, а не в его редактировании. Нет человеческого текста, чтобы вернуться к вызывающему коду.

Никогда не знаешь, сколько символов новой строки может появиться в HTML-коде. Создание счетчика, который ищет "второго" символа новой строки, ненадежно. Это может не существовать.

Конечно, в дальнейшем вопрос редактирования текста в пустом элементе <p></p> с дополнительным пробелом (пример 2) может означать уничтожение (возможно, пропуск) текстового узла между тегами абзаца, кроме одного, чтобы гарантировать элемент содержит именно то, что он должен отображать.

В любом случае, за исключением случаев, когда вы делаете что-то необычное, вам понадобится способ определить, .nodeValue свойство .nodeValue текстового узла имеет настоящий, читаемый человеком текст, который вы хотите редактировать. filterWhitespaceLines возвращает нас на полпути.

var whitespaceLine = /(?:^\s+$)/; // Non-capturing Regular Expression.

for (var i = 0; i < filteredTextArray.length; i++) {
    if (!whitespaceLine.test(textArray[i])) {  // If it is not a line of whitespace.
        filteredTextArray.push(textArray[i].trim());  // Trimming here is fine. 
    }
}

В этот момент вы можете получить вывод, который выглядит следующим образом:

["Dealing with text nodes is fun.", "Some people just use jQuery."]

Нет никакой гарантии, что эти две строки смежны друг с другом в DOM, поэтому объединение их с помощью .join() может создать неестественную композицию. Вместо этого в коде, который вызывает getTextById(), вам нужно выбрать, с какой строкой вы хотите работать.

Проверьте вывод.

try {
    var strings = getTextById("bio");

    if (strings === null) {
        // Do something.
    } else if (strings.length === 1) {
        // Do something with strings[0]
    } else { // Could be another else if
        // Do something. It all depends on the context.
    }
} catch (e) {
    console.log(e.message);
}

Можно добавить .trim() внутри getStringsFromChildren() чтобы избавиться от .trim() и конечных пробелов (или превратить группу пробелов в строку нулевой длины (""), но как узнать заранее, что может понадобиться каждому приложению произойти с текстом (строкой), как только он будет найден? Вы этого не сделаете, поэтому оставьте это конкретной реализации, и пусть getStringsFromChildren() будет универсальным.

Могут быть случаи, когда этот уровень специфичности (target и т.д.) Не требуется. Это прекрасно. Используйте простое решение в этих случаях. Тем не менее, обобщенный алгоритм позволяет вам приспособиться к простым и сложным ситуациям.

Ответ 8

Это также будет игнорировать пробелы, поэтому вы никогда не получили Blank textNodes..code, используя основной Javascript.

var oDiv = document.getElementById("MyDiv");
var firstText = "";
for (var i = 0; i < oDiv.childNodes.length; i++) {
    var curNode = oDiv.childNodes[i];
    whitespace = /^\s*$/;
    if (curNode.nodeName === "#text" && !(whitespace.test(curNode.nodeValue))) {
        firstText = curNode.nodeValue;
        break;
    }
}

Проверьте это на jsfiddle: - http://jsfiddle.net/webx/ZhLep/

Ответ 9

Вы также можете использовать тест XPath text() node, чтобы получить только текстовые узлы. Например

var target = document.querySelector('div.title');
var iter = document.evaluate('text()', target, null, XPathResult.ORDERED_NODE_ITERATOR_TYPE);
var node;
var want = '';

while (node = iter.iterateNext()) {
    want += node.data;
}