【问题标题】:JavaScript: is there a way to initialize elements in a live collection automatically?JavaScript:有没有办法自动初始化实时集合中的元素?
【发布时间】:2017-01-14 10:42:24
【问题描述】:

考虑以下示例

// 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+

【问题讨论】:

标签: javascript initialization live htmlcollection


【解决方案1】:

这是一个代码示例来说明我的comment。然而,正如你所看到的,它不会跟踪 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>

【讨论】:

  • 这种方法很有趣。我有兴趣让 AngularJS 的用户都满意,无论是动态操作 DOM 的任何 JS,对于我的 bootstrap.native 库,也许您可​​以帮助提供一种轻量且快速的方法来进行此更新。跨度>
  • 此时我正在寻找一个小实用函数来做onpropertychange | DOMAttrModified | DOMNodeInserted,完成这项工作的 4-5 行代码。我仍然愿意接受您可能提出的任何建议,因为我不知道 AngularJS。
  • @thednp 这里与 Angular 没有任何共同之处,除了著名的数据绑定模式(数据更改 -> 更新 DOM),您可以通过多种方式重现。我只是想向您展示,如果您可以完全控制 DOM 操作会更好,但根据您的情况,您可能无法做到这一点。不过我的贡献就到此为止了。
【解决方案2】:
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);
};

注意:非常老套

【讨论】:

  • propertyChange 事件怎么样?我正在阅读msdn.microsoft.com/en-us/library/ms536956(v=vs.85).aspx
  • 注意更改子元素的 innerText 或 innerHTML 不会导致父元素的 onpropertychange 事件触发。
  • 我认为 propertyChange 事件在我 appendChild 时触发,它会更改 document.all.length,记住我有兴趣找到一种方法来检查何时将新项目添加到 DOM。
  • 这是一个重点。你还需要找到添加的元素,使用上面的代码......
  • 是的,所以我不需要Element.prototype.appendChild hack,我会找到另一种方法。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-04-19
  • 1970-01-01
  • 2020-09-05
  • 2021-02-26
  • 1970-01-01
  • 2016-03-30
相关资源
最近更新 更多