在Meteor中动态显示模板,无需重新渲染/重新创建模板

时间:2014-03-23 12:24:43

标签: javascript meteor handlebars.js

SO的长期用户,但是第一次发布海报。

我有一个Meteor Web应用程序,其中向用户呈现具有单个输入的页面。一旦他们采取行动,下面的部分将显示如下。这个过程重复进行。

Journey.html

<head>
  <title>Page Journey</title>    

  <script type="text/javascript">
    function showValue(newValue)
    {
        document.getElementById("range").innerHTML=newValue;
    }
    </script>
</head>

<body>
  {{> Page0}}

  {{> Page1}}

  {{> Page2}}

  {{> Page3}}
</body>

<template name="Page0">
  <h1>This is Page 0!</h1>  
  <p>Welcome to Journey App.</p>
  <input type="range" min="1" max="10" value="1" step="1" onchange="showValue(this.value)" />
    <span id="range">1</span>
</template>

<template name="Page1">
    {{#if showpage1}}
  <h1>This is Page 1!</h1>  
  <p>{{page1copy}}</p>
  <input type="button" value="Show Page 2" />
  {{/if}}
</template>

<template name="Page2">
    {{#if showpage2}}
  <h1>This is Page 2!</h1>
  <p>{{page2copy}}</p>
  <input type="button" value="Show Page 3" />
  {{/if}}
</template>

<template name="Page3">
    {{#if showpage3}}
  <h1>This is Page 3!</h1>
  <p>{{page3copy}}</p>
  {{/if}}
</template>

Journey.js

//On initialization, set position to 0.
if (Meteor.isClient) {
  Meteor.startup(function () {
    Session.set("position",0);
  });
}

if (Meteor.isClient) {

  Template.Page0.events({
    'click input': function () {
      var value = getValue();
      if (value>5)         {        Session.set("position",1);        }
      else                 {        Session.set("position",0);        }
    }
  });

    Template.Page1.events({
    'click input': function () {      
      //Increment position
      Session.set("position",2);
    }
  });

    Template.Page2.events({
    'click input': function () {      
      //Increment position
      Session.set("position",3);
    }
  });
}

if (Meteor.isClient) {
  Template.Page1.showpage1 = function () {
    return Session.get("position") > 0;
  }

  Template.Page2.showpage2 = function () {
    return Session.get("position") > 1;
  }

  Template.Page3.showpage3 = function () {
    return Session.get("position") > 2;
  }
}

if (Meteor.isClient) {
  Template.Page1.rendered = function(){
    console.log ('Page 1 rendered');
  };

  Template.Page2.rendered = function(){
    console.log ('Page 2 rendered');
  };

  Template.Page3.rendered = function(){
    console.log ('Page 3 rendered');
  };
}

function getValue()
{
  var value = parseInt(document.getElementById("range").innerHTML);
  return value;
}

我是不是错了?

我希望每次加载新页面时都会启动一项功能(例如,谷歌分析跟踪代码)。当页面第一次加载时,.rendered()函数会被触发,所以这不是理想的。

1 个答案:

答案 0 :(得分:2)

一种方法是听取会话变量的更改,如下所示:

if (Meteor.isClient) {
  Deps.autorun(function(){
    var position=Session.get("position");
    console.log("POSITION HAS CHANGED TO "+position);
  });
}

在另一个层面上,我认为通过在同一模板中移动条件并使用帮助程序,您可以让您的生活更轻松。像这样:

<body>
  {{>pages}}
</body>

<template name="pages">
  {{> Page0}}
  {{#if showpage 1}}
    {{> Page1}}
  {{/if}}
  {{#if showpage 2}}
    {{> Page2}}
  {{/if}}
  {{#if showpage 3}}
    {{> Page3}}
  {{/if}}
</template>

在.js文件中:

if (Meteor.isClient) {
  Template.pages.showpage = function (p) {
    return (Session.get("position")>=p);
  };
}

它具有你的&#34;呈现的附加效果&#34;只有在模板实际在屏幕上时才会调用回调。 但是,当渲染3时,还会调用1和2,因为会话变量(position)将触发整个pages模板刷新。

因此日志输出将如下所示

POSITION HAS CHANGED TO 0
POSITION HAS CHANGED TO 1
Page 1 rendered
POSITION HAS CHANGED TO 2
Page 1 rendered
Page 2 rendered
POSITION HAS CHANGED TO 3
Page 1 rendered
Page 2 rendered
Page 3 rendered 

如果您希望在模板显示在页面上时触发一次回调,而不是在刷新时触发,则可以使用Template.pageX.created代替Template.pageX.rendered

POSITION HAS CHANGED TO 0 
POSITION HAS CHANGED TO 1 
Page 1 created 
Page 1 rendered 
POSITION HAS CHANGED TO 2 
Page 2 created 
Page 1 rendered 
Page 2 rendered 
POSITION HAS CHANGED TO 3 
Page 3 created 
Page 1 rendered 
Page 2 rendered 
Page 3 rendered 

因为所有模板都依赖于相同的会话变量,所以每次更改时,都会重新呈现所有模板。

如果你想避免这种情况,我想到的唯一解决方案是为每个子页面使用不同的会话变量。做好准备,它会变得有点丑陋,但我真的不知道其他方法:)

if (Meteor.isClient) {
  function setPosition(a){
    // only touch the following pages
    for(var i=3; i>a; --i)
      Session.set("position-"+i,false);  
    Session.set("position-"+a,true);
  }

  Meteor.startup(function () {
    setPosition(0);
  });

  Template.Page0.events({
    'click input': function () {
      var value = getValue();
      if (value>5)         {        setPosition(1);        }
      else                 {        setPosition(0);        }
    }
  });

    Template.Page1.events({
    'click input': function () {      
      //Increment position
      setPosition(2);
    }
  });

    Template.Page2.events({
    'click input': function () {      
      //Increment position
      setPosition(3);
    }
  });

  Template.pages.showpage = function (p) {
    return (Session.get("position-"+p));
  };
}

如果你这样做,它将无法正常工作,因为pages模板现在将取决于三个会话变量,因此在修改任何这些变量时它将完全重新呈现。

您需要拆分模板,使其仅依赖于一个会话变量。但我们希望能够保留我们之前制作的帮手,对吗?

因此,我们可以使用{{#isolate}}帮助器来虚拟地分离模板的某些部分。

  {{#isolate}}
    {{> Page0}}
  {{/isolate}}

  {{#isolate}}
    {{#if showpage 1}}
      {{> Page1}}
    {{/if}}
  {{/isolate}}

  {{#isolate}}
    {{#if showpage 2}}
      {{> Page2}}
    {{/if}}
  {{/isolate}}

  {{#isolate}}
    {{#if showpage 3}}
      {{> Page3}}
    {{/if}}
  {{/isolate}}

现在日志是这样的:

Page 1 created 
Page 1 rendered 
Page 2 created 
Page 2 rendered 
Page 3 created 
Page 3 rendered