Как выбрать текстовые узлы с помощью jQuery?

Я хотел бы получить все текстовые узлы-потомки элемента в виде коллекции jQuery. Как лучше всего это сделать?

Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
В настоящее время производительность загрузки веб-сайта имеет решающее значение не только для удобства пользователей, но и для ранжирования в...
Безумие обратных вызовов в javascript [JS]
Безумие обратных вызовов в javascript [JS]
Здравствуйте! Юный падаван 🚀. Присоединяйся ко мне, чтобы разобраться в одной из самых запутанных концепций, когда вы начинаете изучать мир...
Система управления парковками с использованием HTML, CSS и JavaScript
Система управления парковками с использованием HTML, CSS и JavaScript
Веб-сайт по управлению парковками был создан с использованием HTML, CSS и JavaScript. Это простой сайт, ничего вычурного. Основная цель -...
JavaScript Вопросы с множественным выбором и ответы
JavaScript Вопросы с множественным выбором и ответы
Если вы ищете платформу, которая предоставляет вам бесплатный тест JavaScript MCQ (Multiple Choice Questions With Answers) для оценки ваших знаний,...
392
0
171 116
11
Перейти к ответу Данный вопрос помечен как решенный

Ответы 11

Jauco опубликовал хорошее решение в комментарии, поэтому я копирую его здесь:

$(elem)
  .contents()
  .filter(function() {
    return this.nodeType === 3; //Node.TEXT_NODE
  });

на самом деле $ (elem) .contents () .filter (function () {return this.nodeType == Node.TEXT_NODE;}); достаточно

Jauco 11.07.2009 17:53

IE7 не определяет глобальный узел, поэтому, к сожалению, вам придется использовать this.nodeType == 3: stackoverflow.com/questions/1423599/node-textnode-and-ie7

Christian Oudard 29.12.2009 23:00

Разве это не только возвращает текстовые узлы, которые являются прямыми дочерними элементами элемента, а не потомками элемента, как запрошено OP?

Tim Down 15.10.2010 18:12

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

Tim Down 11.10.2012 02:35

добавьте .text() в конце, если хотите, чтобы это была строка. В противном случае это все еще объект. Попытка отобразить его в документе приведет к отображению [Объект объекта].

Shahar 29.09.2013 12:14

@ChristianOudard Это было бы действительно просто полифилить, не так ли? Сделал бы ваш код более разборчивым.

mpen 11.06.2014 01:28

это не сработает, если текстовый узел глубоко вложен в другие элементы, потому что метод contents () возвращает только непосредственные дочерние узлы, api.jquery.com/contents

resgef 16.10.2015 19:08

@Jauco, нет, недостаточно! поскольку .contents () возвращает только непосредственные дочерние узлы

resgef 16.10.2015 19:14
Ответ принят как подходящий

В jQuery нет удобной функции для этого. Вам нужно объединить contents(), который даст только дочерние узлы, но включает текстовые узлы, с find(), который дает все дочерние элементы, но не текстовые узлы. Вот что я придумал:

var getTextNodesIn = function(el) {
    return $(el).find(":not(iframe)").addBack().contents().filter(function() {
        return this.nodeType == 3;
    });
};

getTextNodesIn(el);

Примечание. Если вы используете jQuery 1.7 или более раннюю версию, приведенный выше код не будет работать. Чтобы исправить это, замените addBack() на andSelf(). andSelf() устарел и заменен addBack() начиная с версии 1.8.

Это несколько неэффективно по сравнению с чистыми методами DOM и должно включать уродливый обходной путь для перегрузки jQuery его функции contents() (спасибо @rabidsnail в комментариях за указание на это), поэтому здесь не-jQuery решение, использующее простую рекурсивную функцию. Параметр includeWhitespaceNodes определяет, включаются ли в вывод текстовые узлы с пробелами (в jQuery они автоматически отфильтровываются).

Обновление: исправлена ​​ошибка, когда includeWhitespaceNodes является ложным.

function getTextNodesIn(node, includeWhitespaceNodes) {
    var textNodes = [], nonWhitespaceMatcher = /\S/;

    function getTextNodes(node) {
        if (node.nodeType == 3) {
            if (includeWhitespaceNodes || nonWhitespaceMatcher.test(node.nodeValue)) {
                textNodes.push(node);
            }
        } else {
            for (var i = 0, len = node.childNodes.length; i < len; ++i) {
                getTextNodes(node.childNodes[i]);
            }
        }
    }

    getTextNodes(node);
    return textNodes;
}

getTextNodesIn(el);

Может ли переданный элемент быть именем div?

crosenblum 10.02.2011 18:56

@crosenblum: Вы можете сначала вызвать document.getElementById(), если вы это имеете в виду: var div = document.getElementById("foo"); var textNodes = getTextNodesIn(div);

Tim Down 10.02.2011 19:43

Из-за ошибки в jQuery, если у вас есть какие-либо фреймы в el, вам нужно использовать .find (': not (iframe)') вместо .find ('*').

bobpoekert 03.02.2012 04:29

