Всплытие событий

157
29 октября 2018, 14:40

Несколько месяцев назад писал свою первую навигацию по странице. Сейчас столкнулся с той же задачей и решил немного усовершенствовать код, чуть красивее чтоли переписать и слегка расширить. Но во время отладки возник вопрос – почему в одном случае требуется "убивать" действие по умолчанию на фазе погружения, а в другом нет?

Вот мой старый код:

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.

READ ALSO
Валидация vue.js

Валидация vue.js

Всем привет,написал авторизацию,и пару проверок написано в таком виде

168
В чём опасность использования for .. in для объекта или массива?

В чём опасность использования for .. in для объекта или массива?

В чём опасность использования forin для объекта или массива?

160
Как сделать сортировку div-ов в JavaScript?

Как сделать сортировку div-ов в JavaScript?

Нужно сортировать не вертикально а горизонтально!

231
Как считать значение параметра тега HTML в js?

Как считать значение параметра тега HTML в js?

как присвоить переменной значение параметра style через его класс?

154