Почему window.onload и window.addEventListener(«загрузка», функция) реагируют по-разному?

#javascript #html

#javascript #HTML

Вопрос:

Я столкнулся с этой проблемой, когда они не реагируют одинаково. В основном html и css (или вы можете напрямую перейти на javascript. Я включу html и css для контекста).

 <body>
  <div class="container">
    <div class="box green"></div>
    <div class="box red"></div>
    <div class="box blue"></div>
    <div class="box yellow"></div>
    <div class="box pink"></div>
    <div class="box orange"></div>
    <div class="box yellow"></div>
    <div class="box red"></div>
    <div class="box blue"></div>
    <div class="box pink"></div>
    <div class="box green"></div>
    <div class="box orange"></div>
  </div>
  <div class="score">"Your Score"</div>
</body>
  

Это CSS

     body{
      height: 100vh;
      background: #00aaaa;
      display: flex;
      flex-direction: column;
      align-items: center;
      justify-content: center;
    }
    .container{
      background: rgba(0, 200, 200, .5);
      display: grid;
      grid-template-columns: repeat(4, 100px);
      grid-template-rows: repeat(3, 100px);
      grid-gap: 5px;
    }
    .box:hover{
      border: 2.5px solid black;
    }
    .green{background: green;}
    .red{background: red;}
    .blue{background: blue;}
    .yellow{background: yellow;}
    .pink{background: pink;}
    .orange{background: orange;}
    .score{
      margin-top: 12px;
      width: 415px;
      text-align: center;
     }
  

Окно показывает его цвет в течение 3 секунд после загрузки страницы. И становится серым. Javascript устроен так, что всякий раз, когда вы нажимаете на каждое поле, оно показывает его цвет. Вот javascript.

 let $$ = document.querySelectorAll.bind(document);
let $ = document.querySelector.bind(document);

window.addEventListener("load", setTimeout(colorReset, 3000)); 

function colorReset(){
  $$(".box").forEach((boxColor)=>{
    boxColor.style.background = "grey";
  });
}

function revealColor(x){
  x.style.background = x.classList[1];
}

$$(".box").forEach((boxWithColor)=>{
  boxWithColor.addEventListener("click", ()=>{
    revealColor(boxWithColor);
  });
});
  

Приведенный выше скрипт не отображает цвет окна при нажатии. Но я заменяю window.addEvenListener(«загрузка», функция) на window.onload = setTimeout(«colorReset», 3000); Теперь это работает. Итак, мой вопрос в том, реагируют ли они по-разному?

Комментарии:

1. window.addEventListener("load", setTimeout(colorReset, 3000)); — это не делает то, что вы думаете.

2. Вы ждете 3 секунды после загрузки окна при использовании setTimeout

3. @Dshiz Да, это то, что я пытаюсь сделать. Также через 3 секунды фон каждого окна становится серым. А затем, когда я нажимаю на поле, оно показывает соответствующий цвет. Это то, что я пытаюсь сделать. Но когда я нажимаю, это не соответствует цвету. Он остается серым.

4. Вам также необходимо запустить остальную часть скрипта (особенно $$(".box").forEach((boxWithColor)=>{ часть в DOMContentLoaded обработчике, а не в теле корневого скрипта.

Ответ №1:

В вашем скрипте как есть есть две основные ошибки:

  1. Вы setTimeout неправильно используете addEventListener .
  2. Вы выполняете оценку $$(".box") до того, как HTML был полностью загружен, поэтому document.querySelectorAll вернет пустые или неполные результаты.

Часть 1: addEventListener с setTimeout :

Ваш код должен передавать ссылку на функцию addEventListener , но ваш код фактически передает number значение, потому что вы вызываете setTimeout на сайте вызова, а не передаете ссылку на setTimeout (что в любом случае не сработает, поскольку addEventListener функция обратного вызова должна иметь один Event параметр, а исходное number значение из setTimeout которого возвращает «timer-id» вы можете перейти clearTimeout к отмене активного таймера).

Измените это:

 window.addEventListener("load", setTimeout(colorReset, 3000)); 
  

на это:

 // ES3-style:
window.addEventListener("load", function( e ) { setTimeout(colorReset, 3000); } );

// ES5-style (arrow-function, lambda-function):
window.addEventListener("load", e => setTimeout(colorReset, 3000) );
  

Кроме того, вам следует избегать использования свойств событий в стиле старого стиля (очень, очень старого стиля) onload / onclick / etc, потому что они не поддерживают множественную отправку (по крайней мере, без некоторых грубых хаков).

Часть 2. Пройдите по DOM только после его загрузки.

  • Я предполагаю, что на вашей HTML-странице ваш скрипт находится во встроенном <script> элементе (не используется <script src=""> , который находится в <head> .
    • Это означает, что браузер запустится $$(".box").forEach((boxWithColor)=>{ , когда он немедленно столкнется со сценарием.
    • Это не сработает, потому что при вычислении вышеуказанного селектора * div.box в DOM еще не загружены элементы!

Чтобы исправить это, переместите весь ваш скрипт в отдельный function и передайте его addEventListener( 'DOMContentLoaded' ) . Также рассмотрите возможность использования for-of вместо NodeList.forEach и перемещения setTimeout вызова в функцию, например:

 const $$ = document.querySelectorAll.bind(document);
const $  = document.querySelector.bind(document);

function onDOMLoaded( e ) {
    
    for( const box of $$('.box') ) {
        
        boxWithColor.addEventListener( 'click', ce => revealColor( ce.currentTarget ) );
    }

    setTimeout( colorReset, 3000 );
}
    
window.addEventListener( "DOMContentLoaded", onDOMLoaded ); 

function colorReset() {
  $$(".box").forEach((boxColor)=>{
    boxColor.style.background = "grey";
  });
}

function revealColor(x){
  x.style.background = x.classList[1];
}

  

Комментарии:

1. все еще не сработало. Теперь фон даже не меняется на серый. Сначала он изменил весь свой цвет на серый после отображения цвета для каждого поля в течение 3 секунд.

2. @LForLaddu Я подозреваю, что происходит что-то еще. Пожалуйста, обновите свой вопрос, чтобы включить весь ваш код в виде интерактивного фрагмента или JSFiddle.

3. @LForLaddu Я нашел другую проблему и обновил свой ответ.