Как получить только видимый текст с помощью JQuery (или Javascript) - PullRequest
16 голосов
/ 04 декабря 2009

У меня есть сайт, который конвертирует японское кандзи в ромадзи (римские буквы) :

и вывод показывает и скрывает CSS, что пользователь должен видеть в зависимости от своих критериев ввода. Например:

<div id="output">
    <span class="roman">watashi</span> 
    <span class="english">I</span>
</div>

Интерфейс позволяет пользователю переключаться между и выводить watashi или I в зависимости от того, что они хотят видеть.

CSS скрывает одно или другое с помощью jQuery и кнопки переключения. (Механизм сокрытия включает в себя простое добавление класса к body и позволить CSS делать свое дело).

Проблема в том, что когда пользователи копируют / вставляют текст в Word, он копирует все. Поэтому я решил использовать систему для копирования и вставки текста, используя JavaScript и jQuery, но проблема повторяется:

$('#output').text()

выводит watashi I, даже если I невидимо на самой странице а не watashi. Есть ли способ получить только видимый текст?

Ответы [ 6 ]

17 голосов
/ 10 октября 2015

другие решения не дали мне то, что мне было нужно.

Короткий ответ

мой ответ:

$('#output *:not(:has(*)):visible').text()

plunkr

TL; DR

Проблема с решением Маркга

Вы не должны задавать текст всего элемента под каким-либо корневым элементом.

почему? - будет повторять вывод и игнорировать скрытый флаг

Давайте рассмотрим простой пример

<div id="output" class="my-root">
    <div class="some-div">
         <span class="first" style="display:none"> hidden text </span>
         <span class="second" > visible text </span>
    </div>
<div>

сейчас, если я сделаю $('#output').children(":visible").text()

Я получу .some-div и .second .. когда на самом деле .some-div меня не касается ..

когда я запрашиваю text() для этих элементов, .some-div также возвращает скрытый текст ..

так что технически решение Маркга неверно ИМХО ...

Причина моего ответа

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

Предположение состоит в том, что текст появляется только в элементах листа.

Так что мы не увидим ничего подобного:

<div id="output" class="my-root">
    <div class="some-div">
         <span class="first" style="display:none"> hidden text </span>
         <span class="second" > visible text </span>
    </div>

    some text here.. 

<div>

Почему это предположение кажется мне разумным? две причины:

  • Потому что сложно поддерживать страницу, созданную таким образом, и со временем люди с опытом узнают об этом и избегают этого.
  • Легко преобразовать ваш html в такую ​​структуру. просто оберните текст родителей с пролетами. Таким образом, даже если это предположение не существует прямо сейчас, туда легко попасть.

Исходя из этого предположения, вы хотите запросить все конечные элементы (элементы без дочерних элементов), отфильтровать видимое и запросить их текст.

$('#output *:not(:has(*)):visible').text()

Это должно дать правильный результат.

У вас есть текст вне листа?

комментарии предполагают, что иногда вы просто должны иметь текст вне элемента листа

<div> This is some <strong style="display:none"> text </strong>  </div>

Как видите, у вас есть <strong> в качестве листа, и обычно текст вне него, как в этом примере.

Вы можете обойти это с обходным путем, который я предлагаю выше ... но что, если вы не можете?

Вы можете клонировать дом, а затем удалить все скрытые элементы. Проблема здесь заключается в том, что для работы селекторов :visible или :hidden необходимо, чтобы в документе был элемент dom (то есть фактически видимый для пользователя). Итак, этот метод имеет некоторые побочные эффекты, поэтому будьте осторожны.

Вот пример

для этого HTML

 <div id="output" class="my-root">
     <span>
         some text <strong style="display:none">here.. </strong>
     </span>
</div>

Этот JavaScript работает

$(function(){
     var outputClone = $('#output').clone();
    $('#output :hidden').remove(); 
    console.log($('#output').text()); // only visible text
    $('#output').replaceWith(outputClone);
    console.log($('#output').text()); // show original state achieved. 
})

см. Плункер здесь

как уже упоминалось - побочные эффекты могут выглядеть как кратковременное мерцание или какой-то сценарий инициализации, который должен быть запущен ... некоторых можно избежать с некоторым оригинальным мышлением (div с размером 1px / 1px, чтобы содержать клон вместе с оригинальным контентом?) В зависимости от ваш сценарий

11 голосов
/ 04 декабря 2009

Используйте : видимый селектор Jquery

В вашем случае я думаю, что вы хотите сделать:

$('#output').children(":visible").text() 
3 голосов
/ 28 декабря 2017

Попробуйте это в современных браузерах (здесь 'element' - это не DQ-объект DQ):

function getVisibleText(element) {
    window.getSelection().removeAllRanges();

    var range = document.createRange();
    range.selectNode(element);
    window.getSelection().addRange(range);

    var visibleText = window.getSelection().toString().trim();
    window.getSelection().removeAllRanges();

    return visibleText;
}

тогда:

getVisibleText(document.getElementById('output'));
1 голос
/ 27 июля 2016
var lookup = function(element, text) {
    //DFS Recursive way of finding text on each level
    //Visible only works on elements that take up space(i.e. not fixed position elements)
    var results = element.children(':visible');

    //Look at the text at each level with the children removed
    var newText = '';
    results.each(function(index, value) {
        newText += $(value).clone()
            .children()
            .remove()
            .end()
            .text();
    });

    var moreResultText = '';
    results.each(function(index, value) {
        moreResultText += lookup($(value), text);
    })

    if (results.length > 0) {
        return text + newText + moreResultText;
    } else {
        return text;
    }
};

lookup($('#output'), ''));

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

Будьте осторожны, конечно, это не сохраняет никакого смысла в форматировании, и расстояние между выводами может быть неправильным между элементами. Кроме того, он, вероятно, неправильно упорядочивает возвращаемый текст, в этих аспектах его использование будет ограничено. Другим соображением является то, что реальное определение visible немного сложно зафиксировать , но для этого примера я принимаю, что «: visible» работает для большинства распространенных случаев.

Я использую его, чтобы проверить, содержит ли страница видимый текст (просто запустите его на элементе body), но, вероятно, он подойдет и для этого примера.

1 голос
/ 24 марта 2016

Парень имеет правильный ответ.

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

$('*:not(:has(*)):visible', this).text()
0 голосов
/ 04 декабря 2009

Вместо того, чтобы скрывать диапазон, удалите элемент span и сохраните ссылку на него. Когда пользователь нажимает на кнопку переключения, удалите другую и вставьте ту, на которую вы сохранили ссылку. Пользователь не сможет выбрать то, чего больше нет в DOM.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...