2013-02-11 72 views
0

考虑一个显示用户冰箱内容的Web应用程序。除此之外,需要显示当前在冰箱中的水果列表。每种水果需要一个非常不同的显示。最重要的是,会有大量不同的水果类型。胡须中的复杂模板组成

我想用Mustache模板库实现这个,但我不太确定最好的方法是什么。

对于初学者来说,这里是每个水果的模板:

{{! apple.mustache }} 
A {{appleType}} apple from {{groceryStore}} 

{{! orange.mustache }} 
An orange from {{countryOfOrigin}} 

{{! banana.mustache }} 
A {{ripeness}} banana 

...many more templates here... 

方法1

有一个“视图模型”或“查看帮助”对象通过创建准备模板数据“ isBanana “/” isOrange“/等。键将传递给模板。在这种情况下,冰箱模板看起来像这样:

You have the following food in your fridge: 

{{#fruits}} 
     {{#isApple}} 
       {{> apple}} 
     {{/isApple}} 
     {{#isOrange}} 
       {{> orange}} 
     {{/isOrange}} 
     {{#isBanana}} 
       {{> banana}} 
     {{/isBanana}} 
     ...more conditionals.... 
{{/fruits}} 

我见过这种方法推荐了几个地方在互联网上。但是,我看不到它会如何缩放:每次添加新的水果类型时,必须修改冰箱模板。它似乎也在反对胡斯塔的“无逻辑”哲学。

方法2

使视图模型负责确定正确的模板为每果型,它的渲染,并返回HTML作为模板数据。冰箱模板现在看起来是这样的:

You have the following food in your fridge: 

{{{fruits}}} 

和视图模型:

class InventoryViewModel 
{ 
    // ... 

    function getFruits() 
    { 
     foreach ($this->fridge->getFruits() as $fruit) { 
      if ($fruit instanceof Banana) { 
       $html .= $this->mustache->render(...); 
      } elseif ($fruit instanceof Apple) { 
       $html .= $this->mustache->render(...); 
      } else { 
       // ... 
      } 
     } 

     return $html; 
    } 
} 

的似乎比第一种办法比较好,但它需要注入胡子模板渲染对象到每个视图模型。如果可能,我想避免这种耦合。

方法3

使用某种模板组成特征,这不是官方的胡子规范的一部分。 (https://github.com/janl/mustache.js/pull/242https://github.com/mustache/spec/issues/38等)。

以下哪个选项最好?为什么?我能看到更好的东西吗?

回答

3

也许最简单的是在您的ViewModel中使用高阶部分(lambda部分)来为您选择部分。

你的基本模板将是这个样子:

{{# items }} 
    {{# getPartial }}{{ type }}{{/ getPartial }} 
{{/ items }} 

假设你的水果有一门课程的“类型”。然后你会添加一个高阶节getPartial

<?php 

class InventoryViewModel 
{ 
    // ... 

    function getPartial() 
    { 
     // you could do string manipulation here, 
     // but I prefer the explicitness of a `case` 

     return function($tpl, $mustache) { 
      switch ($mustache->render($tpl)) { 
       case 'Banana': 
        return '{{> banana }}'; 
       case 'Apple': 
        return '{{> apple }}'; 
       case 'Orange': 
        return '{{> orange }}'; 
      } 
     }; 
    } 
} 

在这种情况下,您的模板通过移动逻辑与之配套的视图模型,在那里可以进行单元测试,嘲笑仍然是“逻辑免费”,等等。