Несколько месяцев назад писал свою первую навигацию по странице. Сейчас столкнулся с той же задачей и решил немного усовершенствовать код, чуть красивее чтоли переписать и слегка расширить. Но во время отладки возник вопрос – почему в одном случае требуется "убивать" действие по умолчанию на фазе погружения, а в другом нет?
Вот мой старый код:
function pageNav(e) {
var link = e.target.closest('[data-nav~="page-nav"]');
if(link) {
link.onclick = function(){return false};/*1*/
var href = link.getAttribute('href').slice(1);
if(href.length >= 1) {
var elem = document.getElementById(href);
var distance = Math.ceil(elem.getBoundingClientRect().top);
var step = (distance > 0) ? 20 : -20;
distance = Math.abs(distance);
var smoothScrolling = setInterval(function move() {
if(distance > Math.abs(step) ) {
window.scrollBy(0, step);
distance -= 20;
}
else {
var lastStep = (step > 0) ? distance : -distance;
window.scrollBy(0, lastStep);
clearInterval(smoothScrolling);
}
}, 7)
}
}
}
window.addEventListener('click', pageNav, true);/*2*/
Он реализован через делегирование на всю страницу. Здесь важна строка с меткой 1, в которой отменяется действие по умолчанию, когда мы находим ссылку. В строке с меткой 2 вешается обработчик, где событие обрабатывается при погружении, т.к. прервать переход по ссылке на фазе всплытия не удалось из-за того, что событие на внутреннем элементе всплывает раньше.
Теперь второй вариант кода, не окончательный, но то что нужно в нём присутствует:
function NavigatorMenu(elem) {
elem.onclick = function(e) {
let link = e.target.closest('[data-href], a');
if(link && this.contains(link)) smoothNavigator(link, 20, 7, e);
}
}
function smoothNavigator(elem, stepSize, stepTime, event) {
if(elem.tagName == 'A') event.preventDefault();/*3*/
let href/*id*/ = (elem.tagName == 'A') ? elem.getAttribute('href').slice(1) : elem.dataset.href;
if(href < 1) return;
let moveTo = document.getElementById(href);
let distance = Math.ceil(moveTo.getBoundingClientRect().top);
stepSize = (distance > 0) ? stepSize : -stepSize;
distance = Math.abs(distance);
let smoothScrolling = setInterval(function move() {
if(distance > Math.abs(stepSize) ) {
window.scrollBy(0, stepSize);
distance -= 20;
} else {
let lastStep = (stepSize > 0) ? distance : -distance;
window.scrollBy(0, lastStep);
clearInterval(smoothScrolling);
}
}, stepTime);
}
let menu = new NavigatorMenu(document.getElementById('main-nav') );
Здесь же обработчик повешен через onclick, т.е. обработка спокойно происходит на фазе всплытия. Хотя в строке с меткой 3 остановка действия браузера по умолчанию должна произойти после того, как осуществится переход по ссылке, т.е. при обработке внешнего элемента на который повешен обработчик – так вижу последовательность выполнения кода я. Может глаз уже замылился. Почему получается так что событие, которое должно сначало всплыть на ссылке, а потом на элементе-меню во втором варианте кода меняет свой порядок? Основная разница, которую я вижу – это addEventListener/onclick и return false/preventDefault.
Виртуальный выделенный сервер (VDS) становится отличным выбором
В чём опасность использования forin для объекта или массива?
как присвоить переменной значение параметра style через его класс?