如何使用 Meteor Spacebars 模板动态呈现 HTML?

Posted

技术标签:

【中文标题】如何使用 Meteor Spacebars 模板动态呈现 HTML?【英文标题】:How can I dynamically render HTML using Meteor Spacebars templates? 【发布时间】:2014-06-18 08:57:16 【问题描述】:

假设我将<div>name</div><div>age</div> 存储在我的数据库中。 然后我想获取第一个 html 字符串并在模板中呈现它 - > template1 它只呈现带有 name 把手的第一个字符串。然后我想给那个新生成的模板/html数据,这样它就可以用数据库中的实际name填充车把,这样我们就可以得到<div>John</div>。我试过做

<template name="firstTemplate">
    #with dataGetter
        > template1
    /with
</template>

其中template1定义为

<template name="template1">
    templateInfo
</template>

templateInfo 是从数据库中返回前面提到的带有把手的 html 字符串的助手。

dataGetter 就是这样(只是一个例子,我正在使用不同命名的集合)

Template.firstTemplate.dataGetter = function() 
    return Users.findOne(_id: Session.get("userID"));

我无法填充 name。我已经尝试了几种不同的方法,但似乎 Meteor 不明白字符串中的把手需要用数据进行评估。我在 0.7.0 上,所以没有 Blaze,由于我正在使用其他软件包,我目前无法升级,它们目前还没有 0.8+ 版本支持。非常感谢任何关于如何让它发挥作用的想法。

【问题讨论】:

【参考方案1】:

如果您需要动态编译 复杂 模板,我会建议 Kelly 的回答。

