JavaScript模板和DOM节点的重用

时间:2012-12-07 11:22:03

标签: javascript templates

JavaScript模板有几个库(Mustache,下划线模板)。他们所做的是创建新的DOM节点。

在我的应用程序中,我尝试重用DOM节点以减少内存消耗。一个例子是带有分页的缩略图库。当我加载50个下一个缩略图时,我重复使用相同的50个节点。

我可以轻松地使用模板库渲染新节点,但是有一些模板库而不是创建新节点,可以重用或更新现有节点吗?

2 个答案:

答案 0 :(得分:1)

根据我的经验,创建元素和使用它们的最快方法是尽可能少地创建,在必要时克隆它们,因为它更快,并使用片段来保存它们并尽可能少地对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);

根据我的经验,这是最快的,任何模板库只会增加很多开销和低效率,因为它会检查这个等等。

答案 1 :(得分:0)

我的解决方案有点像adeneo,但更通用一点。我在我的项目中使用它,它只使用原生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;
  }
};