【问题标题】:Dynamically showing templates in Meteor without re-rendering/re-creating template在 Meteor 中动态显示模板,无需重新渲染/重新创建模板
【发布时间】:2014-03-24 01:25:15
【问题描述】:

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() 函数在页面第一次加载时被触发,所以这并不理想。

【问题讨论】:

    标签: javascript meteor handlebars.js


    【解决方案1】:

    一种方法是像这样监听会话变量的变化:

    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);
      };
    }
    

    它的附加效果是,只有当模板实际在屏幕上时,才会调用“渲染”回调。 不过,在渲染 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 
    

    【讨论】:

    • 这真的很有帮助,谢谢!如果我用 Template.created() 替换了 Template.rendered() 那么每个模板只会触发一次?
    • 是的,每次将模板添加到页面时。这意味着如果position 由于某种原因回到零,然后再次增加,回调将被触发,因为模板已被删除并再次添加。但是,如果您的某个子页面内部发生变化,您将不会收到通知
    • 好的。现在这是一个单独的问题,但是当位置增加到 3 时,如何让第 1 页和第 2 页不重新渲染?我在每个页面中都初始化了一些我不想重置的自定义插件。
    • 这是我的看法,我真的很想看到更好的解决方案
    • 有趣的是,Meteor 0.8.0 更新 (Blaze) 解决了 Template.rendered() 多次触发的问题。因此,此更新不推荐使用 #isolate 和 #constant。
    猜你喜欢
    • 2013-09-02
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-09-22
    • 2018-08-27
    • 1970-01-01
    • 1970-01-01
    • 2019-11-19
    相关资源
    最近更新 更多