JavaScript 模板有几个库(Mustache、下划线模板)。他们所做的是创建新的 DOM 节点。
在我的应用程序中,我试图重用 DOM 节点以减少内存消耗。一个例子是带有分页的缩略图库。当我加载下一个 50 个缩略图时,我重用了相同的 50 个节点。
我可以使用模板库轻松渲染新节点,但是是否有一些模板库可以重用或更新现有节点,而不是创建新节点?
JavaScript 模板有几个库(Mustache、下划线模板)。他们所做的是创建新的 DOM 节点。
在我的应用程序中,我试图重用 DOM 节点以减少内存消耗。一个例子是带有分页的缩略图库。当我加载下一个 50 个缩略图时,我重用了相同的 50 个节点。
我可以使用模板库轻松渲染新节点,但是是否有一些模板库可以重用或更新现有节点,而不是创建新节点?
根据我的经验,创建元素并使用它们进行操作的最快方法是创建尽可能少的元素,在必要时克隆它们,因为这样会更快,然后使用片段来保存它们并尽可能少地对 DOM 进行更改,从而限制重排。我做了很多(简化了很多):
var div = document.createElement('div'),
anchor = document.createElement('a'),
span = document.createElement('span'),
frag = document.createDocumentFragment();
anchor.className = 'link';
span.style.height = '20px';
for (var i=0; i<something; i++) {
var wrapper = div.cloneNode(false),
link = anchor.cloneNode(true),
child = span.cloneNode(true);
wrapper.id = 'myWrapper-'+i;
wrapper.setAttribute('data-somevalue', 'myValue'+i);
child.appendChild(link);
wrapper.appendChild(child);
frag.appendChild(wrapper);
}
document.body.appendChild(frag);
以我的经验,这是尽可能快的,任何模板库在检查这个和那个等时都会增加很多开销和效率低下。
我的解决方案有点像adeno,但更通用一点。我在我的项目中使用它,它只使用原生 DOM API,保持 js 和 html 完全分离。
<ul class="list">
<li class="item">
<label><span class="name">Field:</span><input name="" type="" value="" /></label>
</li>
</ul>
请注意,发送给客户端时应删除空格。
首先根据交付的 HTML 生成一个模板,它需要一个根元素和一些绑定点作为参数。
var ul = document.querySelector('.list');
var tpl = new Tmpl(ul.querySelector('li'), [['.name', 'input@name'], 'input@type', 'input@value']);
然后使用数据生成<li>
s。
var data = [['test1', 'text', 'test value'], ['test2', 'checkbox', 'true']]
for (var i = 0; i < data.length; i++)
ul.appendChild(tpl.generate(data[i]));
当需要更新一个实例时,您可以这样做:
tpl.apply(ul.querySelector('li'), ['test3', 'button', 'it\'s a button now']);
现在列表已生成。
Tmpl 类(最小化,删除了其他功能,并且没有任何依赖关系)粘贴在下面:
function Tmpl(node, targets, singleton) {
this.elem = node;
this.begins = [];
this.targets = [];
this.fields = [];
this.mapping = [];
for (var i = 0; i < targets.length; i++) {
var tmp = targets[i] instanceof Array ? targets[i] : [targets[i]];
this.begins.push(this.targets.length);
for (var j = 0; j < tmp.length; j++) {
var field = this.parse(node, tmp[j]);
if (field) {
this.targets.push(tmp[j]);
this.fields.push(field);
this.mapping.push(i);
}
}
}
this.begins.push(this.targets.length);
node.parentNode.removeChild(node);
return this;
}
Tmpl.prototype = {
generate: function(data) {
for (var i = 0; i < this.fields.length; i++)
this.fields[i].nodeValue = data[this.mapping[i]];
return this.elem.cloneNode(true);
},
apply: function(node, data) {
for (var i = 0; i < this.fields.length; i++)
this.parse(node, this.targets[i]).nodeValue = data[this.mapping[i]];
return node;
},
applySingle: function(node, index, datum) {
for (var i = this.begins[index]; i < this.begins[index+1]; i++)
this.parse(node, this.targets[i]).nodeValue = datum;
return node;
},
parse: function(that, selector) {
selector = selector.split('@');
var node = selector[0] == '.' ? that : that.querySelector(selector[0]);
if (selector[1]) {
var attr = node.getAttributeNode(selector[1]);
if (!attr) {
attr = document.createAttribute(selector[1]);
node.setAttributeNode(attr);
}
node = attr;
}
if (node instanceof HTMLElement && node.nodeType != 2 && node.nodeType != 3)
node = node.firstChild && node.firstChild.nodeType == 3 ?
node.firstChild : node.appendChild(document.createTextNode(''));
return node;
}
};