【Meteor】Nodejs isolate 和 constant

【Meteor】Nodejs isolate 和 constant

isolate 和 constant

Metoer除了Handlebars已经提供的widtheachifunless,另外还提供了2个隐藏的全局helper——isolateconstant。经过查询,这些都在Meteor官方包templatingdeftemplate.js文件中,仔细看看还会发现他修改了原版Handlebarseach函数。

讲解准备

构建一个Meteor项目,然后修改默认项目的html文件:

<head>
    <title>isolate和constant</title>
</head>

<body> <div> {{> main}} </div> </body>

<template name=“main”> <button onclick=“javascript:$(‘input’).val(‘填补空白’)”>填补所有空白</button> <div> {{> A}} {{> B}} {{> C}} {{> D}} {{> E}} {{> F}} </div> </template>

<template name=“A”> <div style=“background:#9cc”> <input/>Session.get(‘A’) = {{data}} {{> A_a}} {{> A_b}} </div> </template> <template name=“A_a”> <div> <input/>Session.get(‘A_a’) = {{data}} {{> A_a_1}} </div> </template> <template name=“A_b”> <div> <input/>Session.get(‘A_b’) = {{data}} {{> A_b_1}} </div> </template> <template name=“A_a_1”> <div> <input/>Session.get(‘A_a_1’) = {{data}} </div> </template> <template name=“A_b_1”> <div> <input/>Session.get(‘A_b_1’) = {{data}} </div> </template>

<template name=“B”> <div style=“background:#cc9”> <input/>Session.get(‘B’) = {{data}} {{> B_a}} {{> B_b}} </div> </template> <template name=“B_a”> <div> &#123;&#123;#constant&#125;&#125;<br/>{{#constant}}<input/>{{/constant}}Session.get(‘B_a’) = {{data}}<br/>&#123;&#123;/constant&#125;&#125; {{> B_a_1}} </div> </template> <template name=“B_b”> <div> <input/>Session.get(‘B_b’) = {{data}} {{> B_b_1}} </div> </template> <template name=“B_a_1”> <div> <input/>Session.get(‘B_a_1’) = {{data}} </div> </template> <template name=“B_b_1”> <div> <input/>Session.get(‘B_b_1’) = {{data}} </div> </template>

<template name=“C”> <div style=“background:#c9c”> <input/>Session.get(‘C’) = {{data}} {{> C_a}} {{> C_b}} </div> </template> <template name=“C_a”> <div> <input/>Session.get(‘C_a’) = &#123;&#123;#isolate&#125;&#125;{{#isolate}}{{data}}{{/isolate}}&#123;&#123;/isolate&#125;&#125; {{> C_a_1}} </div> </template> <template name=“C_b”> <div> <input/>Session.get(‘C_b’) = {{data}} {{> C_b_1}} </div> </template> <template name=“C_a_1”> <div> {{#isolate}}<input/>{{/isolate}}Session.get(‘C_a_1’) = {{data}} </div> </template> <template name=“C_b_1”> <div> <input/>Session.get(‘C_b_1’) = {{data}} </div> </template> <template name=“D”> <div> <input/>Session.get(‘D’) = {{data}} </div> </template> <template name=“E”> <div> <input/>.contains(Session.get(‘list’),‘E’) = {{hasE}} </div> </template> <template name=“F”> <div> <input/>.contains(Session.get(‘list’),‘F’) = {{hasF}} (isolateValue(fn)包裹) </div> </template>

再来修改js文件:

