Как динамически добавить прослушиватель событий в NodeElement

Здесь мне нужно добавить прослушиватель событий щелчка к серии элементов span с миниатюрами изображений, чтобы сделать их доступными для выбора. Они создаются динамически, когда пользователь вводит файл, используя относительную форму.

До сих пор мне удавалось ссылаться на вновь созданные дочерние узлы выходного элемента, которые их содержат.

HTML:

<div id="imageBox"><output id="list"><!-- Newly created span elements here --></output></div>

Относительный скрипт с глобальной областью действия:

var father = document.getElementById('list');
var children = father.childNodes;

Затем я обрабатывал клики глобально в прослушивателе элемента body:

document.body.addEventListener('click', function( event ) {

if (children) {

for (var i = 0; i < children.length; i++) {

  children[i].addEventListener("click", function(){
    if(this.style.boxShadow === '') this.style.boxShadow ='0 0 1em blue';
    else this.style.boxShadow = '';}, false);
    }
  }

}, false);

Но, как я и ожидал, он работает, просто дважды щелкнув новый элемент.

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

function handleFileSelect(evt) {
var files = evt.target.files; // FileList object

// Loop through the FileList and render image files as thumbnails.
for (var i = 0, f; f = files[i]; i++) {

  // Only process image files.
  if (!f.type.match('image.*')) {
    continue;
  }

  var reader = new FileReader();

  // Closure to capture the file information.
  reader.onload = (function(theFile) {
    return function(e) {
      // Render thumbnail.
      var span = document.createElement('span');
      span.innerHTML = ['<img class="thumb" src="', e.target.result,'" title="', escape(theFile.name), '"/>'].join('');
      document.getElementById('list').insertBefore(span, null);

      console.log(children.length);

      clickable();
    };
  })(f);

  // Read in the image file as a data URL.
  reader.readAsDataURL(f);
}


}

function clickable(){
if (children) {

for (var i = 0; i < children.length; i++) {

  children[i].addEventListener("click", function(){
    if(this.style.boxShadow === '') this.style.boxShadow ='0 0 1em blue';
    else this.style.boxShadow = '';}, false);
    }
  }
}

Любая идея о том, как справиться с этим, чтобы заставить его работать одним щелчком мыши?

Скрипка:

https://jsfiddle.net/b130p9tb/2/

ПРОГРЕСС ОБНОВЛЕНИЕ:

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

Обновленная скрипта: https://jsfiddle.net/b130p9tb/3/


person iomv    schedule 14.11.2015    source источник
comment
Пожалуйста, покажите обратный вызов, который вы пытались добавить, чтобы мы могли увидеть, что вы сделали неправильно.   -  person Barmar    schedule 14.11.2015
comment
Можете ли вы поделиться существующим кодом или демо над jsfiddle. Это поможет нам понять реальную проблему.   -  person Shahzad Fateh Ali    schedule 14.11.2015


Ответы (1)


Проблема в том, что вы добавляете слушателей ко всем элементам каждый раз, когда добавляете изображение. Итак, когда вы добавляете первое изображение, у вас есть один прослушиватель событий. Затем, когда вы добавляете второе изображение, ваш первый элемент имеет 2 прослушивателя событий. Таким образом, он выбирает, а затем сразу же отменяет выбор. И т.п.

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

document.getElementById('list').addEventListener("click", function (e) {
    e.target.classList.toggle('selected');
}, false);

https://jsfiddle.net/ugvqy1r5/1/

person Julien Grégoire    schedule 15.11.2015
comment
Я почти уверен, что использовал подход добавления прослушивателя событий в «список» ранее во время своих тестов, но по какой-то причине теперь это сработало для меня. Я рад, что вы объяснили мне, в чем была проблема, и использование свойства toggle приятно. - person iomv; 15.11.2015