Здравствуйте.
Есть маленький код, который устанавливает значение top
у блока в зависимости от положения scroll'а. Проблема в том, что не во всех браузерах оно плавно отображается, т.е. при scroll'е происходят резкие скачки (браузера: IE, Opera <11 и т.д.). Как убрать эти скачки и сделать полностью плавные движения?
Код:
window.onscroll = function() {
document.getElementsByTagName('div')[0].style.marginTop = window.pageYOffset + 'px';
};
body {height: 2000px; }
div {
width: 200px;
height: 200px;
background-color: black;
}
<div></div>
Отображение со скачками:
На картинке маленькие скачки, но с разными объектами и разными браузерами - скачки разного размера.
Ссылка на сторонний редактор: jsfiddle-gjx7ecd4
Поведение блока сильно похоже на fixed, с тем исключением, что при полной прокрутке окна вверх, он маргинится на несколько пикселей. Возможно, решением будет - присвоение ему класса с необходимыми параметрами, если величина прокрутки окна больше его первоначального отступа.
var elem = document.getElementById('test'); //получаем целевой элемент
var style = elem.currentStyle || window.getComputedStyle(elem);/* тк, если
напрямую обратиться к свойству style,
то мы получим список правил для, непосредственно, ЭЛЕМЕНТА,
нам же нужен именно список правил,
для таблицы стилей(первое выражение для IE)*/
var scrollOffset = style.marginTop;//Собственно, получаем начальный отступ из стилей
scrollOffset = scrollOffset.substr(0, scrollOffset.length-2)//убираем злосчастные `px`
window.onscroll = function() {
if(window.pageYOffset > scrollOffset){
elem.className = 'scrolled';
return;
}
elem.className = '';
};
body {height: 2000px; padding: 0px; margin: 0px;}
div#test {
width: 200px;
height: 200px;
background-color: black;
margin-top: 7px;
}
.scrolled{
position: fixed;
margin-top: 0px !important;
/*Свойства стилей для id перекрывают свойства для классов,
посему так, но для новичков: это BAD PRACTICE!*/
box-sizing: border-box;
background-color: red !important;
/*Просто, дабы понимать, что сейчас на нем висит класс*/
}
<div id='test'></div>
Никакими ухищрениями сделать плавный скролл через onscroll не получится. Проблема в том, что за время поворота колеса мыши вылетает 5-12 событий onwheel, которые трансформируются в onscroll. Ваш код пытается их переварить - и получаются скачки.
Событие scroll не всплывает, поэтому стандартный scroll невозможно отменить через preventDefault.
Возился с этой проблемой довольно долго. Пришлось перехватывать onWheel и анимировать плавно до нужного места. Анимацию делал на jQuery, здесь в рамках ответа на javascript анимацию не ставил - просто скроллинг окна и transfrom: translate
.
Важное замечание. Браузер по-разному обрабатывает top
и transform
, есть примеры в Сети, что transform
работает намного более плавно.
Приведенный ниже код перехватывает onWheel, накапливает события в течение 150мс, чтобы отследить полное единичное движение колеса, затем поднимает флажок animating
. Во время "анимации" скрипт не воспринимает более никакие новые события скролла, один раз прокручивает окно на полную ранее просуммированную величину скролла, изменяет положение черного квадрата через transform
и через 100мс сбрасывает флажок animating
.
Эти величины - 150 и 100мс - сугубо эмпирические и подгоняются под конкретную задачу, особенно в том случае, если скрипт осуществляет анимацию элемента.
// Так квадрат дергается
// window.onscroll = function() {
// document.getElementsByTagName('div')[0].style.transform = 'translateY(' + window.pageYOffset + 'px' + ')';
// return false;
// };
// А так - не дергается
var animating = false;
var timeoutID;
function onWheel(event) {
event = event || window.event;
var pos = event.deltaY || event.detail || event.wheelDelta;
console.log(pos);
if (animating) {
finalPos = finalPos + pos;
event.preventDefault();
return false;
}
if (pos > 0) {
// downscroll code
if (!animating) {
// Scroll
animating = true;
finalPos = pos;
event.preventDefault();
clearTimeout(timeoutID);
timeoutID = setTimeout(function() {
console.log('scroll to ' + finalPos);
window.scrollTo(window.scrollX, window.scrollY + finalPos);
document.getElementsByTagName('div')[0].style.transform = 'translateY(' + window.pageYOffset + 'px' + ')';
setTimeout(function() {
animating = false;
}, 100);
}, 150);
}
} else {
// upscroll code
if (!animating) {
// Scroll
animating = true;
finalPos = pos;
event.preventDefault();
clearTimeout(timeoutID);
timeoutID = setTimeout(function() {
console.log('scroll to ' + finalPos);
window.scrollTo(window.scrollX, window.scrollY + finalPos);
document.getElementsByTagName('div')[0].style.transform = 'translateY(' + window.pageYOffset + 'px' + ')';
setTimeout(function() {
animating = false;
}, 100);
}, 150);
}
}
}
if (window.addEventListener) {
if ('onwheel' in document) {
window.addEventListener("wheel", onWheel, {passive: false, capture: true}); // IE9+, FF17+, Ch31+
} else if ('onmousewheel' in document) {
window.addEventListener("mousewheel", onWheel); // устаревший вариант события
} else {
window.addEventListener("MozMousePixelScroll", onWheel); // Firefox < 17
}
} else {
window.attachEvent("onmousewheel", onWheel); // IE8-
}
Посмотреть работающий код можно тут в jsfiddle или тут на странице тестового сайта.
Виртуальный выделенный сервер (VDS) становится отличным выбором
Подскажите как записать данные в JSON файл? Мне нужно, чтобы после заполнения полей и нажатия на кнопку Save данные сохранялись в JSON файле
Подключил модуль request-promiseДля отправки файла использую вот такой код
Есть этот элементКак мне ему сделать display none, если data-date="2017-02-30"