if (Meteor.isClient) {
    Session.set('A','A');
    Session.set('A_a','A_a');
    Session.set('A_a_1','A_a_1');
    Session.set('A_b','A_b');
    Session.set('A_b_1','A_b_1');
    Session.set('B','B');
    Session.set('B_a','B_a');
    Session.set('B_a_1','B_a_1');
    Session.set('B_b','B_b');
    Session.set('B_b_1','B_b_1');
    Session.set('C','C');
    Session.set('C_a','C_a');
    Session.set('C_a_1','C_a_1');
    Session.set('C_b','C_b');
    Session.set('C_b_1','C_b_1');
    Session.set('D','D');
    Template.A.data = function(){return Session.get('A')};
    Template.A_a.data = function(){return Session.get('A_a')};
    Template.A_a_1.data = function(){return Session.get('A_a_1')};
    Template.A_b.data = function(){return Session.get('A_b')};
    Template.A_b_1.data = function(){return Session.get('A_b_1')};
    Template.B.data = function(){return Session.get('B')};
    Template.B_a.data = function(){return Session.get('B_a')};
    Template.B_a_1.data = function(){return Session.get('B_a_1')};
    Template.B_b.data = function(){return Session.get('B_b')};
    Template.B_b_1.data = function(){return Session.get('B_b_1')};
    Template.C.data = function(){return Session.get('C')};
    Template.C_a.data = function(){return Session.get('C_a')};
    Template.C_a_1.data = function(){return Session.get('C_a_1')};
    Template.C_b.data = function(){return Session.get('C_b')};
    Template.C_b_1.data = function(){return Session.get('C_b_1')};
    Template.D.data = Session.get('D');
    Template.E.hasE = function(){
      return _.contains(Session.get('list'),'E');
    };
    Template.F.hasF = function(){
      return isolateValue(function(){
        return _.contains(Session.get('list'),'F');
      });
    }
}

如果你不介意样式,可以不放下面的。

*{
  font-size: 8px;
}
div{
  border:1px solid #999;
  border-bottom: none;
  border-right: none;
  margin:2px auto 2px 50px;
}

input{
  border:1px solid black;
  height:12px;
  line-height: 12px;
}

最后运行项目。(Session值可以通过控制台手动更改)

注意:填补所有空白就是让所有input标签都填充一个内容。

测试一

动作:

1.填补所有空白 --> Session.set(‘A’,‘任意值’) 2.填补所有空白 --> Session.set(‘A_a’,‘任意值’) 3.尝试修改所有以A开头的其他Session值

结果:

1.Session变化所在的模板A发生重绘,该模板下的所有子模板都发生重绘 2.Session变化所在的模板A_a发生重绘,该模板下的所有子模板发生重绘,但他的父模板没有发生重绘 3.尝试其他的,结果同2

结论:

1.Session发生变化的当前模板发生重绘,写入到信息都被重置 2.重绘只发生在当前和子模板,即向下传递,而不会向上传递

测试二

动作:

1.填补所有空白 --> Session.set(‘B’,‘任意值’) 2.填补所有空白 --> Session.set(‘B_a’,‘任意值’) 3.尝试修改所有以B开头的其他Session值

结果:

