2016-02-21 2 views
1

Я пытаюсь работать через Udacity JavaScript Design Patterns course. Одним из практических проектов является создание страницы с несколькими фотографиями кошек. На каждой фотографии есть свой заголовок и счетчик, указывающий, сколько раз на каждую фотографию было нажато. Я начал с того, что все было жестко закодировано в html, но теперь я пытаюсь сделать его более простым и простым в обновлении, создав большую часть страницы из JavaScript. Я смог получить весь текст и изображения, чтобы показать, и у меня есть счетчик второго изображения, когда он нажимается, но я не могу понять, почему первое изображение не обновляет счетчик. Нажатие на нее даже не запускает «click» EventListener.JavaScript addEventListener в цикле

HTML:

<html> 
<body> 
<div id="cats"></div> 
</body> 
<script src="catclick.js"></script> 
</html> 

JS:

"use strict"; 

var cat1 = {}; 
cat1.photo = "cat.jpg"; 
cat1.name = "Whiskers"; 
cat1.count = 0; 

var cat2 = {}; 
cat2.photo = "cat2.jpg"; 
cat2.name = "Socks"; 
cat2.count = 0; 

var cats = [cat1, cat2]; 

var catDiv = document.getElementById('cats'); 

function increaseCount(cat, span) { 
    cat.count++; 
    span.innerHTML = cat.count; 
} 

for (var i=0; i<cats.length; i++) { 
    (function() { 
     var currCat = cats[i]; 

     var existingHTML = catDiv.innerHTML; 
     var newHTML = '<h3>' + currCat.name + '</h3><img id="' + currCat.name + '-photo" src="' + currCat.photo + '">'; 
     newHTML += '<p>' + currCat.name + ' has been clicked <span id="' + currCat.name + '-count">0</span> times.</p>';  
     catDiv.innerHTML = existingHTML + newHTML; 

     var photoObj = document.getElementById(currCat.name + "-photo"); 
     var countSpan = document.getElementById(currCat.name + "-count"); 

     photoObj.addEventListener('click', function(){increaseCount(currCat, countSpan);}, false); 
    }()) 
} 

я сделать массив из двух кошки объектов, получить ссылку на DIV в моем HTML, определить функцию increaseCount, которая обновляет span, содержащий кол-во кликов данной фотографии, а затем цикл каждого объекта cat в моем массиве, генерирование html для их названия, изображения и счетчика перед добавлением прослушивателя событий, когда их изображение является кликом рунец.

Второе изображение работает так, как ожидалось, но первое не запускает прослушиватель событий. Я думал, что это может быть связано с closure, но я завернул все в цикл в функции.

Update

С предложением заостренные, я обновил петлю следующим образом, и он работает, как ожидалось. Я также добавил i к функции, как было предложено, хотя я не уверен, что это действительно необходимо в этом случае.

for (var i=0; i<cats.length; i++) { 
    (function (i) { 
     var currCat = cats[i]; 

     var newDiv = document.createElement("div"); // div for this cat 

     var catTitle = document.createElement("h3"); // cat name 
     catTitle.appendChild(document.createTextNode(currCat.name)); 
     newDiv.appendChild(catTitle); 

     var catPhoto = document.createElement("img"); // cat photo 
     catPhoto.setAttribute("id", currCat.name + "-photo"); 
     catPhoto.setAttribute("src", currCat.photo); 
     newDiv.appendChild(catPhoto); 

     var catPara = document.createElement("p"); // cat click count 
     var catSpan = document.createElement("span"); 
     catSpan.setAttribute("id", currCat.name + "-count"); 
     catSpan.appendChild(document.createTextNode("0")); 
     catPara.appendChild(document.createTextNode(currCat.name + " has been clicked ")); 
     catPara.appendChild(catSpan); 
     catPara.appendChild(document.createTextNode(" times.")); 
     newDiv.appendChild(catPara); 

     catDiv.appendChild(newDiv); 

     catPhoto.addEventListener('click', function(){increaseCount(currCat, catSpan);}, false); 
    }(i)); 
} 
+2

При установке '.innerHTML', даже если вы кладете обратно предыдущее содержимое вы проигрышные задания обработчиков событий. Назначения обработчика событий связаны с самими узлами DOM, и перезапись '.innerHTML' удаляет эту часть DOM и создает целое новое поддерево. – Pointy

+2

Разделите его на два отдельных цикла: сначала создайте контент, а затем назначьте обработчики событий. Или создайте контент, добавив узлы DOM вместо перезаписывания DOM через '.innerHTML'. – Pointy

+0

Спасибо, Поинты. – WhiteHotLoveTiger

ответ

2

Есть пара вещей.

Сначала вам нужно пройти в i функции:

(function (i) { 
    var currCat = cats[i]; 
    ... 
}(i)); 

Но вторая точка является более сложным. Вы создаете элементы «на лету» и пытаетесь подключить к ним слушателей событий, которые не работают. То, что вам нужно использовать, это event delegation - привязка прослушивателя событий к родительскому элементу и перехват событий, которые пузырятся из прикрепленных элементов.

Необходимо внести некоторые изменения в ваш код, чтобы сделать эту работу.

1) Добавить пару из данных атрибутов элементов изображения для ссылки на индекс кошки, и имя кошки:

<img data-name="' + currCat.name + '" data-index="' + i + '" + id="' + currCat.name + '-photo" src="' + currCat.photo + '"> 

2) Создание нового слушателя событий на catDiv элемент, подбирая значения из набора данных элемента clicked, передавая эти значения в inceaseCount.

catDiv.addEventListener('click', function(e) { 
    if (e.target && e.target.nodeName == "IMG") { 
    var data = e.target.dataset; 
    increaseCount(data.index, data.name + '-count'); 
    } 
}); 

3) Перепишите функцию increaseCount для учета этих изменений.

function increaseCount(index, span) { 
    cats[index].count++; 
    document.getElementById(span).innerHTML = cats[index].count; 
} 

Working example

+0

Это выглядит так, как будто он должен работать, но на самом деле я все равно получаю такое же поведение. – WhiteHotLoveTiger

+0

Я сделал JSFiddle: https://jsfiddle.net/90aybuxq/ – WhiteHotLoveTiger

+0

Я знаю, в чем проблема. Медведь со мной ... :) – Andy

Смежные вопросы