@be_a_man

Как выполнить JS функцию при скроле только 1 раз?

Не пинайте, гуглил, но не понимаю логику. + в карму тому кто объяснит.
Код вопроса здесь
function sAnim(el, fun, offset = 0) {
	
	let self = document.querySelectorAll(el);
	let winScrollY = window.scrollY;
	let winHeight = window.innerHeight;

	for (var i = 0; i < self.length; i++) {
		
		let el = self[i];
		let pos = el.getBoundingClientRect().top ;
		let top = pos.top + pageYOffset;

		if (winScrollY > top - winHeight + winHeight/100*offset && winScrollY - winHeight < top - winHeight) {

			//Нужно выполнить только 1 раз
			fun(el);

		}
	}

}

function showHuntInSelecter(el) {
	el.classList.add('show-hint');
	setTimeout(function () {
		el.classList.remove('show-hint');
	}, 4000)
}

	var scroll = window.requestAnimationFrame || window.webkitRequestAnimationFrame ||
	window.mozRequestAnimationFrame || window.msRequestAnimationFrame ||
	window.oRequestAnimationFrame || function(callback){ window.setTimeout(callback, 1000/60) };
	var lastPosition = -1;
	function loop(){
		if (lastPosition == window.pageYOffset) {
			scroll(loop);
			return false;
		} else lastPosition = window.pageYOffset;
		// Функции при скролле

			sAnim('.selecter', showHuntInSelecter, 30);

		// Функции при скролле
		scroll(loop);
	}; loop();



------------------

UPD: Решение здесь
  • Вопрос задан
  • 744 просмотра
Решения вопроса 3
@be_a_man Автор вопроса
В общем разобрался. Решение

Благодарности:
1. Ernest Faizullin за наводку.
2. Сергей Соколов за наводку и заметку о производительности
Поскольку выяснилось, что для каждого элемента селектора надо вызывать ф-ю один раз, а не всего один раз глобально, понадобится книга учёта, где элементы будут отмечаться: выполнил / не выполнил ещё пока.

Не факт, что нужно на каждый кадр отрисовки заново искать в DOM элементы по селектору - это медленно.


Зачем вообще это нужно было? Чтобы было универсальное решение для работы с элементами, когда они попадают в зону видимости.
Ответ написан
erniesto77
@erniesto77
oop, rb, py, php, js
если я правильно понял, то предлагаю примерно так
let something _executed = false;

something = (function () {
    return function () {
        if ( ! something _executed ) {
            // do something
            something _executed= true;
        }
    };
})();
Ответ написан
sergiks
@sergiks Куратор тега JavaScript
♬♬
Upd.
Поскольку выяснилось, что для каждого элемента селектора надо вызывать ф-ю один раз, а не всего один раз глобально, понадобится книга учёта, где элементы будут отмечаться: выполнил / не выполнил ещё пока.

Не факт, что нужно на каждый кадр отрисовки заново искать в DOM элементы по селектору - это медленно.

Всё решение надо переписать с нуля, а тратить на это время нет желания.

Плохой старый ответ. Игнорировать.

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

Warning этот вариант сработает вообще всего 1 раз, даже если элементов класса несколько. Похоже, ТС хотел иного: «1 раз для каждого найденного элемента класса».

мусорный пакет с макаронами
(function(selector){     // ДОБАВЛЕНО
  var done = false;      // ДОБАВЛЕНО

  function sAnim(el, fun, offset = 0) {
    let self = document.querySelectorAll(el);
    let winScrollY = window.scrollY;
    let winHeight = window.innerHeight;
    for (var i = 0; i < self.length; i++) {
      let el = self[i];
      let pos = el.getBoundingClientRect().top;
      let top = pos.top + pageYOffset;
      if (winScrollY > top - winHeight + winHeight / 100 * offset && winScrollY - winHeight < top - winHeight) {
        //Нужно выполнить только 1 раз
        
        if(done) return; // ДОБАВЛЕНО
        fun(el);
        done = true;     // ДОБАВЛЕНО
      }
    }
  }
  
  function showHuntInSelecter(el) {
    el.classList.add('show-hint');
    setTimeout(function() {
      el.classList.remove('show-hint');
    }, 4000)
  }
  
  var scroll = window.requestAnimationFrame || window.webkitRequestAnimationFrame || window.mozRequestAnimationFrame || window.msRequestAnimationFrame || window.oRequestAnimationFrame ||
  
  function(callback) {
    window.setTimeout(callback, 1000 / 60)
  };
  
  var lastPosition = -1;
  
  function loop() {
    if (lastPosition == window.pageYOffset) {
      scroll(loop);
      return false;
    } else lastPosition = window.pageYOffset;
    // Функции при скролле
    sAnim(selector, showHuntInSelecter, 30);  // РЕДАКТИРОВАНО
    // Функции при скролле
    scroll(loop);
  };
  
  loop();

})('.selecter')          // ДОБАВЛЕНО
Ответ написан
Пригласить эксперта
Ответы на вопрос 1
ThunderCat
@ThunderCat Куратор тега JavaScript
{PHP, MySql, HTML, JS, CSS} developer
я чего то не догоняю или просто нужно завести массив флагов?
Ответ написан
Комментировать
Ваш ответ на вопрос

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

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