Ответ 1
Используйте : видимый селектор JQuery
В вашем случае я думаю, что вы хотите сделать:
$('#output').children(":visible").text()
У меня есть веб-сайт, который преобразует Японский кандзи в ромаджи (римские буквы):
и вывод показывает и скрывает с 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
. Есть ли способ получить только видимый текст?
Используйте : видимый селектор JQuery
В вашем случае я думаю, что вы хотите сделать:
$('#output').children(":visible").text()
другие решения не дали мне то, что мне было нужно.
мой ответ:
$('#output *:not(:has(*)):visible').text()
Вы не должны запрашивать текст всего элемента под некоторым корневым элементом.
почему? - он будет повторять вывод и игнорировать скрытый флаг
рассмотрим простой пример
<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
также вернет скрытый текст.
поэтому технически решение marcgg ошибочно ИМХО...
Теперь, чтобы правильно ответить на вопрос, мы должны сделать предположение. Тот, который для меня кажется достаточно разумным.
Предположение заключается в том, что текст появляется только в листовых элементах.
Итак, мы не увидим что-то вроде этого:
<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>
Почему это предположение кажется мне разумным? две причины:
В этом предположении вы хотите запросить все элементы листа (элементы без детей), отфильтровать видимые и запросить их текст.
$('#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.
})
см. plunker здесь
как упоминалось - побочные эффекты могут появляться как мгновенное мерцание или некоторая инициализация script, которые должны запускаться. Некоторым можно избежать с некоторым оригинальным мышлением (div с размером 1px/1px, чтобы содержать клон вместе с исходным контентом?) в зависимости от вашего сценария.
У Гая есть правильный ответ.
Однако я имел дело с объектом "this", поэтому, чтобы получить его ответ на работу, вам нужно использовать следующий синтаксис...
$('*:not(:has(*)):visible', this).text()
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" работает для большинства распространенных случаев.
Я использую его, чтобы проверить, содержит ли страница видимый текст (просто запустите его на элементе body), но он, вероятно, тоже будет работать для этого примера.
Вместо того, чтобы скрывать диапазон, удалите элемент span и сохраните ссылку на него. Когда пользователь нажимает на кнопку переключения, удалите другую и вставьте ту, на которую вы указали ссылку. Пользователь больше не сможет выбирать то, что больше не находится в DOM.
Попробуйте это в современных браузерах (здесь "элемент" - объект DOM без JQuery):
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'));