oink
@oink
Профессиональный веб-макакинг

Можно ли реализовать проверку на видимость элемента без on scroll?

Добрый день. Есть такой кусок кода из некоторой библиотеки для реализации "бегущих счетчиков" (когда цифры бегут от нуля до указанного значения, типовой пример: "Опыт нашей компании в данной сфере: 'n' лет" - и вместо 'n' цифра бежит от нуля до произвольного числа. Вот этот код:

(function ($) {
	$.fn.countTo = function (options) {
		options = options || {};

		return $(this).each(function () {
			// set options for current element
			var settings = $.extend({}, $.fn.countTo.defaults, {
				from:            $(this).data('from'),
				to:              $(this).data('to'),
				speed:           $(this).data('speed'),
				refreshInterval: $(this).data('refresh-interval'),
				decimals:        $(this).data('decimals')
			}, options);

			// how many times to update the value, and how much to increment the value on each update
			var loops = Math.ceil(settings.speed / settings.refreshInterval),
				increment = (settings.to - settings.from) / loops;

			// references & variables that will change with each update
			var self = this,
				$self = $(this),
				loopCount = 0,
				value = settings.from,
				data = $self.data('countTo') || {};

			$self.data('countTo', data);

			// if an existing interval can be found, clear it first
			if (data.interval) {
				clearInterval(data.interval);
			}
			data.interval = setInterval(updateTimer, settings.refreshInterval);

			// initialize the element with the starting value
			render(value);

			function updateTimer() {
				value += increment;
				loopCount++;

				render(value);
				if (typeof(settings.onUpdate) == 'function') {
					settings.onUpdate.call(self, value);
				}

				if (loopCount >= loops) {
					// remove the interval
					$self.removeData('countTo');
					clearInterval(data.interval);
					value = settings.to;

					if (typeof(settings.onComplete) == 'function') {
						settings.onComplete.call(self, value);
					}
				}
			}

			function render(value) {
				var formattedValue = settings.formatter.call(self, value, settings);
				$self.html(formattedValue);
			}
		});
	};

	$.fn.countTo.defaults = {
		from: 0,               // the number the element should start at
		to: 0,                 // the number the element should end at
		speed: 1000,           // how long it should take to count between the target numbers
		refreshInterval: 10,  // how often the element should be updated
		decimals: 0,           // the number of decimal places to show
		formatter: formatter,  // handler for formatting the value before rendering
		onUpdate: null,        // callback method for every time the element is updated
		onComplete: null       // callback method for when the element finishes updating
	};

	function formatter(value, settings) {
		return value.toFixed(settings.decimals);
	}
}(jQuery));

jQuery(function ($) {
  // custom formatting example
  $('.counter-number').data('countToOptions', {
	formatter: function (value, options) {
	  return value.toFixed(options.decimals).replace(/\B(?=(?:\d{3})+(?!\d))/g, ',');
	}
  });

  // start all the timers
  $('.timer').each(count);

  function count(options) {
		var $this = $(this);
		options = $.extend({}, options || {}, $this.data('countToOptions') || {});
		$this.countTo(options);
  }
});


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

var counters = document.getElementById('counters');

if (counters) {
	function isScrolledIntoView(counters) {
	  var countersTop = counters.getBoundingClientRect().top;
	  var countersBottom = counters.getBoundingClientRect().bottom;

	  var isVisible = (countersTop >= 0) && (countersBottom <= window.innerHeight);
	  return isVisible;
	}

	$(window).on('scroll', function() {

	  if (isScrolledIntoView(counters) && !finished) {
	    $('.counter-number').countTo();

	    // Unbind scroll event
	    $(window).off('scroll');
	  }
	});
}


Все замечательно работает, НО если промотать страницу до этих счетчиков, обновить, подождать, пока они прокрутятся, и крутануть колесико мыши, они снова начинают отсчитывать сначала. Вопрос: можно как-то пофиксить, определив, что элемент уже в зоне видимости? Как видно, on scroll для проверки на видимость уже занят. Пробовал присоседить булиеву переменную, чтобы var animatsiaUzheVsyo становилась true после едичиного воспроизведения, но, видимо, куда-та не туда я ее пихаю.
  • Вопрос задан
  • 52 просмотра
Пригласить эксперта
Ответы на вопрос 1
@justadumb
Есть гораздо более лучший вариант для вашей задачи, IntersectionObserver, гуглите, нативная js фича. Вот пример реализации.
function onEntry(entry) {
    entry.forEach((change) => {
      if(change.isIntersecting) {
        change.target.classList.add('visible');
      }
    });
  }
  
  // list of options
  let options = {
    threshold: [0.4]
  };
  
  // instantiate a new Intersection Observer
  let observer = new IntersectionObserver(onEntry, options);
  
  // list of paragraphs
  let elements = document.querySelectorAll('section');
  
  // loop through all elements
  // pass each element to observe method
  // ES2015 for-of loop can traverse through DOM Elements
  for (let elm of elements) {
    observer.observe(elm);
  }
Ответ написан
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Похожие вопросы