【Meteor】Nodejs isolate 和 constant
【Meteor】Nodejs isolate 和 constant
isolate 和 constant
Metoer
除了Handlebars
已经提供的width
、each
、if
、unless
,另外还提供了2个隐藏的全局helper
——isolate
和constant
。经过查询,这些都在Meteor
官方包templating
的deftemplate.js
文件中,仔细看看还会发现他修改了原版Handlebars
的each
函数。
讲解准备
构建一个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>
{{#constant}}<br/>{{#constant}}<input/>{{/constant}}Session.get(‘B_a’) = {{data}}<br/>{{/constant}}
{{> 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’) = {{#isolate}}{{#isolate}}{{data}}{{/isolate}}{{/isolate}}
{{> 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.数据更新为与之前一致是不会刷新模板的
测试五
动作:
- 填补所有空白 --> Session.set(‘list’,[‘A’,‘B’,‘C’,‘D’,‘E’]);
- 填补所有空白 --> Session.set(‘list’,[‘A’,‘B’,‘C’,‘D’,‘E’,‘F’]);
- 填补所有空白 --> 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
包。
动作:
- 填补所有空白 --> Session.set(‘list’,[‘A’,‘B’,‘C’,‘D’,‘E’,‘F’]);
- 填补所有空白 --> Session.set(‘list’,[‘A’,‘B’,‘C’,‘D’,‘E’,‘F’,‘G’]);
- 填补所有空白 --> 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
的不足,使得他能比较对象类型。
【Meteor】Nodejs isolate 和 constant
isolate 和 constant
Meteor
提供了一些额外的全局辅助函数,其中两个是 isolate
和 constant
。这两个函数主要用于控制模板的重绘行为。
- 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('填补空白');
}
});
}
测试一
动作:
- 点击按钮 -->
Session.set('A', '任意值')
- 点击按钮 -->
Session.set('A_a', '任意值')
- 修改其他以
A
开头的Session
值
结果:
- 只有模板
A
发生重绘,其子模板也发生重绘。 - 只有模板
A_a
发生重绘,其子模板也发生重绘,但其父模板A
不发生重绘。 - 结果同 2。
结论:
- 当
Session
值变化时,当前模板及其子模板会重绘。 - 重绘只发生在当前模板及其子模板,不会向上传播。
测试二
动作:
- 点击按钮 -->
Session.set('B', '任意值')
- 点击按钮 -->
Session.set('B_a', '任意值')
- 修改其他以
B
开头的Session
值
结果:
- 只有模板
B
发生重绘,但{{#constant}}
包裹的输入标签没有变化。 - 模板
B_a
因为{{#constant}}
包裹而不发生重绘,但其子模板重绘。 - 结果同测试一。
结论:
constant
包裹的内容不会因数据变化而重绘。constant
不影响重绘的向下传递。
测试三
动作:
- 点击按钮 -->
Session.set('C', '任意值')
- 点击按钮 -->
Session.set('C', '任意值')
- 修改其他以
C
开头的Session
值
结果:
- 模板
C
发生重绘,其子模板也发生重绘。 - 模板
C_a
被{{#isolate}}
包裹的数据发生变化,但模板及其子模板不发生重绘。 - 结果同测试一。
结论:
isolate
包裹的数据发生变化,但模板不重绘。isolate
不会影响外部模板的重绘。
测试四
动作:
- 点击按钮 -->
Session.set('D', '任意值')
- 点击按钮 -->
Session.set('C', 'C')
(始终设置为原始值)
结果:
- 模板
D
没有重绘。 - 模板
C
没有重绘。
结论:
- 动态函数返回的
helper
会保持动态句柄,否则是死数据。 - 数据更新为与之前一致时不会刷新模板。
测试五
动作:
- 点击按钮 -->
Session.set('list', ['A', 'B', 'C', 'D', 'E']);
- 点击按钮 -->
Session.set('list', ['A', 'B', 'C', 'D', 'E', 'F']);
- 点击按钮 -->
Session.set('list', ['A', 'B', 'C', 'D', 'F']);
结果:
list
中包含E
,数据变为true
,模板重绘。list
中仍然包含E
,数据保持true
,但模板仍重绘。list
中不包含E
,数据变为false
,模板重绘。
结论:
- 无论
Session
如何变化,都会重绘模板。
测试六
引入 isolate-value
包:
// 引入 isolate-value 包
meteor add isolate-value
动作:
- 点击按钮 -->
Session.set('list', ['A', 'B', 'C', 'D', 'E', 'F']);
- 点击按钮 -->
Session.set('list', ['A', 'B', 'C', 'D', 'E', 'F', 'G']);
- 点击按钮 -->
Session.set('list', ['A', 'B', 'C', 'D', 'G']);
结果:
Session
变化,但_.contains(Session.get('list'), 'F')
返回结果不变时,模板不重绘。
结论:
isolateValue
函数包裹能将Session
的变化延迟到返回结果中。
通过以上测试,我们可以更好地理解 isolate
和 constant
在 Meteor 中的作用,以及它们如何帮助我们更灵活地控制模板的重绘行为。
谢谢分享
在Meteor框架中,isolate
和 constant
是两个非常有用的辅助函数,用于控制模板中的数据渲染行为。
常量 (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
: 包裹的数据会独立于外部数据的变化,但是包裹的模板本身仍然可以响应外部数据的变化。
通过使用这些辅助函数,你可以更精确地控制模板的渲染逻辑,从而提高应用的性能。