Ractivejs 中的递归部分超出调用堆栈

Recursive partial in Ractivejs exceeding call stack

自从发现 Ractivejs 以来,我正在慢慢地将我的应用程序转移到它上面。

之前,我使用 vanilla JavaScript 构建了一个 html 树结构来创建元素,然后在完成后将其附加到页面。我最近将它移到了 Ractivejs 上,它在小树结构上工作得很好,但如果它涉及到一个深度嵌套的对象,它会超出调用堆栈。

有没有一种方法可以将我在 JavaScript 中构建的元素附加到 Ractivejs 模板并在其上保留 Ractivejs 事件,或者有没有一种方法可以递归地遍历大对象不超过调用堆栈?

例子

树是如何在 JavaScript

中构建的

var tree = {
  'childPages' : [{    
    'name': 'first child',
    'childPages': []
  }, {
    'name': 'second child',
    'childPages': [{
       'name': 'second first sub child',
       'childPages': []
     }]
  }, {
    'name': 'third child',
    'childPages': [{
        'name': 'third first sub child',
        'childPages': [{
            'name': 'sub sub child',
            'childPages': []
         }]
     }]
  }]
};


function buildTree (tree) {
  var ul = document.createElement('ul');;
  for(var i =0; i < tree.childPages.length; i++){
    var li = document.createElement('li');
    li.innerText = tree.childPages[i].name;
    ul.appendChild(li);
    if (tree.childPages[i].childPages.length) {
       li.appendChild (buildTree(tree.childPages[i]));
    }
  }
  return ul;
}

document.body.appendChild(buildTree(tree));

如何在 Ractivejs 模板中构建树

var ractive = new Ractive({
  el : 'body',
  template: '#treeNode',
  data: {
'childPages' : [{    
  'name': 'first child',
  'childPages': []
}, {
  'name': 'second child',
  'childPages': [{
    'name': 'second first sub child',
    'childPages': []
  }, {
    'name': 'second second sub child',
    'childPages': []
  }]
}, {
  'name': 'third child',
  'childPages': [{
    'name': 'third first sub child',
    'childPages': [{
      'name': 'sub sub child',
      'childPages': []
    }]
  }]
}]
  }
});
<script src="http://cdn.ractivejs.org/latest/ractive.js"></script>
<script id="treeNode" type="text/ractive">
  <ul>
    {{#each childPages}}
      <li>
         {{name}}
          {{#if childPages}}
           {{> treeNode}}
          {{/if}}
      </li>
     {{/each}}
  </ul>
</script>

通常当您超出调用堆栈时,这是因为 Ractive 处理缺失数据属性的方式 - 如果您有 {{with foo}}{{bar}}{{/with}}foo.bar 不存在,则 {{bar}} 引用是未解决,所以它 'goes up the context stack',然后寻找 bar

大多数时候这真的很方便,但在这种情况下可能会有问题,因为如果树中的项目没有 childPages 属性,Ractive 会去向上堆栈到父级 - 这将我们送入无限递归兔子洞。

有两种解决方法:

  • 确保树中的每个节点都有一个 childPages 属性,即使它是一个空数组,或者...
  • 使用受限引用。如果你使用 this.childPages 而不是 childPages (或 ./childPages - 它是等价的,你可能对其中一个有审美偏好)那么 Ractive 将不会在当前上下文之外寻找一条数据。这是一个例子,删除了所有空的 childPages 数组 - 没有 this.,我们立即超出了调用堆栈,但因为它在那里我们是完全安全的。

var ractive = new Ractive({
  el : 'body',
  template: '#treeNode',
  data: {
'childPages' : [{    
  'name': 'first child'
}, {
  'name': 'second child',
  'childPages': [{
    'name': 'second first sub child'
  }, {
    'name': 'second second sub child'
  }]
}, {
  'name': 'third child',
  'childPages': [{
    'name': 'third first sub child',
    'childPages': [{
      'name': 'sub sub child'
    }]
  }]
}]
  }
});
<script src="http://cdn.ractivejs.org/latest/ractive.js"></script>
<script id="treeNode" type="text/ractive">
  <ul>
    {{#each this.childPages}}
      <li>
         {{name}}
          {{#if this.childPages}}
           {{> treeNode}}
          {{/if}}
      </li>
     {{/each}}
  </ul>
</script>