否则,您有两种选择:

    创建每个模板变体,然后动态选择正确的模板:

    例如,创建您的模板

    <template name="displayName">name</template>
    <template name="displayAge">age</template>
    

    然后动态地包含它们

    > Template.dynamic template=templateName
    

    其中templateName 是返回"age""name" 的助手

    如果您的模板很简单,只需自己执行替换即可。您可以使用Spacebars.SafeString 返回 HTML。

    function simpleTemplate(template, values)
          return template.replace(/\w+/g, function(sub) 
              var p = sub.substr(2,sub.length-4);
              if(values[p] != null)  return _.escape(values[p]); 
              else  return ""; 
          )
    
    Template.template1.helpers(
      templateInfo: function()
          // In this context this/self refers to the "user" data
          var templateText = getTemplateString();
          return Spacebars.SafeString(
              simpleTemplate(templateText, this)
          );
      
    

【讨论】:

是的,我昨天选择了第二个选项,希望 Blaze 和接下来的任何内容都可以让我们选择即时将 html 编译到车把中。还是让我生气,我不得不自己重新安装车把,叹息。 JSYK eval 由模板包在内部用于创建模板。空格键编译器将解析您的字符串并正确地转义它们,就像它处理您的模板一样。 就标签而言,您可能想要解析出任何 【参考方案2】:

您实际上可以使用空格键编译器自己将字符串编译为模板。您只需使用meteor add spacebars-compiler 将其添加到您的项目中。

在使用 0.8.x 的项目中

var compiled = Spacebars.compile("<div>name</div> and <div>age</div>");
var rendered = eval(compiled);

Template["dynamicTemplate"] = UI.Component.extend(
  kind: "dynamicTemplate",
  render: rendered
);

在使用 0.9.x 的项目中

var compiled = SpacebarsCompiler.compile("<div>name</div> and <div>age</div>");
var renderer = eval(compiled);

Template["dynamicTemplate"] = Template.__create__("Template.dynamicTemplate", rendered);

【讨论】:

哈,这是一个更好的解决方案,我会研究一下。不确定我是否在 0.7.0 中提供了 UI 类。 该软件包似乎不存在-既不在流星中,也不在陨石中。我猜这是 0.7.0 后流星的东西。 因为空格键是 Meteor UI 的一部分,我认为你需要 Meteor > 0.8.0 我的错,我认为空格键只是把手的 Meteor 名称,独立于 Meteor 的版本。我猜他们只是将它们重命名为 0.8.x+。不过仍然在 0.7.0 上。【参考方案3】:

在 1.0 中,上述方法均无效。我让它与客户端代码中定义的以下函数一起工作。关键是将选项 isTemplate: true 传递给编译函数。

var compileTemplate = function(name, html_text) 
  try 
    var compiled = SpacebarsCompiler.compile(html_text,  isTemplate:true );
      var renderer = eval(compiled);
      console.log('redered:',renderer);
      //Template[name] = new Template(name,renderer);
      UI.Template.__define__(name, renderer);
   catch (err)
    console.log('Error compiling template:' + html_text);
    console.log(err.message);
  
;

你可以在客户端上这样调用:

compileTemplate('faceplate', '&lt;span&gt;Hello!!!!!!_id&lt;/span&gt;');

这将在您的 html 中使用 UI 动态呈现

&gt; Template.dynamic template='faceplate'

【讨论】:

一定要添加spacebars-compiler包(meteor add spacebars-compiler)这样你就可以使用SpacebarsCompiler 我在控制台中得到 'redered:function anonymous()' msg,但是 > UI.dynamic template='faceplate' 在我的情况下没有做任何事情。我正在使用 Meteor 1.1.0.2 如何渲染面板子模板,即通常在面板内的 > child 但不通过动态添加 > Template.dynamic template='faceplate' 进行渲染跨度> 【参考方案4】:

幸运的是,整个问题和任何其他类似问题的解决方案已以 Blaze package 的形式提供给 Meteor API,这是使反应式模板成为可能的核心 Meteor 包。如果您查看链接的文档,您会发现 Blaze 包提供了一长串函数,这些函数允许以编程方式创建、呈现和删除反应性和非反应性内容的各种解决方案。

为了解决上述问题,您需要做以下事情:

首先,预测需要为应用程序动态呈现的不同 HTML 块。在这种情况下,这些块将是 &lt;div&gt;name&lt;/div&gt;&lt;div&gt;age&lt;/div&gt;,但它们实际上可以是任何有效的 HTML(尽管它还不是公共 API 的一部分,但未来开发人员将有更多选项来定义这些内容以更动态的方式,如文档中提到的here)。您可以将它们放入小的模板定义中,如下所示:

<template name="nameDiv">
    <div>name</div>
</template>

<template name="ageDiv">
    <div>age</div>
</template>

其次,firstTemplate 模板的定义需要更改为包含可以通过编程方式引用的 HTML 节点,如下所示:

<template name="firstTemplate">
    <div></div>
</template>

然后您需要为您的 firstTemplate 模板定义逻辑,该模板利用 Blaze 包提供的一些功能,即 Blaze.With、Blaze.render 和 Blaze.remove(尽管您可以更改遵循逻辑并改用 Blaze.renderWithData 函数;这完全取决于您对如何定义逻辑的个人偏好 - 为了便于说明,我在下面仅提供一种可能的解决方案。

Template.firstTemplate.onRendered(function() 
    var dataContext = Template.currentData();
    var unrenderedView = Blaze.With(dataContext, function() 
        // Define some logic to determine if name/age template should be rendered
        // Return either Template.nameDiv or Template.ageDiv
    );
    var currentTemplate = Template.instance();
    var renderedView = Blaze.render(unrenderedView, currentTemplate.firstNode);

    currentTemplate.renderedView = renderedView;
);

Template.firstTemplate.onDestroyed(function() 
    var renderedView = Template.instance().renderedView;
    Blaze.remove(renderedView);
);

因此,我们在 onRendered 函数中为您的 firstTemplate 模板所做的是动态确定我们想要呈现到页面上的哪些数据(在您的情况下是姓名或年龄)并使用Blaze.With() 函数使用firstTemplate 模板的数据上下文创建该模板的未渲染视图。然后,我们选择我们希望动态生成的内容包含在其中的firstTemplate模板元素节点,并将这两个对象传递给Meteor.render()函数,该函数将未渲染的视图渲染到以指定元素节点为父节点的页面上呈现的内容。

如果您阅读了Blaze.render() 函数的详细信息,您将看到此渲染的内容将保持反应状态,直到使用Blaze.remove() 函数移除渲染的视图,或从DOM 中移除指定的父节点。在上面的示例中,我将引用从调用Blaze.render() 收到的渲染视图,并将其直接保存在模板对象上。我这样做是为了当模板本身被销毁时,我可以在onDestroyed() 回调函数中手动删除渲染的视图,并确保它确实被销毁了。

【讨论】:

【参考方案5】:

一种非常简单的方法是在 onRendered 事件中包含对全局 Blaze 对象的调用。

Blaze.renderWithData(Template[template_name], data ,document.getElementById(template_id))

【讨论】:

【参考方案6】:

按照@user3354036 的回答:

var compileTemplate = function(name, html_text) 
  try 
    var compiled = SpacebarsCompiler.compile(html_text,  isTemplate:true ),
        renderer = eval(compiled);

    console.log('redered:',renderer);
    //Template[name] = new Template(name,renderer);
    UI.Template.__define__(name, renderer);
   catch (err) 
    console.log('Error compiling template:' + html_text);
    console.log(err.message);
  
;

1) 在你的 HTML 中添加这个

 > Template.dynamic template=template

2) 调用compileTemplate方法。

compileTemplate('faceplate', '<span>Hello!!!!!!_id</span>');
Session.set('templateName','faceplate');

将模板名称保存在 Session 变量中。下一点解释了这一点的重要性。

3) 编写一个帮助函数来返回模板名称。我已经使用 Session 变量来做到这一点。如果您在单击事件上添加动态内容或者父模板已经呈现,这很重要。否则你永远不会看到动态模板被渲染。

'template' : function() 
  return Session.get('templateName');

4) 写这个是父模板的渲染方法。这是为了重置 Session 变量。

Session.set('templateName','');

这对我有用。希望它可以帮助某人。

【讨论】:

太棒了!非常感谢挽救了我的一天:) 在渲染我以前的辅助函数停止工作后,你遇到过这个 别忘了运行meteor add spacebars-compiler 才能使用SpacebarsCompiler

以上是关于如何使用 Meteor Spacebars 模板动态呈现 HTML?的主要内容,如果未能解决你的问题,请参考以下文章

Meteor - 啥是 Spacebars.kw hash: Object

如何将带有参数的 Meteor Spacebars 助手传递给另一个助手属性?

meteor.js 和空格键 - 在嵌套循环中传递变量

如何在模板助手中使用 Meteor 方法

如何在不使用帮助器的情况下访问 Meteor 模板中的全局变量?

如何在 Meteor 模板文件中添加图像?