Jquery: как заставить функцию scroll вызываться только один раз?

420
24 апреля 2017, 04:02

Есть небольшая функция, которая при скролле добавляет\удаляет класс элементу + скрывает\открывает блоки:

$(document).ready(function() {
    var navbar = $('.navbar');
    var head = $('#head');
    var headFix = $('#head-fix');
    var main = $('.main');
  $(window).scroll(function() {
    if ($(this).scrollTop() > 1) {
        navbar.addClass('navbar-fix');
        head.css('display', 'none');
        headFix.css('display', 'block');
        main.css('margin-top', '200px');
    }
    else {
        navbar.removeClass('navbar-fix');
        head.css('display', 'block');
        headFix.css('display', 'none');
        main.css('margin-top', '0');
    }
  });
});

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

Как сделать, чтобы функция отрабатывала только один раз - при переходе scrollTop() через 1 (туда и обратно)?

Answer 1

Так же можно сделать с использованием Intersection Observer API:

(function($) { 
  $(function() { 
    var navbar = $('.navbar') 
      , head = $('#head') 
      , headFix = $('#head-fix') 
      , main = $('.main') 
      , observeTarget = $('.observeMe').get(0) 
      , isTop = null; 
    // создаем новый observer 
    var observer = new IntersectionObserver(intersection); 
    // observer следит за элементом 0x0 в верху страницы 
    observer.observe(observeTarget); 
    function intersection(entries) { 
      //т.к. у нас только один элемент, берем просто 0 элемент от entries 
      if (!entries[0].intersectionRatio) { 
          //прячем, если пересечение исчезло 
          navbar.addClass('navbar-fix'); 
          head.hide(); 
          headFix.show(); 
          main.css('marginTop', 200);       
      } else { 
          navbar.removeClass('navbar-fix'); 
          head.show(); 
          headFix.hide(); 
          main.css('marginTop', 0); 
 
      } 
    } 
  }); 
})(jQuery);
.content { 
  height: 2000px; 
} 
.observeMe { 
  height: 0px; 
  position: absolute; 
  top: 0; 
  left: 0; 
  width: 0; 
  margin: 0; 
  border: none; 
  padding: 0; 
} 
div { 
  border: 1px solid; 
  margin: 16px; 
  padding: 16px; 
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script> 
<div class="observeMe"></div> 
<div class="content"> 
  <div class="navbar">Navbar</div> 
  <div id="head">Head</div> 
  <div id="head-fix">Head Fix</div> 
  <div class="main">Main</div> 
</div>

по умолчанию не работает нигде, кроме chrome-based >= 51.

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

Answer 2

(function($) { 
  $(function() { 
    var navbar = $('.navbar') 
      , head = $('#head') 
      , headFix = $('#head-fix') 
      , main = $('.main') 
      , isTop = null; 
    $(window).scroll(function() { 
      var newIsTop = $(this).scrollTop() > 1 ? false : true; 
      if (isTop !== newIsTop) { 
        isTop = newIsTop; 
        if (!isTop) { 
          navbar.addClass('navbar-fix'); 
          head.hide(); 
          headFix.show(); 
          main.css('marginTop', 200); 
        } 
        else { 
          navbar.removeClass('navbar-fix'); 
          head.show(); 
          headFix.hide(); 
          main.css('marginTop', 0); 
        } 
      } 
    }).scroll(); 
  }); 
})(jQuery);
.content { 
  height: 2000px; 
} 
 
div { 
  border: 1px solid; 
  margin: 16px; 
  padding: 16px; 
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script> 
<div class="content"> 
  <div class="navbar">Navbar</div> 
  <div id="head">Head</div> 
  <div id="head-fix">Head Fix</div> 
  <div class="main">Main</div> 
</div>

Answer 3

Можно попробовать вот так, условия будут проверяться, но срабатывать перерисовка будет только когда условие выполнится, дёрганья и ряби не наблюдал:

$(document).ready(function() { 
  var navbar = $('.navbar'), 
    head = $('#head'), 
    headFix = $('#head-fix'), 
    main = $('.main'); 
 
  function funcRemove(e) { 
    if (document.body.scrollTop > 10) { 
      //console.log('funcRemove'); 
      navbar.addClass('navbar-fix'); 
      head.hide(); 
      headFix.show(); 
      main.css('marginTop', 150); 
      window.removeEventListener('scroll', funcRemove); 
      window.addEventListener('scroll', funcAdd); 
    } 
  } 
 
  function funcAdd() { 
    if (document.body.scrollTop < 10) { 
      //console.log('funcAdd'); 
      navbar.removeClass('navbar-fix'); 
      head.show(); 
      headFix.hide(); 
      main.css('marginTop', 0); 
      window.removeEventListener('scroll', funcAdd); 
      window.addEventListener('scroll', funcRemove); 
    } 
  } 
 
  window.addEventListener('scroll', funcRemove); 
});
.content { 
  height: 1000px; 
} 
 
div { 
  border: 1px solid; 
  margin: 16px; 
  padding: 16px; 
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script> 
 
<div class="content"> 
  <div class="navbar">Navbar</div> 
  <div id="head">Head</div> 
  <div id="head-fix">Head Fix</div> 
  <div class="main">Main</div> 
</div>

READ ALSO
Gulp собрать в минимизировать в один файл

Gulp собрать в минимизировать в один файл

Есть директория src/less-build-structure/ с кучей файлов и папокКак все эти файлы, включая те, которые в папках собрать в один файл est

337
перемещение элемента с помощью AngularJS или JQuery

перемещение элемента с помощью AngularJS или JQuery

Задача такая есть: несколько кнопок, если нажать одну из них то к ней должен переместить элемент , в данном случае просто текстЯ реализовал...

319
Three js загрузка Obj-модели

Three js загрузка Obj-модели

Пытаюсь загрузить модель (Obj+Mtl) по примеру из официальной документации

298
Как получить доступ к DOM iframe другого сайта на своем домене?

Как получить доступ к DOM iframe другого сайта на своем домене?

Есть 2-а сайта (первый - HTTP, второй - HTTPS), оба на одном домене, но каталоги разныеДоступ ко всему есть

476