2017-01-07 9 views
0

Я пришел на нечто совершенно странное, и я не могу понять, как его решить.Eventlistener wont register click

Я работаю над проектом в университете, где нам поручено создать игру, чтобы оценить интеллект пользователя. Каждая игра - это собственный модуль.

Тот, над которым я сейчас работаю, в основном отображает кучу флагов в течение секунды, прежде чем перевернуть их, используя window.setTimeout. Это работает абсолютно нормально, переход и все выглядит гладко. За время, когда я настраиваю доску (показывая флаги), я также даю каждому флагу eventListener, который слушает clicks, который переворачивает флаг по его оси Y.

Однако последняя часть задания заключается в создании и отображении списка флагов. Я использую отдельную функцию под названием set_list, которая просто добавляет упорядоченный список к innerHTML игрового поля.

Но всякий раз, когда я добавляю список, eventListener ломается (т. Е. Он просто не будет активен при нажатии перевернутых флагов).

Here is a JSFiddle that might help describe the issue

Сама игра запускается при нажатии кнопки. Таким образом, в основном есть кнопка со своим собственным eventListener, которая должна быть нажата для игрового поля, чтобы начать:

document.getElementById('start').addEventListener('click', function(){ 
    setup_cards(); 
    create_cards(); 
    set_list(); 
}); 

И эти две функции, которые, кажется, вносит беспорядок вещей:

function create_cards() { 
    for (i = 0; i < cards_arr.length; i++) { 
     if (i == 3 || i == 6) { 
      flag_divs += "</div><div class='row flag-buffer'>" 
     } 
     if (flags[cards_arr[i]].name == 'Colombia' || flags[cards_arr[i]].name == 'Chile' || flags[cards_arr[i]].name == 'Japan') { 
      flag_divs += "<div id='flag_" + i + "' class='flip-container col-xs-2 col-xs-offset-1'>" + 
         "<div class='front'>" + 
         "</div>" + 
         "<div class='back'>" + 
         specialflag(flags[cards_arr[i]].name) + 
         "</div>" + 
         "</div>"; 
     } else { 
      flag_divs += "<div id='flag_" + i + "' class='flip-container col-xs-2 col-xs-offset-1'>" + 
          "<div class='front'>" + 
          "</div>" + 
          "<div class='back'>" + 
          "<div id='" + flags[cards_arr[i]].class + "' class='flag'> </div>" + 
          "</div>" + 
          "</div>"; 
     } 
    } 
    board.innerHTML = '<h3 class="text-center"> Memorize the flags </h3><div class="container-fluid"> <div class="row">' + flag_divs + '</div></div>'; 
    var myNodeList = document.getElementsByClassName('flip-container'); 



    for (var iterator = 0; iterator < myNodeList.length; iterator++) { 

     var el = document.getElementById(myNodeList["flag_" + iterator].id); 
     el.id = iterator; 
     //console.log(el); 
     el.style.transform = 'rotateY(180deg)'; 
     el.classList.add('flipper'); 
     el.addEventListener('click', function() { 
      animate(this); 
     }); 
     var animate = function (sender) { 
      sender.style.transform = "rotateY(0deg)"; 
      console.log("animating"); 
      sender.style.transform = "rotateY(180deg)"; 
      sender.classList.add('flipper'); 

     }; 
    } 
    window.setTimeout(() => { 
     for (var iterator = 0; iterator < myNodeList.length; iterator++) { 
      var el = document.getElementById(myNodeList[iterator].id); 
      el.id = iterator; 
      el.style.transform = 'rotateY(0deg)'; 
      console.log("I'm done!"); 
     } 
    }, 1000); 
} 

function set_list() { 
    console.log("I'm in"); 
    var flag_list = "<ol>"; 
    for (var i = 0; i < cards_arr.length; i++) { 
     flag_list += "<li>" + flags[cards_arr[i]].name + "</li>"; 
    } 
    flag_list += "</ol>"; 
    board.innerHTML += flag_list; 
    console.log(board.innerHTML); 
} 
+0

Вы проверили свою консоль на наличие ошибок? – NewToJS

+0

@NewToJS Хорошее предложение, но да. Я делал это несколько раз локально. Хотя я не уверен в ошибке в скрипке. – geostocker

+0

Попробуйте использовать этот скрипт https://jsfiddle.net/h5vqLcpf/1/ – NewToJS

ответ

0

Ваша проблема здесь:

board.innerHTML += flag_list; 

Что это делает прошу содержание board элемента в виде HTML-строке, добавив еще несколько HTML до конца этой строки, а затем удаление содержимого из board и заменяя их разобранную строку. У вновь созданного узла кнопки запуска нет подключенного прослушивателя событий, поэтому ничего не происходит.

Использование element.innerHTML += some_html - плохая идея по многим причинам, являясь одним из них. Лучше всего избегать использования .innerHTML всякий раз, когда вы можете.

  • Положить большую часть текста/HTML вашей игры, как вы можете (в данном случае, кнопки пуска, в частности, а также текст инструкции) в исходной статической HTML вместо того чтобы использовать JS, чтобы добавить его.
  • Чтобы управлять существующим HTML, используйте операции манипулирования узлами DOM, такие как document.createElement и element.appendChild, которые работают с точки зрения дерева DOM вместо текста.
  • Относительно безопасное использование для .innerHTML заключается в том, чтобы установить начальное содержимое только что созданного элемента.

Тем не менее, самое простое исправление для существующего кода, чтобы изменить порядок, в котором вещи случиться так, что вы делаете addEventListenerпосле последнего времени вы используете innerHTML. То есть, возьмите код слушателя событий из create_cards и поместите его (в функцию или нет, как вам нравится), где он будет вызываться после set_list().


Кроме того, построение HTML с помощью конкатенации строк, как вы делаете

... + "<div id='" + flags[cards_arr[i]].class + "' class='flag'> </div>" + ... 

очень плохая практика, потому что - не в этом случае, а в других - это приводит к ошибкам безопасности XSS. Рассмотрим, что произойдет, если строка, которую вы вставляете, содержит символ кавычки.

Использование методов DOM (createTextNode, setAttribute или свойств и т. Д.) Для создания узлов - это хороший способ избежать рисков XSS, поскольку вам не нужно убеждать в том, что текст цитируется или дезинформируется.

+0

Не считая вопросов XSS и безопасности, поскольку это не входит в сферу назначения, как я могу это исправить? Более конкретно, в коде. Я знаю, что это плохая практика, чтобы спросить об этих вещах, когда речь идет о назначениях и т. Д., Но в этом случае я честно не успеваю реструктурировать код или идею о том, как действовать с тем, что у меня есть. Я даже не понимаю, почему происходит это странное взаимодействие между addEventListener и setTimeout ...:/ – geostocker

+0

@geostocker Похоже, вас учат с плохих примеров. Я бы рекомендовал найти лучшую инструкцию. Но я отредактировал свой ответ, чтобы предложить простое исправление. –

0

Могли бы вы добавить некоторые неопределенные тесты после getElementById() вызывает, например:

if (el == null) { 
    // Error handler. 
} else { 
    // Your existing code. 
}