JavaScript: есть ли способ автоматически инициализировать элементы в живой коллекции?

Рассмотрим следующий пример

// a sample constructor
var SampleConstructor = function(element,options);

// a full live collection
var domCollection = document.getElementsByTagName('*');

// bulk init
for (var i = 0; i < domCollection.length; i++) {
  if ('some conditions required by component') {
    new SampleConstructor( domCollection[i], {});
  }
}

Вопросы

  • Будут ли новые добавленные элементы в DOM инициализированы образцом конструктора?
  • Если нет, то есть ли способ сделать это без jQuery и без циклического перебора коллекции на интервальной основе?

Заметка

Нужное решение для IE8+

2 ответа

Вот пример кода, иллюстрирующий мой комментарий. Однако, как вы можете видеть, он не отслеживает изменения DOM, на самом деле, я предпочитаю противоположный способ, который широко используется современными JavaScript-фреймворками, такими как Angular: наблюдать за структурой необработанных данных и соответствующим образом обновлять DOM.

// Observable

Observable = function () {
  this.observers = [];
};

Observable.prototype.addObserver = function (observer) {
  this.observers.push(observer);
};

Observable.prototype.emit = function (evt, args) {
  var i, n = this.observers.length;
  for (i = 0; i < n; i++) {
    this.observers[i].update(this, evt, args);
  }
};

// Collection

Collection = function () {
  this.items = [];
  Observable.call(this);
};

Collection.prototype = new Observable();

Collection.prototype.size = function () {
  return this.items.length;
};

Collection.prototype.add = function (item) {
  this.items.push(item);
  this.emit("added", [item]);
};

Collection.prototype.removeAt = function (i) {
  var items = this.items.splice(i, 1);
  this.emit("removed", [items[0], i]);
};

// program

var i, s = "h*e*l*l*o";
var collection = new Collection();
var words = document.getElementsByTagName("div");
var wordA = words[0], wordB = words[1];

collection.addObserver({
  update: function (src, evt, args) {
    this[evt](args);
  },
  added: function (args) {
    wordA.appendChild(
      this.createSpan(args[0])
    );
    wordB.appendChild(
      this.createSpan(args[0])
    );
  },
  removed: function (args) {
    wordB.removeChild(
      wordB.childNodes[args[1]]
    );
  },
  createSpan: function (c) {
    var child;
    child = document.createElement("span");
    child.textContent = c;
    return child;
  }
});

for (i = 0; i < s.length; i++) {
  collection.add(s[i]);
}

for (i = 1; i < 5; i++) {
  collection.removeAt(i);
}

function rdm (max) {
  return Math.floor(
    Math.random() * max
  );
}

function addRdmLetter () {
  collection.add(
    (rdm(26) + 10).toString(36)
  );
}

function removeRdmLetter () {
  var n = collection.size();
  if (n > 0) collection.removeAt(rdm(n));
}

function showLetters () {
  alert(collection.items.join(""));
}
body {
  font-size: 16px;
  font-family: Courier;
}

span {
  padding: 5px;
  display: inline-block;
  margin: -1px 0 0 -1px;
  border: 1px solid #999;
}

#buttons {
  position: absolute;
  top: 10px;
  right: 10px;
}
<p>wordA</p><div></div>
<p>wordB</p><div></div>
<div id="buttons">
  <button type="button" onclick="addRdmLetter()">Add letter</button>
  <button type="button" onclick="removeRdmLetter()">Remove letter</button>
  <button type="button" onclick="showLetters()">Show letters</button>
</div>

function compare(arr,newarr,callback){
  var index=0;
  var newindex=0;
  while(newarr.length!=newindex){
   if ( arr[index] == newarr[newindex]) {
     index++; newindex++;
   } else {
     callback (newarr[newindex]);
     newindex++;
   }
  }
}
//onload
var store=[];
compare([],store=document.getElementsByClassName("*"),yourconstructor);
//regular
var temp=document.getElementsByClassName("*");
compare(store,temp,yourconstructor);
store=temp;

Я думаю, что это наиболее эффективно проверить. Единственное решение, которое я знаю, это делать это регулярно, используя setTimeout. Другим способом было бы обнаружить все изменения JS DOM, что-то вроде:

var add = Element.prototype.appendChild;
Element.prototype.appendChild=function(el){
 yourconstructor(el);
 add.call(this,el);
};

Примечание: очень хакерский

Другие вопросы по тегам