Во-первых. Для определения видимости есть специальный API. Он страшен, как жизнь простого программиста, но это, всё-таки, стандарт. Вот небольшая обёртка, которую я написал для себя:
// Starts observing visibility of the given element. On change,
// the callback is called with Boolean visibility as argument.
System.attachOnVisibilityChangedHandler = function (element, callback, visiblePart = 0.5)
{
const options =
{
root: null,
threshold: [0, 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9, 1],
};
const observer = new IntersectionObserver((entries, observer) =>
{
entries.forEach(entry =>
{
callback(entry.target, entry.intersectionRatio >= visiblePart);
});
}, options);
observer.observe(element);
}
Во-вторых. Он тоже даёт ложноположительные срабатывания (я думаю, в этом ваша проблема). Это by design. Поэтому надо проверять предыдущее состояние, чтобы понять, изменилось ли оно:
// For all elements, marked with 'autoplay' and 'autoplay-once' classes, adds 'start-autoplaying' class when visible first time.
// For all elements, marked with 'autoplay' only, adds 'start-autoplaying' class every time, when visible, and removes it, when not.
function autoplayAnyWhenVisible()
{
$('.autoplay').each(function ()
{
const startAutoplayingClass = 'start-autoplaying';
const visiblePart = $(this).data('visible-part') ?? 0.5;
const onElementVisibilityChanged = function (element, isVisible)
{
const autoplayOnce = $(element).hasClass('autoplay-once');
const wasVisible = $(element).data('is-visible');
if (isVisible && !wasVisible)
{
$(element)
.addClass(startAutoplayingClass)
.data('is-visible', true);
}
if (autoplayOnce)
return;
if (!isVisible && wasVisible)
{
$(element)
.removeClass(startAutoplayingClass)
.data('is-visible', false);
}
};
System.attachOnVisibilityChangedHandler(this, onElementVisibilityChanged, visiblePart);
});
}
С этим кодом просто маркируете элементы при помощи класса autoplay (плюс autoplay-once если надо проигрывать анимацию только один раз), указываете долю видимости, и при
реальном показе/сокрытии будет добавляться/убираться класс start-autoplaying (куда и засовываете анимацию написания текста):
<div class="… autoplay autoplay-once" data-is-visible="false" data-visible-part="0.3">