Объединить функции resize и scroll в jquery
Есть две функции. В первой при размере окна больше 725px к классу header добавляется класс sticky, на меньших разрешениях удаляется.
function checkWidth() {
if ($(window).width() > 725) {
$('header').addClass('sticky');
} else {
$('header').removeClass('sticky');
}
}
$(window).resize(checkWidth);
Во второй функции при скролле более 10px к header прибавляется класс sticky.
$(window).scroll(function() {
var height = $(window).scrollTop();
if(height > 10){
$('header').addClass('sticky');
$('.header-wrapper').addClass('topbar-size');
} else{
$('header').removeClass('sticky');
$('.header-wrapper').removeClass('topbar-size');
}
});
проблема в том, что на разрешениях меньше 725px sticky не должен прибавляться к header и должен отключаться скролл. я не знаю как сделать правильно. я нашарил что правильно объединять функции надо по такому принципу:
var func = function(e){ /* resize and scroll logic */};
$(window).scroll(func).resize(func);
но я не понимаю как.
Ответы (2 шт):
Не пугайтесь большому количеству кода, для казалось бы, такого простого действия.
Суть в чём, тут много проверок, связанных с оптимизацией - в чём суть этой оптимизации:
Без неё, наша проверка будет срабатывать каждый раз когда будет выполнен scroll или resize, с данной проверкой, будет выполнятся только тогда, когда все условия будут совпадать.
Вот реализация данного решения на jQuery
let header = $('header'),
h_min = 725, // Минимальная ширина экрана для работы скрипта
s_pos = 10, // Позиция скролла, при которой включается `sticky`
isSticky = $(window).scrollTop() > s_pos ? true : false, // Некая оптимизация, с изначальной проверкой
isMinSize = $(window).width() < h_min ? false : true; // Некая оптимизация, с изначальной проверкой
if(isSticky === true && isMinSize === true) header.addClass('sticky'); // При изначальной проверке мы проверяем, что если позиция скролла изначально больше минимальной высоты для работы скрипта, при этом минимальная ширина не достигнута, то выдаём класс `sticky`
$(window).on({ // Вещаем обработчики на скролл и ресайз
'scroll': function() {
if(isMinSize === true) { // Если минимальная ширина достигнута, то `sticky` добавляться или удаляться не будет.. Если проверка прошла, то:
if($(window).scrollTop() >= s_pos && isSticky === false) { // Если позиция скролла больше или равна минимальной высоте, то
isSticky = true; // Меняем "флаг" для оптимизации
header.addClass('sticky'); // вешаем класс `sticky`
} else
if($(window).scrollTop() < s_pos && isSticky === true) { // Тут такое же принцип действия как и выше, но наоборот
isSticky = false;
header.removeClass('sticky');
}
}
},
'resize': function() { // Далее проверяем ресайз
if($(window).width() < h_min && isMinSize === true) { // Если ширина окна меньше минимальной ширины, то:
isMinSize = false; // Выставляем "флаг" для оптимизации
if($(window).scrollTop() >= s_pos) { // Тут такое же принцип действия как и выше, но наоборот
isSticky = false;
header.removeClass('sticky');
}
} else
if($(window).width() >= h_min && isMinSize === false) { // Тут аналогично проверке выше, только так же наоборот
isMinSize = true;
if($(window).scrollTop() >= s_pos) { // Если позиция скролла больше или равна минимальной высоте, то
isSticky = true; // Меняем "флаг" для оптимизации
header.addClass('sticky'); // вешаем класс `sticky`
}
}
}
});
body {
height: 150vh;
margin: 0;
}
header {
display: block;
width: 100%;
height: 50px;
position: fixed;
top: 0;
background: blue;
}
header.sticky {
background: red;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<header></header>
Когда нажмёте "Выполнить код" ничего работать не будет - потому что сниппет по ширине меньше 725px, если нажмёте в правой стороне На всю страницу, то код будет работать.
При этом дописал некую механику.
Если скролл больше s_pos, и ширина экрана становится больше h_min - то класс sticky удалится. Так же работает и в обратную сторону.
Зачем вам использовать JS там, где можно сделать на CSS. Для задачи sticky достаточно написать:
header {
/* стили, когда ширина viewport > 725 */
}
@media screen and (max-width: 725px) {
header {
/* стили, когда ширина viewport <= 725 */
}
}
Для задачи со скроллом добавить:
var $window = $(window), $body = $(document.body);
$window.on('resize scroll update', function() {
$body.attr('data-scrolled', $window.scrollTop() > 10 ? 'Y' : 'N');
}).trigger('update');
И затем написать стили с учетом скролла:
body[data-scrolled="N"] header {
/* стили без скролла и когда ширина viewport > 725 */
}
body[data-scrolled="Y"] header {
/* стили со скроллом и когда ширина viewport > 725 */
}
@media screen and (max-width: 725px) {
body[data-scrolled="N"] header {
/* стили без скролла и когда ширина viewport <= 725 */
}
body[data-scrolled="Y"] header {
/* стили со скроллом и когда ширина viewport <= 725 */
}
}
Да, здесь возможно придется дублировать одинаковые стили, но такой вариант гораздо более оптимизирован с точки зрения отрисовки браузером изменяющегося контента.