1.Session变化所在的模板B发生重绘,唯独被{{#constant}}{{/constant}}所包裹的输入标签没有变化。 2.Session变化所在的模板B_a因为被{{#constant}}{{/constant}}包裹,所以没变化,但其子模板重绘了。 3.结果同测试一结果

结论:

1.重绘对constant包裹的内容无效 2.constant不影响重绘的向下传递

测试三

动作:

1.填补所有空白 --> Session.set(‘C’,‘任意值’) 2.填补所有空白 --> Session.set(‘C’,‘任意值’) 3.尝试修改所有以C开头的其他Session值

结果:

1.Session变化所在的模板C发生重绘,其子模板同样发生重绘 2.Session变化所在的模板C_a,被{{#isolate}}{{/isolate}}包裹的数据发生变化,但模板及其子模板没发生重绘 3.结果同测试一结果

结论:

1.isolate包裹的数据会发生变化 2.isolate除此之外的任何模板都不会发生改变

constant

中文含义很明显,“不变”的意思,主要用在DOM元素保持其可视化不变。如果包裹了helper,数据会变化,但是显示不会变化(大家自行测试)。

isolate

中文含义是“隔离”,能将动态数据与外界隔离。表示数据的变化不会影响外围的任何模板。如果包裹了DOM,不会影响重绘的执行。

测试四

动作:

1.填补所有空白 --> Session.set(‘D’,‘任意值’) 2.填补所有空白 --> Session.set(‘C’,‘C’);(始终设置为他的原始值)

结果:

1.模板D没有重绘 2.模板C没有重绘

结论:

1.helper如果是函数返回,将能保持动态句柄,否则是死数据 2.数据更新为与之前一致是不会刷新模板的

测试五

动作:

  1. 填补所有空白 --> Session.set(‘list’,[‘A’,‘B’,‘C’,‘D’,‘E’]);
  2. 填补所有空白 --> Session.set(‘list’,[‘A’,‘B’,‘C’,‘D’,‘E’,‘F’]);
  3. 填补所有空白 --> Session.set(‘list’,[‘A’,‘B’,‘C’,‘D’,‘F’]);

结果:

1.list中包含E,数据变为true,模板重绘 2.list中仍然包含E,数据保持true,但模板依旧重绘 3.list中不包含E,数据变为false,模板重绘

结论:

1.无论Session如何改变,都会重绘他所在模板

疑问:

如果将测试二、三的结论用在本次测试中,我们可以使得模板不重绘。虽然解决了他一直重绘的情况,但某些时候,我希望在返回true的情况下重绘,这样就无法实现了。下面就要使用Meteor的扩展包isolate了。

测试六

在运行项目前,先引入isolate-value包。

动作:

  1. 填补所有空白 --> Session.set(‘list’,[‘A’,‘B’,‘C’,‘D’,‘E’,‘F’]);
  2. 填补所有空白 --> Session.set(‘list’,[‘A’,‘B’,‘C’,‘D’,‘E’,‘F’,‘G’]);
  3. 填补所有空白 --> Session.set(‘list’,[‘A’,‘B’,‘C’,‘D’,‘G’]);

结果:

1.Session变化,但_.contains(Session.get('list'),'F')返回结果不变时,模板不重绘

结论:

1.isolateValue函数包裹能将Session的变化延迟到返回结果中

isolate-value

这个包只有一个API,就是isolateValue(fn),并且它是全局的。如果是将Session本身的某个值取出来返回(Session作为返回值),他自己会判断是否与上次一致,如果与上次不一致,则重绘Session所在模板。而有时,我们需要经过Session的计算返回结果(Session作为中间值,运算结果作为返回值)。当Session变化时,即使返回值结果保持与之前一致,但仍旧重绘模板,有时这并不是我们需要的,而isolateValue能为我们解决这个问题。

isolateValue还扩展了原equals的不足,使得他能比较对象类型。


3 回复

【Meteor】Nodejs isolate 和 constant

isolate 和 constant

Meteor 提供了一些额外的全局辅助函数,其中两个是 isolateconstant。这两个函数主要用于控制模板的重绘行为。

  • isolate:用于隔离动态数据,使得数据的变化不会影响外部模板的重绘。
  • constant:用于保持 DOM 元素的可视化不变,即使数据发生变化,显示也不会改变。

讲解准备

首先,我们创建一个简单的 Meteor 项目,并修改默认的 HTML 文件:

<head>
    <title>isolate和constant</title>
</head>

<body>
<div>
    {{> main}}
</div>
</body>

<template name="main">
    <button onclick="javascript:$('input').val('填补空白')">填补所有空白</button>
    <div>
        {{> A}}
        {{> B}}
        {{> C}}
        {{> D}}
        {{> E}}
        {{> F}}
    </div>
</template>

<template name="A">
    <div style="background:#9cc">
        <input/>Session.get('A') = {{data}}
        {{> A_a}}
        {{> A_b}}
    </div>
</template>
<!-- 更多模板定义 -->

接下来,修改 JavaScript 文件:

if (Meteor.isClient) {
    // 初始化 Session 值
    Session.set('A', 'A');
    Session.set('A_a', 'A_a');
    Session.set('A_b', 'A_b');
    
    // 定义模板数据
    Template.A.data = function() { return Session.get('A'); };
    Template.A_a.data = function() { return Session.get('A_a'); };
    Template.A_b.data = function() { return Session.get('A_b'); };

    // 模板重绘事件
    Template.main.events({
        'click button': function() {
            $('input').val('填补空白');
        }
    });
}

测试一

动作:

  1. 点击按钮 --> Session.set('A', '任意值')
  2. 点击按钮 --> Session.set('A_a', '任意值')
  3. 修改其他以 A 开头的 Session

结果:

  1. 只有模板 A 发生重绘,其子模板也发生重绘。
  2. 只有模板 A_a 发生重绘,其子模板也发生重绘,但其父模板 A 不发生重绘。
  3. 结果同 2。

结论:

  1. Session 值变化时,当前模板及其子模板会重绘。
  2. 重绘只发生在当前模板及其子模板,不会向上传播。

测试二

动作:

  1. 点击按钮 --> Session.set('B', '任意值')
  2. 点击按钮 --> Session.set('B_a', '任意值')
  3. 修改其他以 B 开头的 Session

结果:

  1. 只有模板 B 发生重绘,但 {{#constant}} 包裹的输入标签没有变化。
  2. 模板 B_a 因为 {{#constant}} 包裹而不发生重绘,但其子模板重绘。
  3. 结果同测试一。

结论:

  1. constant 包裹的内容不会因数据变化而重绘。
  2. constant 不影响重绘的向下传递。

测试三

动作:

  1. 点击按钮 --> Session.set('C', '任意值')
  2. 点击按钮 --> Session.set('C', '任意值')
  3. 修改其他以 C 开头的 Session

结果:

  1. 模板 C 发生重绘,其子模板也发生重绘。
  2. 模板 C_a{{#isolate}} 包裹的数据发生变化,但模板及其子模板不发生重绘。
  3. 结果同测试一。

结论:

  1. isolate 包裹的数据发生变化,但模板不重绘。
  2. isolate 不会影响外部模板的重绘。

测试四

动作:

  1. 点击按钮 --> Session.set('D', '任意值')
  2. 点击按钮 --> Session.set('C', 'C')(始终设置为原始值)

结果:

  1. 模板 D 没有重绘。
  2. 模板 C 没有重绘。

结论:

  1. 动态函数返回的 helper 会保持动态句柄,否则是死数据。
  2. 数据更新为与之前一致时不会刷新模板。

测试五

动作:

  1. 点击按钮 --> Session.set('list', ['A', 'B', 'C', 'D', 'E']);
  2. 点击按钮 --> Session.set('list', ['A', 'B', 'C', 'D', 'E', 'F']);
  3. 点击按钮 --> Session.set('list', ['A', 'B', 'C', 'D', 'F']);

结果:

  1. list 中包含 E,数据变为 true,模板重绘。
  2. list 中仍然包含 E,数据保持 true,但模板仍重绘。
  3. list 中不包含 E,数据变为 false,模板重绘。

结论:

  1. 无论 Session 如何变化,都会重绘模板。

测试六

引入 isolate-value 包:

// 引入 isolate-value 包
meteor add isolate-value

动作:

  1. 点击按钮 --> Session.set('list', ['A', 'B', 'C', 'D', 'E', 'F']);
  2. 点击按钮 --> Session.set('list', ['A', 'B', 'C', 'D', 'E', 'F', 'G']);
  3. 点击按钮 --> Session.set('list', ['A', 'B', 'C', 'D', 'G']);

结果:

  1. Session 变化,但 _.contains(Session.get('list'), 'F') 返回结果不变时,模板不重绘。

结论:

  1. isolateValue 函数包裹能将 Session 的变化延迟到返回结果中。

通过以上测试,我们可以更好地理解 isolateconstant 在 Meteor 中的作用,以及它们如何帮助我们更灵活地控制模板的重绘行为。


谢谢分享

在Meteor框架中,isolateconstant 是两个非常有用的辅助函数,用于控制模板中的数据渲染行为。

常量 (constant)

constant 可以用来确保包裹在其内部的表达式不会因外部数据的变化而重新渲染。这对于那些不需要频繁更新的数据特别有用。

示例代码:

<template name="B_a">
    <div>
        {{#constant}}
            {{data}}
        {{/constant}}
    </div>
</template>

隔离 (isolate)

isolate 则可以将某部分数据从父模板的数据流中隔离出来,使其不受外部数据变化的影响。

示例代码:

<template name="C_a">
    <div>
        {{#isolate}}
            {{data}}
        {{/isolate}}
    </div>
</template>

这两个函数的主要区别在于:

  • constant: 包裹的数据即使外部数据发生变化也不会重新渲染。
  • isolate: 包裹的数据会独立于外部数据的变化,但是包裹的模板本身仍然可以响应外部数据的变化。

通过使用这些辅助函数,你可以更精确地控制模板的渲染逻辑,从而提高应用的性能。

回到顶部