@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: Решение здесь
  • Вопрос задан
  • 743 просмотра
Решения вопроса 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
я чего то не догоняю или просто нужно завести массив флагов?
Ответ написан
Комментировать
Ваш ответ на вопрос

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

Войти через центр авторизации
Похожие вопросы
SummerWeb Ярославль
от 120 000 до 180 000 ₽
Brightdata Тель-Авив
от 5 500 до 6 500 $
Market-place Ростов-на-Дону
от 100 000 до 200 000 ₽
21 июн. 2024, в 17:10
1000 руб./за проект
21 июн. 2024, в 16:44
500 руб./за проект