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
的不足,使得他能比较对象类型。
谢谢分享