0

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

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

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

4

2 回答 2

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);

以我的经验,这是尽可能快的,任何模板库在检查这个和那个等时都会增加很多开销和效率低下。

于 2012-12-07T11:41:52.783 回答
0

我的解决方案有点像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;
  }
};
于 2012-12-07T12:05:50.980 回答