访问父作用域
考虑:
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;
};
这不在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 可以尝试保持与把手兼容并使用../
语法作为父上下文?
有这方面的吗?
对于点符号是可选的情况,还需要有文档和样式建议。
view = { wrap: { txt: "test" } };
{{#wrap}}
{{wrap.txt}} {{! Should I use this?}}
{{txt}} {{! Or this?}}
{{/wrap}}
更多细节在这里: https :
最有用的评论
对。 我完全忘记了车把。
让用户流失到车把上。
这是一个可以接受的设计决定。