<script type="text/html" id="template1"> <tr> <td>${ID}</td> <td>${$data.Name}</td> <td>${$item.getLangs(';')}</td> </tr> </script> var users = [ { ID: 'think8848', Name: 'Joseph Chan', Langs: [ 'Chinese', 'English' ] }, { ID: 'aCloud', Name: 'Mary Cheung', Langs: [ 'Chinese', 'French' ] } ] $('#template1').tmpl(users,{ getLangs: function(separator){ return this.data.Langs.join(separator); } }).appendTo('#table1');
乍一看,调用的方式是一样的,你会疑问为什么模版里要用$item和$data这样的形式,其实你仔细看一下上个例子生成的匿名函数,就能发现这里这么写其实是为了更好的拼接。以下是这个例子所生成的匿名函数:
function anonymous(jQuery, $item) { var $=jQuery,call,__=[],$data=$item.data;with($data){__.push('<tr> <td>');if(typeof(ID)!=='undefined' && (ID)!=null){__.push($.encode((typeof(ID)==='function'?(ID).call($item):(ID))));}__.push('</td> <td>');if(typeof($data.Name)!=='undefined' && ($data.Name)!=null){__.push($.encode((typeof($data.Name)==='function'?($data.Name).call($item):($data.Name))));}__.push('</td> <td>');if(typeof($item.getLangs)!=='undefined' && ($item.getLangs)!=null){__.push($.encode($item.getLangs(';')));}__.push('</td> </tr>');}return __;
$data是$item的一个属性,存储着数据,$item中同样有很多自定义方法。这里getLangs方法里的this在匿名函数具体调用的时候会指向$item,这里需要注意一下。在newTmplItem方法里执行我们生成的匿名函数,这里都没有什么问题,这里我们通过正则简单回看一下这个${ID},${$data.Name}是如何匹配的。这两个匹配其实是一个道理,匹配的正则如下:
/\{\{(\/?)(\w+|.)(?:\(((?:[^\}]|\}(?!\}))*?)?\))?(?:\s+(.*?)?)?(\(((?:[^\}]|\}(?!\}))*?)\))?\s*\}\}/g
大家对照我之前的分解表看比较方便。我们拿${$data.Name}举例,不过使用之前,它已经转成{{= $data.Name}}
2:尝试匹配(\/?),?表示优先匹配,但是{{后面没有/,所以匹配无效,?表示最多成功匹配一个。继续后面的匹配
3:尝试匹配(\w+|.),如果|左边的能匹配成功则不需要进行右边的匹配,所以\w+会尽可能去匹配,但是\w无法匹配=所以,尝试用|右边的.去匹配,.可以匹配=,因为没有量词,所以只能匹配这个=
4:尝试匹配(?:\(((?:[^\}]|\}(?!\}))*?)?\))?
4.1:(?:)表示匹配但不捕获,其里面第一个要匹配的是(,可以看到{{=后面是空格而不是(所以匹配失败,加上这不捕获的分组使用的是优先量词?,允许匹配为空,继续后面的匹配
5:尝试匹配(?:\s+(.*?)?)?
5.1:分组里第一个匹配\s+,匹配=后面的空格符号,继续尝试匹配,当匹配到$时发现无法匹配,则\s+匹配结束。
5.2:尝试匹配(.*?)?,分组外围使用的是?,尽可能尝试匹配一个看看,对于(.*?)匹配$,因为(.*?)是惰性匹配(不优先匹配),所以系统选择不匹配,另外外围的?也允许匹配不成功。继续后面的匹配
6:尝试匹配(\(((?:[^\}]|\}(?!\}))*?)\))?
6.1:如果4的步骤不匹配,那5中的\(同样无法匹配$,所以匹配失败
7:尝试匹配\s*\}\},如果从$开始匹配,果断匹配失败。整个匹配结束了么?其实还没有,开始对惰性匹配继续进行匹配
8:让(.*?)先匹配$,再执行5,6步骤,如果最终匹配失败了,继续让(.*?)匹配$d,依次类推,直到(.*?)匹配到$data.Name,这时6结果匹配成功。整个正则匹配匹配成功。
以上则是该正则的一次简单匹配过程,可以发现该正则使用了惰性匹配一定程度上减少了正则的回溯次数,提高了效率。
3.each的用法
<script type="text/html" id="template1"> <li> ID: ${ID}; Name: ${Name}; <br />Langs: <ul> <STRONG> {{each(i,lang) Langs}} <li>${i + 1}: <label>${lang}. </label> </li> {{/each}} </STRONG> </ul> </li> </script> var users = [ { ID: 'think8848', Name: 'Joseph Chan', Langs: [ 'Chinese', 'English' ] }, { ID: 'aCloud', Name: 'Mary Cheung', Langs: [ 'Chinese', 'French' ] } ]; $('#template1').tmpl(users).appendTo('#eachList')
运行过程基本一致,我们就看两个部分:
之前的${ID},${Name}和之前的匹配是一致的,这里就不描述了,看一下这段字符串的匹配。
{{each(i,lang) Langs}} ${i + 1}: ${lang}. {{/each}}
主要是{{each(i,lang) Langs}}和{{/each}}这两条的匹配
{{each(i,lang) Langs}}
2:尝试匹配(\/?),/不能与e相匹配,所以匹配失败,因为存在?量词,继续下面的匹配
3:尝试匹配(\w+|.),其中\W+是优先匹配,所以它一直匹配到each,当它尝试匹配(时,发现匹配失败时,则就返回匹配结果each进入分组,继续下面的匹配
4:尝试匹配(?:\(((?:[^\}]|\}(?!\}))*?)?\))?
4.2:尝试匹配((?:[^\}]|\}(?!\}))*?)?