Mustache.js: 访问父作用域

创建于 2014-12-11  ·  18评论  ·  资料来源: janl/mustache.js

访问父作用域

考虑:

node = {
  id: 1,
  children : [
      { id : 2 },
      { id : 3 }
  ]
}

以及以下模板:

{{ id }} {# will output node.id #}
{{#children}}
    {{children.id}}  {# will output node.children[i].id #}
    {{id}}  {# will also output node.children[i].id #}
{{/children}}

实际上,您有时必须访问父属性(例如在嵌套节点模型中)。
它可以很容易地实现,就像使用“../”来获取父作用域一样

前任 :

{{ id }} {# will output node.id #}
{{#children}}
    {{children.id}}  {# will output node.children[i].id #}
    {{id}}  {# will also output node.children[i].id #}
    {{ ../id }}  {# will output node.id #}
{{/children}}

要实现这一点:

  Context.prototype.lookup = function (name) {
    var cache = this.cache;

    var value;
    if (name in cache) {
      console.log(name + ' found');
      value = cache[name];
    } else {
      var context = this, names, index;

      while (context) {
        if (name.indexOf('.') > 0) {
          value = context.view;
          names = name.split('.');
          index = 0;

          while (value != null && index < names.length)
            value = value[names[index++]];
        } else if(name.match(/^\.\.\//)) {
          name = name.replace(/^\.\.\//, '');
        } else {
          value = context.view[name];
        }

        if (value != null)
          break;

        context = context.parent;
      }

      cache[name] = value;
    }

    if (isFunction(value))
      value = value.call(this.view);

    return value;
  };
Future Plugin

最有用的评论

对。 我完全忘记了车把。

让用户流失到车把上。
这是一个可以接受的设计决定。

所有18条评论

这不在mustache的规范中,是吗? 这个没有解决办法吗? 我很惊讶之前没有人遇到过这个限制。

我同意经常需要访问父作用域中的内容。 我务实的方法一直是避免含糊不清的属性名称。 这对我来说已经工作了很长时间,尽管它经常导致奇怪的对象。

另一方面,说到车把的经验; 拥有这种能力可能会诱使人们创建疯狂纠结的父作用域解析: {{../../../id}}{{movieId}}更难掌握。

确实,使用“../”可能会导致不可读。 但另一方面,使用caml 解析父级无法实现,因为您可以在本地范围内使用caml。 此外,我认为定义一个关键字来访问 parent 不会尊重 Mustache 哲学。

坦率地说,我想不出比使用目录表示更简单更好的主意。

是的,避免含糊不清的属性名称也会导致更具可读性/详细的模板。 但我理解为什么有些人会喜欢这个功能。

编写一个单独的包来修改mustache.js的内部工作以添加所需的功能怎么样? 有点像插件。

老实说,除非通过插件或编译指示,否则我并没有真正看到这种情况发生。 插件 API 现在似乎不是优先事项。

我一直在考虑更多关于这个......

我相信 Mustache 的理念不是将数据按原样传递给渲染器,而是预先将其“准备”到视图中。 然后,您的节点中有一个parentId属性。

阅读和维护具有更多详细变量的模板也更容易:

{{ id }}
{{#children}}
    {{children.id}}
    {{id}}
{{/children}}

之前与之后

{{ nodeId }}
{{#children}}
    {{ nodeId }}
    {{ parentId }}
{{/children}}

相关: http :

(很抱歉召唤你@bobthecow ,但我一直很欣赏你的小胡子智慧:微笑:)

你已经可以上去了,所以解决第一个模板显示的问题所需要做的就是用临时对象{node: ... }包装数据,用{{#node}}...{{/node}}包装模板,然后{{node.id}}部分可以工作。 您不需要(也不会)以这种方式改变现有数据,并且您可以在to_html()模板中添加这两个“JIT”...

感觉很像一个不完整的解决方法。 它也仅适用于简单的 2 级模型,您可以通过外层的信封包裹来求解。 但是如果模型更深呢? 那种感觉很杂耍。

通常我需要绑定一个我从较低数据层获得的模型,我的工作是呈现它 - 以我从基础结构获得的任何形式。 这里的主张是我必须递归地将模型一直深入地转换为可呈现的状态 - 这里将考虑redable property names
这不方便地符合现实......
是的,没错,它将模板与模型结合在一起。 但是你能告诉我一个没有与具体模型规则相结合的模板吗? 根据定义,所有模板都是为呈现定义的模型而制作的。
另一层将定义层向后移动一步,并需要一个转换层——这是令人讨厌的,并不总是必要的

恕我直言,我认为该工具应该将选择权留给用户,而不是强加自以为是的规则

对于读者, @rndme建议的示例:

const Mustache = require('mustache')

var view = {
  node: {
    id: 5,
    children: [ { id: 6 }, { id: 7 } ]
  }
}

const template = `
{{#node}}
  children:
  {{#children}}

    id: {{ id }}
    parentId: {{ node.id }}
  {{/children}}
{{/node}}
`

const output = Mustache.render(template, view)
console.log(output)

  children:

    id: 6
    parentId: 5

    id: 7
    parentId: 5

使用下面的模板不工作latest ,但_it应该WORK_,海事组织。

const template = `
  children:
  {{#node.children}}

    id: {{ id }}
    parentId: {{ node.id }}
  {{/node.children}}
`

是的,没错,它将模板与模型结合在一起。 但是你能告诉我一个没有与具体模型规则相结合的模板吗? 根据定义,所有模板都是为呈现定义的模型而制作的。
另一层将定义层向后移动一步,需要一个翻译层——这很乏味而且并不总是必要的

Afaik,Mustache 的哲学一直是你生成一个传递给模板的视图——你不直接传递模型。

@osher您能否向我们展示一个您无法通过上述提示/技巧轻松解决的示例?

稍后我会尝试提供片段,但基本上 - 嵌套 3 层是行不通的,因为您无法包装中间层 - 您必须将源转换为处理过的视图。
您将能够访问包装好的顶层,但您没有针对中间层的解决方案。

以一个 swagger 文档为例,在那里你有根级别、路径级别、动词级别(还有更多,但让我们停在这里)。 每个级别都可以指定一个自定义指令—— x-uses ,这是一个针对实现层的 DI 指令。

假设您想从这个 swagger 文档生成 HTML 文档。
您需要一个平面表,为每个操作处理程序(动词级别)指定它接受的 DI,以及它从哪个层继承它。
虽然所有信息都包含在 swagger 文档中 - 您现在遇到了问题。

下一个。
尝试使用 mustache 生成实现文档中描述的 API 的代码,该 API 基于操作默认响应返回模拟响应。
尝试生成 doclet,这些 doclet 描述了使用真实逻辑替换模拟响应的实现开发人员在他们的 DI 上下文中应该期望什么,并具体说明他们获得的级别。
相同的...

不是经典的 HTML 生成 - 是的。 但谁说小胡子只适用于 HTML 呢? 它是一个模板引擎,代码生成通常使用这样的模板引擎来实现;)

你不直接传递模型。

这应该是用户的选择,而不是限制/限制

我再给你举一个例子,我会尽量做到这一点,而不会背叛秘方。

假设一个树数据结构描述了策略游戏中玩家拥有的资产。
树可能有 5 个级别,例如:
Aliance -> Empire -> City -> Army -> Troops

每个级别都可以提供修正加值——例如——或攻击加值、防御加值、健康加值等。
处理相同统计数据的修饰符在所有级别都用相同的名称描述,(主要是因为它们是递归计算的)。
您需要使用模板引擎来展示战斗模拟器,通过显示军队中部队的战斗统计数据,帮助玩家选择哪支军队是给定挑战的理想军队 - 驻留在最低级别,但收集战斗树中以相同属性名称命名的修饰符。
这是_非常_简化的,但基于一个真实的故事,其他工具可以轻松解决问题,无需中间翻译层。

我会增加难度:有时军队会被分配到联盟级别的特遣队中。
Alliance -> Rally -> Troops
该工具应该足够通用(简单的递归)并且不依赖于具体的级别。

我用 mustache 称为部分的东西解决了它,只是我没有使用 mustache ......

@osher说:

这应该是用户的选择,而不是限制/限制

毫无疑问,小胡子有意见。 它的“无逻辑模板”理念对模板施加了很多限制,这一事实通常需要在将数据/模型提供给模板进行渲染之前进行准备。 如果这不能满足您的需求,那么还有可能更好的替代方案,例如把手甚至lodash.template仅举几例

对。 我完全忘记了车把。

让用户流失到车把上。
这是一个可以接受的设计决定。

我很确定@osher在说“这是一个可以接受的设计决定”时是在讽刺,但这个话题自 2016 年以来就被放弃了。这是怎么回事? 似乎在这个 JavaScript 存储库和主存储库中都避免了这个问题:
https://github.com/mustache/mustache.github.com/issues/103

我认为能够引用父作用域是无逻辑的,不应该干扰胡须的理想。

我喜欢始终能够使用符号访问根范围的想法,例如前导“../”:

Mustache.render('{{a1}}{{#a}}{{b.c}}{{../a1}}{{/a}}',{"a":{"b":{"c":"x1"}},"a1":"x2"})
"x2x1"

我希望它呈现“x2x1x2”,但它省略了最后一个,因为它不是这样工作的。
我想我会推荐使用类似 JSONPath 的东西: https ://goessner.net/articles/JsonPath/index.html#e2 但是与 XML 的 XPath 不同,它不推荐/实现父运算符,这正是我所希望的为了。

也许 Mustache 可以尝试保持与把手兼容并使用../语法作为父上下文?

AFAIK,handlebars 只是 JS,而 mustache 在许多环境中使用相同的语法,例如 PHP。 如果你想改变 mustache 语法,你需要说服所有其他非 js 实现也这样做; 一项艰巨的任务。 此外,在修改 JS 代码时,我发现上升“一级”有问题,尽管我在 fork 中添加,实现起来非常

有这方面的吗?

对于点符号是可选的情况,还需要有文档和样式建议。

view = { wrap: { txt: "test" } };
{{#wrap}}
  {{wrap.txt}} {{! Should I use this?}}
  {{txt}} {{! Or this?}}
{{/wrap}}

更多细节在这里: https :

此页面是否有帮助?
0 / 5 - 0 等级

相关问题

chlab picture chlab  ·  11评论

Immortalin picture Immortalin  ·  12评论

ForbesLindesay picture ForbesLindesay  ·  14评论

connor11528 picture connor11528  ·  3评论

funston picture funston  ·  7评论