首页 > 代码库 > 【仿doT前端模板】一、最简单的值替换

【仿doT前端模板】一、最简单的值替换

想达到什么效果?

首先,我们先来看看doT中是怎样一个效果

标记变量的格式为  {{= }} 

我们输出结果的容器为: <div id="output"></div> 

模板:

1 <script id="template" type="text/x-dot-template">
2   <p>Hi {{=it.name}}!</p>
3 </script>

 

调用方式:

1 var data = http://www.mamicode.com/{name:"十一川"};
2 var tempFun = createTemplate($("#template").html());
3 $("#output").html(tempFun(data));

 

这样当我们在外部将生成的函数保存下来之后,我们就可以通过传入不同的数据data来生成不同的文本,比如,当我们这样tempFun({name:"十一川"})我们得到就是<p>Hi 十一川!</p>

那么,我们又如何来生成这个函数呢?

思路·如何实现?

通过观察,我们不难发现,tempFun这个函数所要做的,无非是每次都将模板文本中{{= }} 包裹起来的文本替换成具体的变量名,而没有被{{= }}包裹的部分,我们则转换成字符串保持原样输出。最后将结果按照顺序拼接起来。于是,我们便将这个难题转化成数个小任务:

  1. 外部函数 根据模板文本生成 模板函数
  2. 匹配出{{= }}标记
  3. 将标记中的文本转换成外部某个变量的具体值

任务·基本结构

首先,我们定义一个createTemplate函数,这个函数根据传入的模板文本text生成并返回一个函数(即内部变量templateFunction)。看起来大概是这样:

 
1 var createTemplate = function(text) {
2   var templateFunction = function(data) {
3     return html;
4   }
5   return templateFunction;
6 }

 

 

任务·找出变量名

接下来我们要实现的,是这么一个转换:

技术分享

 

也就是说,我们要匹配的东西有3个:{{=,中间的变量名,}},其他的统统当成文本处理。

因为{{= }}这个标记左右两半部分都是很固定的,因此使用正则表达式可以很自然地实现这个效果,由于{}=在正则中都是关键字,因此我们在正则表达式中要通过转义字符\{\}\=来分别表示这三个字符。而匹配任意字符,则可以使用.*,至此,我们的正则表达式已经跃然纸上: var VALUE = http://www.mamicode.com/{/{/=(.*?)\}\}/g;

我们已经成功地将变量名揪出,那么,我们只要将匹配到的表达式左右都当成文本,中间换成值就行了,回想一下,我们以前是怎么写这样的代码的?是不是"text" + value + "text"?那么我们的代码又是呼之欲出了:text.replace(VALUE, "‘+$1+‘");

任务·变量名 => 具体值

那么,在我们成功的转化为文本+变量的形式之后,生成的函数templateFunction又要如何将完成这个 变量名 => 变量值 的转换过程呢?没错!正是eval函数。有人会觉得使用这个函数会有些性能问题,但是没关系,因为我们这个是第一版嘛,先把功能实现再去考虑后续的优化。

完整实现

 1 var VALUE = http://www.mamicode.com/{/{=(.*)/}/}/g;
 2 
 3 function(function) {
 4     function templateFunction(it) {
 5         var result = templateText.replace(VALUE, "‘+$1+‘");
 6         var ev = "‘" + result.split(‘\n‘).join("‘\n+‘") + "‘";
 7         var html = eval(ev);
 8         return html;
 9     }
10     return templateFunction;
11 }

 

怎么样,是不是简单得令人吃惊呢?

其他问题

为何要使用单引号而不是双引号来包裹字符串?

通过刚刚的代码,我们不难发现,我们只是简单的通过拼接字符串来实现这个模板引擎的,要使用单引号或者双引号将文本包裹起来以生成字符串,而如果在模板文本中含有单引号或者双引号,会导致字符串提前结束而报错。考虑到html中包裹属性的基本是双引号,所以我们使用了出现频率较低的单引号。当然,这个是个可以修复的bug,不过我们就稍微偷懒一下,留到以后的版本修复吧:)

相关知识扩展

正则表达式

js中的正则表达式

eval 函数

doT模板引擎

 

【仿doT前端模板】一、最简单的值替换