首页 > 代码库 > 【仿doT前端模板】二、if else
【仿doT前端模板】二、if else
效果预览
首先,按照惯例,我们先看doT 实现的效果:
模板:
{{? it.name }} <div>嗨, {{=it.name}}!</div> {{?? it.age === 0}} <div>我猜应该还没人给你起名字吧?</div> {{??}} 你已经 {{=it.age}} 岁了但是你还没有名字? {{?}}
数据 | 结果 |
---|---|
{name:‘十一川‘} |
<div>嗨, 十一川! </div> |
{age:0} |
<div>我猜应该还没人给你起名字吧?</div> |
{age:11} |
<div>你已经 11 岁了但是你还没有名字?</div> |
实现思路
我们此次要做的事情,与上次一样,无非是一个 查找标记 => 替换成对应代码 的过程 而区别在于,我们此次要替换的标记不再是一个,而是4个:
标记 | 结果 | |
---|---|---|
{{? it.name }} | => | if( it.name ){ |
{{?? it.age === 0}} | => | } else if( it.age === 0 ) { |
{{??}} | => | } else{ |
{{?}} | => | } |
实现过程
写出正则表达式
var IF = /\{\{\?([^\?]{1}.*?)\}\}/g; var ELSE_IF = /\{\{\?\?(.+?)\}\}/g; var ELSE = /\{\{\?\?\}\}/g; var END_IF = /\{\{\?\}\}/g;
这里需要特别注意的是,匹配if
与其他标记的包含关系,也就是说,如果我们匹配的是:
那么,else
标记的{{??}}
中的第二个?
会被当成条件,也就是说:
甚至于,我们作为结尾的{{?}}
也会被当成没有条件的if语句:
这很明显不是我们想要达到的效果啊!
要解决这个问题,首先能想到的简单粗暴的办法就是。。。我们可以先把{{??}}
跟{{?}}
标记替换掉嘛,这样不就等到替换{{? 条件}}
的时候,我们就能保证全部都是条件语句了。
唔。。。这固然是个“暂时能用的办法”,但是万一哪天,我们心血来潮地把赋值{{= 值}}
改成了这样:{{??? 值}}
,那我们还得去代码里看看值的替换是否在if替换之前?
有!我们不难推导出,这里的“条件”要先符合两个条件:
- 第一个字符不能是
?
这个字符本身 - 不能为空
这样的话,不管我们替换的顺序如何,都能保证不会影响到其他的标记,那么,这两个限定又如何通过正则表达式表达出来呢?
我们可以通过^
符号来表示“不能是某个字符”,而我们要表示“不能是?的一个字符”的话自然就是[^\?]
;而{1}
来表示“有且只有一个字符”。因此([^\?]{1}.*?)
表示的就是“最起码一个字符,而且第一个字符不能是?
的任意长度字符串” ,自然就是我们一开始提到的if的正则表达式。
顺带一提,为什么只限制了“第一个字符不能是?
这个字符”,而不是“所有字符”呢?这是因为三元操作符?:
能够产生一个合法的bool值,比如:a?2:3
,如果我们只是粗暴地规定“所有的条件中都不能包含?
”那么可能会导致原本合法的表达式没有被当成条件。而这个表达式的?前面最起码要有一个变量名,变量名最短也是一个非?的字符,因此在这个层面,我们仅仅限定住“第一个字符”,是有着必要性和充分性的。
而类似的,为了防止 else 的标记被当成“没有条件的 else if 标记” 我们同样要对这里的条件作出“起码有一个字符的限制” ,也就是(.+?)
引入out
现在,我们还有一个问题是,因为引入了判断机制,我们编译之后的代码不能再像之前那样像一条串似的直接拼接起来。我们在第一篇中编译后的代码大概类似于这样:return ‘H1!‘+it.name;
可是,我们只进行了判断,没有进行字符串拼接的话,代码大概是这样:
return if(it.name){ ‘Hi!‘+it.name; }
连语法都不正确了啊喂!不要慌,总之先冷静下来找时光机。。。啊不对,是先回想正常情况下我们是如何完成类似的拼接的:
var out=""; if(it.name){ out += ‘Hi!‘+it.name; } return out;
因此类似的,我们要引入一个变量out
,这样我们就能在判断体内把结果拼接起来了。于是,我们要替换的目标变成了这样:
标记 | 结果 | |
---|---|---|
{{? it.name }} | => | ‘; if( it.name ){ out += ‘ |
{{?? it.age === 0}} | => | ‘; } else if( it.age === 0 ) { out += ‘ |
{{??}} | => | ‘; } else{ out += ‘ |
{{?}} | => | ‘; } out += ‘ |
我们能这么做的前提,是我们假设,在进行判断语句之前,这个字符串还没有结束。 于是,我们加上单引号使其提前结束(我们使用单引号来标记字符串,还记得吗?)在执行完判断之后,我们又通过out+=‘
来继续拼接字符串。也就是说,在执行判断之前,我们的字符串是未结束的状态,在执行完判断之后,我们的字符串依然是未结束的状态
实现过程
好了,剩下的就只有将刚刚的思考转化为实际代码的过程了,我建议你自己手动完成这部分,如果你实在不知如何下手的话,这里有一份代码供你参考:
点击这里直接运行试试
HTML:
<div id="target"></div> <script type="text/x-dot-template" class="js-template"> {{? it.name }} <div>嗨, {{= it.name}}!</div> {{?? it.age === 0}} <div>我猜应该还没人给你起名字吧?</div> {{??}} <div>你已经 {{= it.age}} 岁了但是你还没有名字?</div> {{?}} </script>
JavaScript(需要先引入jQuery):
var jst = {};
var VALUE = http://www.mamicode.com/{/{/=(.*)/}/}/g;"‘+($1)+‘");
var ev = result;
// if && else
// 这里是为了把字符 if else 里面的内容提取出来
ev = ev.replace(IF, "‘; if(($1)){out +=‘ ")
.replace(ELSE, "‘}else{out += ‘ ")
.replace(ELSE_IF, "‘;}else if(($1)){ out += ‘ ")
.replace(END_IF, "‘}; out+=‘ ");
ev = "var out = ‘‘; out+=‘ " + ev.split(‘\n‘).join("") + "‘ ;";
//console.log(ev);
// debugger
return eval(ev);
}
}
//运行部分:
var func = jst.template($(‘.js-template‘).html());
$(‘#target‘).html(func({
name:‘十一川‘,
age:0
}));
【仿doT前端模板】二、if else