我使用Javascript(使用Mootools)使用HTML“模板”元素动态构建大页面,多次复制相同的模板以填充页面。在每个模板中,我使用需要替换的字符串关键字来创建唯一ID。我遇到了严重的性能问题,因为执行所有这些替换需要几秒钟,尤其是在IE中。代码如下所示:
var fieldTemplate = $$('.fieldTemplate')[0];
var fieldTr = fieldTemplate.clone(true, true);
fieldTr.removeClass('fieldTemplate');
replaceIdsHelper(fieldTr, ':FIELD_NODE_ID:', fieldNodeId);
parentTable.grab(fieldTr);
replaceIdsHelper()是根据IE9的分析器的问题方法。我尝试过这种方法的两种实现方式:
// Retrieve the entire HTML body of the element, replace the string and set the HTML back.
var html = rootElem.get('html').replace(new RegExp(replaceStr, 'g'), id);
rootElem.set('html', html);
和
// Load the child elements and replace just their IDs selectively
rootElem.getElements('*').each(function(elem) {
var elemId = elem.get('id');
if (elemId != null) elemId = elemId.replace(replaceStr, id);
elem.set('id', elemId)
});
然而,考虑到调用此方法的次数(约200 ...),这两种方法都非常慢。其他一切运行正常,它只是取代了这些似乎是主要性能瓶颈的ID。有谁知道是否有办法有效地做到这一点,或者它可能运行得如此之慢?元素开始隐藏,直到它们被创建之后才被DOM抓取,所以没有重绘。
顺便说一下,我以这种方式构建页面的原因是为了保持代码干净,因为我们需要能够在加载后动态创建新元素。从服务器端执行此操作会使事情变得更加复杂。
答案 0 :(得分:2)
我不是百分百肯定,但听起来问题是问题在于对dom树的索引。
首先,您是否必须使用ID或者您可以管理课程吗?因为你说更换id是主要问题。
另外,为什么要克隆dom树的一部分而不是只插入一个新的html? 您可以使用String的替代方法(使用MooTools时),如下所示:
var template = '<div id="{ID}" class="{CLASSES}">{CONTENT}</div>';
template.substitute({ID: "id1", CLASSES: "c1 c2", CONTENT: "this is the content" });
您可以在此处阅读更多相关信息http://mootools.net/docs/core/Types/String#String:substitute
然后,只需取出该字符串并将其作为html放入容器中,让我们说:
$("container_id").set("html", template);
我认为它可以提高效率,因为它不会克隆然后再次索引,但我不能确定。试一试,看看会发生什么。
答案 1 :(得分:1)
你可以采取一些措施来优化它 - 而@nizan tomer所说的非常好,伪模板是一种很好的模式。
首先。
var fieldTemplate = $$('.fieldTemplate')[0];
var fieldTr = fieldTemplate.clone(true, true);
你应该这样做:
var templateHTML = somenode.getElement(".fieldTemplate").get("html"); // no need to clone it.
模板本身应该/可以像建议一样,例如:
<td id="{id}">{something}</td>
只读一次,不需要为每个项克隆它 - 而是使用新的Element构造函数并设置innerHTML - 注意它缺少<tr> </tr>
。
如果您有一个包含数据的对象,例如:
var rows = [{
id: "row1",
something: "hello"
}, {
id: "row2",
something: "there"
}];
Array.each(function(obj, index) {
var newel = new Element("tr", {
html: templateHTML.substitute(obj)
});
// defer the inject so it's non-blocking of the UI thread:
newel.inject.delay(10, newel, parentTable);
// if you need to know when done, use a counter + index
// in a function and fire a ready.
});
或者,使用文档片段:
Element.implement({
docFragment: function(){
return document.createDocumentFragment();
}
});
(function() {
var fragment = Element.docFragment();
Array.each(function(obj) {
fragment.appendChild(new Element("tr", {
html: templateHTML.substitute(obj)
}));
});
// inject all in one go, single dom access
parentTable.appendChild(fragment);
})();
我对这两种方法都进行了jsperf测试: http://jsperf.com/inject-vs-fragment-in-mootools
与Firefox和ie9相比,Chrome以惊人的优势获胜。同样令人惊讶的是,在Firefox中,单个注入比片段更快。也许瓶颈在于它是桌子上的TR,这一直是狡猾的。
对于模板:您还可以使用诸如mustache或underscore.js模板之类的东西。