JavaScript: цикл for в динамическом переключении не работает - PullRequest
0 голосов
/ 03 ноября 2018

Я пытаюсь создать динамическую функцию, используя цикл for в javascript, который будет запускать ролловеры. Я использую JS против CSS, так как количество изображений, которые будут перемещаться, растет, и я полагаю, что функцию легче поддерживать, чем x количество селекторов.

Это создает on method похожий на jQuery.

var on = function(event, elem, callback, capture) {
  if (typeof elem === 'function') {
    capture = callback;
    callback = elem;
    elem = window;
  }
  capture = capture ? true : false;
  elem = typeof elem === 'string' ? document.querySelector(elem) : elem;
  if (!elem) return;
  elem.addEventListener(event, callback, capture);
};

Это мои функции rollOver и rollOut:

function rollOver(elem) {
  document.getElementById(elem).src = `/images/home-page/desktop/EYES_ON_YOU_desktop_HP_HOVER_${elem.slice(length-1)}.jpg?$staticlink$`
}

function rollOut(elem) {
  document.getElementById(elem).src = `/images/home-page/desktop/EYES_ON_YOU_desktop_HP_NO_HOVER_${elem.slice(length-1)}.jpg?$staticlink$`
}

И вот где живет мой цикл for:

  document.addEventListener("DOMContentLoaded", function(event) {
      var rollOverCollectionA = document.getElementById('roll-over-collection-a').querySelectorAll('img');
          rollOverCollectionA = Array.prototype.slice.apply(rollOverCollectionA);

          for (var i = 0; i < rollOverCollectionA.length; i++) {
           on('mouseover', rollOverCollectionA[i].id, function(){
             console.log( rollOverCollectionA[i].id)
             rollOver(rollOverCollectionA[i].id);
           });

           on('mouseout', rollOverCollectionA[i].id, function(){
            rollOut(rollOverCollectionA[i].id);
           }); 
          }

    });

Ответы [ 2 ]

0 голосов
/ 03 ноября 2018

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

В современных браузерах решение состоит в том, чтобы использовать let вместо var и, следовательно, запустить цикл как

for (let i = 0; i < rollOverCollectionA.length; i++) ...

Для обсуждения и более старых решений см. Закрытие JavaScript внутри циклов - простой практический пример

В отношении вычисления строки источника изображения

/images/home-page/desktop/EYES_ON_YOU_desktop_HP_HOVER_${elem.slice(length-1)}.jpg?$staticlink$

пожалуйста, просмотрите, что нужно - если вам нужно скопировать все значение elem в виде строки, не включайте вызов slice. Если часть строки требуется, отправленный код может быть правильным. Вырезание из начального индекса elem.length-1 скопирует последнюю букву идентификатора элемента (конечно) и также может быть правильным.


Обновление: Необходимость захвата значения i во время итерации цикла может быть устранена как минимум двумя способами:

  1. В обработчиках mouseover и mouseout замените rollOverCollectionA[i] на this. Нет необходимости в обратном поиске коллекции HTML на основе захваченного значения индекса, чтобы определить элемент, к которому прикреплен обработчик события.

  2. Используйте делегирование события с одним слушателем, подключенным к контейнеру DOM изображений. Использование той же функции on и elem.id.slice(length-1) в качестве возможного суффикса источника изображения, аналогично:

    document.addEventListener("DOMContentLoaded", function(event) {
        var rollOverCollectionA = document.getElementById('roll-over-collection-a');
        on('mouseover', rollOverCollectionA, function( event){
            var elem = event.target;
            if( elem && elem.id && elem.tagName === 'IMG') {
                 elem.src = `/images/home-page/desktop/EYES_ON_YOU_desktop_HP_HOVER_${elem.id.slice(length-1)}.jpg?$staticlink$`;
        }
        });
        on('mouseout', rollOverCollectlonA, function(event) {
            var elem = event.target;
            if( elem && elem.id && elem.tagName === 'IMG') {
                 elem.src = `/images/home-page/desktop/EYES_ON_YOU_desktop_HP_NO_HOVER_${elem.id.slice(length-1)}.jpg?$staticlink$`;
            }
        });
    
    });
    
0 голосов
/ 03 ноября 2018

Основные проблемы, которые я видел, были:

  • elem.slice(length - 1); должно быть elem.slice(elem.length - 1) в противном случае вы вычитаете 1 из неопределенного
  • elem.slice следует заменить на elem.substr(elem.lastIndexOf('-') + 1), в противном случае любые изображения свыше 9 будут начинаться с 0, поскольку вы получите только последний символ идентификатора.
  • Когда вы передаете строку как elem в on, она использует document.querySelector, но вы передаете идентификатор без хеш-символа (#). В любом случае вам это не нужно, поскольку у вас уже есть ссылка на элемент изображения, вы можете просто передать это.

Я также привел это в порядок и немного модернизировал.

Яркой проблемой, о которой я не упомянул, было использование var и цикла for(;;). Спасибо @ tranktor53 за указание на это. Я всегда инстинктивно заменяю циклы for(;;) на циклы for...in или for...of там, где я их вижу, и меняю их на let или const, я даже не замечал, что это было частью проблемы.

function on({ type, element = window, callback, capture = false }) {
  if (typeof element === 'string') element = document.querySelector(element);
  if (!element) return;
  element.addEventListener(type, callback, capture);
};
function rollOver({ element, id }) {
  element.src = `https://via.placeholder.com/200x100?text=${ id }+hover`;
}
function rollOut({ element, id }) {
  element.src = `https://via.placeholder.com/200x100?text=${ id }+no+hover`;
}
document.addEventListener("DOMContentLoaded", _ => {
  const elements = document.querySelectorAll('#roll-over-collection-a img');
  for(let element of elements) {
    const id = element.id.substr(element.id.lastIndexOf('-') + 1);
    on({ type: 'mouseover', element, callback: _ => rollOver({ element, id }) });
    on({ type: 'mouseout' , element, callback: _ => rollOut({ element, id }) });
  }
});
<div id="roll-over-collection-a">
  <img id="roll-over-1" src="https://via.placeholder.com/200x100?text=1+no+hover">
  <img id="roll-over-2" src="https://via.placeholder.com/200x100?text=2+no+hover">
  <img id="roll-over-3" src="https://via.placeholder.com/200x100?text=3+no+hover">
  <img id="roll-over-4" src="https://via.placeholder.com/200x100?text=4+no+hover">
  <img id="roll-over-5" src="https://via.placeholder.com/200x100?text=5+no+hover">
  <img id="roll-over-6" src="https://via.placeholder.com/200x100?text=6+no+hover">
</div>
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...