@rabidsnail: Я думаю, использование .contents() в любом случае подразумевает, что он также будет искать через iframe. Я не понимаю, как это могло быть ошибкой.

Robin Maben 06.02.2012 15:52
bugs.jquery.com/ticket/11275 Вопрос о том, действительно ли это ошибка, по-видимому, обсуждается, но ошибка или нет, если вы вызываете find ('*'). Contents () на узле, который содержит iframe, который не был добавлен в дом, вы получить исключение в неопределенной точке.
bobpoekert 14.02.2012 01:31

@rabidsnail: Хорошо, я думаю, что это как минимум раздражение (если не ошибка) в jQuery и аргумент в пользу простой версии DOM. Отредактирую свой ответ. Спасибо.

Tim Down 14.02.2012 01:57
andSelf() устарел в jQuery 1.8, вместо этого вы можете использовать addBack().
Mottie 14.02.2013 18:03

Вы могли бы рассмотреть nonWhitespace = /\S/ и if (includeWhitespaceNodes || nonWhitespace.test(node.nodeValue)) {, которые, по крайней мере, могут похвастаться большей простотой (хотя они по-разному реагировали бы на пустые текстовые узлы, если это возможно). Я также думаю, что можно было бы улучшить имя переменной регулярного выражения ... что-то вроде whitespaceMatcher или что-нибудь, чтобы указать, что это за переменная.

ErikE 19.11.2013 03:29

@ErikE: Мне нравятся описательные имена переменных. У меня такое чувство, что я выбрал whitespace, чтобы избежать появления горизонтальных полос прокрутки кода в моем браузере.

Tim Down 19.11.2013 03:42

@ErikE: Я согласен с вами по обоим пунктам и отредактировал свой ответ. Пустые текстовые узлы действительно возможны, но будут обрабатываться одинаково как для !/^\s*$/.test(), так и для /\S/.test(), поэтому здесь нет никаких проблем.

Tim Down 19.11.2013 03:55

о, да, это был *, а не +, поэтому пустые узлы сопоставлялись раньше. Рад, что вам понравились мои предложения!

ErikE 19.11.2013 04:03

Отличное предложение. Я бы рекомендовал использовать Node.TextNode вместо 3 для лучшей читаемости.

Ben Siver 28.03.2014 18:58

@BenS: Я бы хотел, но Node.TEXT_NODE не поддерживается в IE <= 8.

Tim Down 28.03.2014 20:31

В этом коде есть ошибка. Прямо сейчас, когда вы передаете false для включения пробелов, он ТОЛЬКО изменяет узлы пробелов, а не исключает их. Вместо этого в строке if (includeWhitespaceNodes || !nonWhitespaceMatcher.test(node.nodeValue)) следует читать: if (includeWhitespaceNodes || nonWhitespaceMatcher.test(node.nodeValue)).

Brian Geihsler 11.06.2014 22:55

@BrianGeihsler: Вы правы, спасибо. В ноябре прошлого года я упростил регулярное выражение, но не смог отменить условие. Хотел бы я проверить это сейчас.

Tim Down 12.06.2014 02:35

@TimDown Я пробовал ваш метод, но он выдает узлы из строя. Что нужно сделать, чтобы теги были в порядке? Я здесь отдельный вопрос задал stackoverflow.com/questions/63270123/…

Amanda 06.08.2020 07:16

@Amanda: Я думаю, что версия, отличная от jQuery, предоставит вам узлы в порядке документа.

Tim Down 06.08.2020 11:05

@TimDown Вы имеете в виду версию jquery? Я использую cheerio, но не понимаю.

Amanda 06.08.2020 12:01

@TimDown Я нашел ответ AKX на stackoverflow.com/questions/63270123/…. Кажется, это работает. Чем он отличается от того, что вы предложили в ответе? Не могли бы вы объяснить / помочь?

Amanda 06.08.2020 12:17

Если вы можете сделать предположение, что все дочерние элементы являются либо узлами элементов, либо текстовыми узлами, то это одно из решений.

Чтобы получить все дочерние текстовые узлы в виде коллекции jquery:

$('selector').clone().children().remove().end().contents();

Чтобы получить копию исходного элемента с удаленными нетекстовыми дочерними элементами:

$('selector').clone().children().remove().end();

Только что заметил комментарий Тима Дауна по поводу другого ответа. Это решение получает только прямых потомков, а не всех потомков.

colllin 20.04.2011 18:58

если вы хотите удалить все теги, попробуйте это

функция:

String.prototype.stripTags=function(){
var rtag=/<.*?[^>]>/g;
return this.replace(rtag,'');
}

использование:

var newText=$('selector').html().stripTags();

У меня была такая же проблема, и я решил ее:

Код:

$.fn.nextNode = function(){
  var contents = $(this).parent().contents();
  return contents.get(contents.index(this)+1);
}

Использование:

$('#my_id').nextNode();

Похож на next(), но также возвращает текстовые узлы.

.nextSibling взят из спецификации Dom: developer.mozilla.org/en/Document_Object_Model_(DOM)/…

Guillermo 14.02.2012 14:15
$('body').find('*').contents().filter(function () { return this.nodeType === 3; });

Также можно сделать так:

var textContents = $(document.getElementById("ElementId").childNodes).filter(function(){
        return this.nodeType == 3;
});

Приведенный выше код фильтрует textNodes от прямых дочерних узлов данного элемента.

... но не все дочерние узлы потомок (например, текстовый узел, который является дочерним элементом элемента, который является дочерним по отношению к исходному элементу).

Tim Down 18.10.2013 01:15

Для меня простой старый .contents(), казалось, работал, чтобы возвращать текстовые узлы, просто нужно быть осторожным с вашими селекторами, чтобы вы знали, что они будут текстовыми узлами.

Например, это обернуло все текстовое содержимое TD в моей таблице тегами pre и не дало никаких проблем.

jQuery("#resultTable td").content().wrap("<pre/>")

jQuery.contents() можно использовать с jQuery.filter для поиска всех дочерних текстовых узлов. С небольшим поворотом, вы также можете найти текстовые узлы внуков. Рекурсия не требуется:

$(function() {
  var $textNodes = $("#test, #test *").contents().filter(function() {
    return this.nodeType === Node.TEXT_NODE;
  });
  /*
   * for testing
   */
  $textNodes.each(function() {
    console.info(this);
  });
});
div { margin-left: 1em; }
<script src = "https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>

<div id = "test">
  child text 1<br>
  child text 2
  <div>
    grandchild text 1
    <div>grand-grandchild text 1</div>
    grandchild text 2
  </div>
  child text 3<br>
  child text 4
</div>

jsFiddle

Я пробовал это. Он печатает имена тегов в неправильном порядке. Есть ли способ печатать имена тегов в том порядке, в котором они встречаются? Я здесь отдельный вопрос задал stackoverflow.com/questions/63276378/…

Amanda 06.08.2020 07:27

По какой-то причине contents() не работал у меня, поэтому, если это не сработало для вас, вот решение, которое я сделал, я создал jQuery.fn.descendants с возможностью включать текстовые узлы или нет

использование


Получить всех потомков, включая текстовые узлы и узлы элементов

jQuery('body').descendants('all');

Получить всех потомков, возвращающих только текстовые узлы

jQuery('body').descendants(true);

Получить всех потомков, возвращающих только узлы элементов

jQuery('body').descendants();

Coffeescript Original:

jQuery.fn.descendants = ( textNodes ) ->

    # if textNodes is 'all' then textNodes and elementNodes are allowed
    # if textNodes if true then only textNodes will be returned
    # if textNodes is not provided as an argument then only element nodes
    # will be returned

    allowedTypes = if textNodes is 'all' then [1,3] else if textNodes then [3] else [1]

    # nodes we find
    nodes = []


    dig = (node) ->

        # loop through children
        for child in node.childNodes

            # push child to collection if has allowed type
            nodes.push(child) if child.nodeType in allowedTypes

            # dig through child if has children
            dig child if child.childNodes.length


    # loop and dig through nodes in the current
    # jQuery object
    dig node for node in this


    # wrap with jQuery
    return jQuery(nodes)

Перетащите версию Javascript

var __indexOf=[].indexOf||function(e){for(var t=0,n=this.length;t<n;t++){if (t in this&&this[t]===e)return t}return-1}; /* indexOf polyfill ends here*/ jQuery.fn.descendants=function(e){var t,n,r,i,s,o;t=e== = "all"?[1,3]:e?[3]:[1];i=[];n=function(e){var r,s,o,u,a,f;u=e.childNodes;f=[];for(s=0,o=u.length;s<o;s++){r=u[s];if (a=r.nodeType,__indexOf.call(t,a)>=0){i.push(r)}if (r.childNodes.length){f.push(n(r))}else{f.push(void 0)}}return f};for(s=0,o=this.length;s<o;s++){r=this[s];n(r)}return jQuery(i)}

Unminified Javascript version: http://pastebin.com/cX3jMfuD

Это кроссбраузер, в код включен небольшой полифилл Array.indexOf.

Я получал много пустых текстовых узлов с принятой функцией фильтра. Если вас интересует только выбор текстовых узлов, которые не содержат пробелов, попробуйте добавить условие nodeValue к вашей функции filter, например, простой $.trim(this.nodevalue) !== '':

$('element')
    .contents()
    .filter(function(){
        return this.nodeType === 3 && $.trim(this.nodeValue) !== '';
    });

http://jsfiddle.net/ptp6m97v/

Или, чтобы избежать странных ситуаций, когда содержимое выглядит как пробел, но не так (например, мягкий дефис &shy;, символы новой строки \n, табуляции и т. д.), Вы можете попробовать использовать регулярное выражение. Например, \S будет соответствовать любым непробельным символам:

$('element')
        .contents()
        .filter(function(){
            return this.nodeType === 3 && /\S/.test(this.nodeValue);
        });

Я пробовал это. Он печатает имена тегов в неправильном порядке. Есть ли способ печатать имена тегов в том порядке, в котором они встречаются? Я здесь отдельный вопрос задал stackoverflow.com/questions/63276378/…

Amanda 06.08.2020 07:28

Другие вопросы по теме