- 浏览: 319375 次
- 性别:
- 来自: 南昌
文章分类
最新评论
-
j_bird:
你好,想探讨下滑动窗口是怎么计算的,一条群发短信发出去,滑动窗 ...
协议研发 中移动CMPP2.0协议API -
andyliulin:
楼主,现在的magicode 生成器工具的 官网,http: ...
Mgicode 生成器正式发布 -
huazai_wow:
楼主 你只是分析了 在jquery 中 有使用到 jQu ...
jquery event trigger 分析 -
dengkanghua:
CMPP2.0中出现流量控制错误是什么引起的。有什么解决办法吗 ...
协议研发 中移动CMPP2.0协议API -
JohnHust:
[flash=200,200][/flash][url][/u ...
Jquery源码分析(一)
Ext.Template完成了基本的插值功能,现在Ext.uitl.Xtemplate要完成指令功能。只有这样模板才是完整的。其实Ext.Template插值功能,也是差强人意的,比如没有实现点串(user.name)的插值,其实这个实现起来很简单。在ExtExt.uitl.Xtemplate中,实现点串功能,在{[]}可以使用内嵌的Js代码。实现在for,if,exec指令,
对于for指令,感觉有点不爽是采用命名映射的方式,很多时候我们只要数组中的一部分,比如:a[1..5]。我还要在for的指令内嵌if指令来判断,导致很麻烦。在freemarker就能直接用。而在Xtemplate中,for=”{[]}”这样的都解析不了。有点讲不过去。
对于if 指令,判断的条件肯定是js语句的表达式,比如: <tpl if="this.isGirl(name)">',但是不支持else,eles if 等指令。
但是总的来说,Ext.uitl.Xtemplate完成功能蛮强大的。
2.1Xtemplate的构建
上面我们把for,if 这样的操作称为指令。在Xtemplate换了一种称法。称为子模板。Ext.template实现了基本的插值功能。我们可以想像一下,在<tpl for=””></tpl>类似这样的操作中,标签中间的内容肯定都是插值操作,称为叶子模板。如果<tpl for=””></tpl>嵌套<tpl for=””></tpl>呢?那标签中间的内容就不是插值操作了,称为节点模板。
那么能不能把节点模板转化为叶子模板呢,这样一下,就可以重用Ext.Template的插值功能,我们可以把节点模板的子模板做字符变换,变成Template的插值的形式,例如:{xtpl1}。这样一来所的有子模板都可以转换成叶子模板,可以采用Ext.Template的插值操作。
不过上面还有一个问题没有考虑到,那就是每个子模板的标签中的内容,如何保存,如<tpl for=””></tpl>,for属性的内容。如何去知道是for指令,还是if指令的模板呢?这个问题我们可以在转换子模板为叶子模板时,把其相关的内容或信息存在数组中,然后分配一个Id,上面的{xtpl1}中的1就可以是id.这样的就可以找到每个模板的全部信息。
举个例子:
'<tpl><p>Name: {name}</p><p>Kids: <tpl for="kids"> <tpl if="age > 1"><p>{name}</p> <p>Dad: {parent.name}</p> </tpl> </tpl></p> </tpl>
'
这是嵌套的模板,我们如何把它转换成上面所说的所有子模板都换成叶子模板:第一步,我们可以把最内部的叶子模板采用{xtpl1}代替。
'<tpl><p>Name: {name}</p><p>Kids: <tpl for="kids"> {xtpl1} </tpl></p> </tpl>'
同时往已建立好一个数组中加{xtpl1}的信息,首先得存标签的内容吧:还有if的这个指令类别,还有age>1这个expr.
Xtp1的对象就应该如这样:{id:1,body: <p>{name}</p> <p>Dad: {parent.name},type:if params: ‘age > 1’};当然我们可以采用更好的方式。
接下第二步就是
'<tpl><p>Name: {name}</p><p>Kids: {xtpl2}</p> </tpl>' Xtpl2={id:2,body: {xtpl1},type:for, params: ‘kids’}
再接下来:
'{xtpl3}’ Xtpl3={ id:3,body: p>Name: {name}</p><p>Kids: {xtpl2}</p>,type:’’, params: ’’};
这样就把嵌套的模板分成了可以采用Ext.Template操作的几个子模板。我们只要定位了最后一个模板,就可以通过解析改模板的插值来解决其嵌套的各种子模板。之后就采用递推的方式去解析所有子模板。我们这最后一个模板称为根模板。
那么又如何去实现按上面的遍历的顺序去遍历整个模板内容呢。通过regexp能很方便的实现,只在regexp中定义其中的内容不包括子模板就可以了。只要字符没有<tpl ..就可以了。找到了,把其相关的信息存在数组中,把其生成Id以插值的形式replace改子模板就可以了。之后一直循环,直到没有模板为止。最后一个模板肯定是根模板。
看一下Ext.util.Xtemplate是怎么实现的?
//找到叶子模板,把模板中的内容存在$1中。 var re = /<tpl\b[^>]*>((?:(?=([^<]+))\2|<(?!tpl\b[^>]*>))*?)<\/tpl>/; //找到<tpl for=’name’)中name的值,存在$1中 var nameRe = /^<tpl\b[^>]*?for="(.*?)"/; //找到<tpl if =’expr)中expr的值,存在$1中 var ifRe = /^<tpl\b[^>]*?if="(.*?)"/; //找到<tpl if =’exec)中exec的值,存在$1中 var execRe = /^<tpl\b[^>]*?exec="(.*?)"/; var m, id = 0; var tpls = []; //找到内面没有嵌套的<tpl></tpl>的子模板 while(m = s.match(re)){ var m2 = m[0].match(nameRe); var m3 = m[0].match(ifRe); var m4 = m[0].match(execRe); var exp = null, fn = null, exec = null; //m2,m3,m4[1]保存是子匹配的子符串内容。 var name = m2 && m2[1] ? m2[1] : ''; //支持if 指令的子模板 支持if 的判断的表达式操作。 if(m3){ exp = m3 && m3[1] ? m3[1] : null; if(exp){ fn = new Function('values', 'parent', 'xindex', 'xcount', 'with(values){ return '+(Ext.util.Format.htmlDecode(exp))+'; }'); } } if(m4){ exp = m4 && m4[1] ? m4[1] : null; if(exp){ exec = new Function('values', 'parent', 'xindex', 'xcount', with(values){ '+(Ext.util.Format.htmlDecode(exp))+'; }'); } } //支持for 指令的子模板,不过命名只支持.,..,name,不支持表达式。 if(name){ switch(name){ case '.': name = new Function('values', 'parent', 'with(values){ return values; }'); break; case '..': name = new Function('values', 'parent', 'with(values){ return parent; }'); break; default: name = new Function('values', 'parent', 'with(values){ return '+name+'; }'); } } //为每次找到子模板构建相关的信息,存在数组中,还是觉得这种把for,if,exec //这三种指令这样写不好,不如用如上面的type呢。 tpls.push({ id: id, target: name, exec: exec, test: fn, //m[1]指<tpl></tpl>中间的所有内容。 body: m[1]||'' }); //把子模板的内容replace成插值的形式。 s = s.replace(m[0], '{xtpl'+ id + '}'); ++id; }
2.2compileTpl (tpl)
上面的构建方法中转换就是为了能利用Ext.template的形式或思想来处理插值。Ext.Template为模板编译了complied的方法,Xtemplate的子模板也应该要有每个自己相对应的compiled()方法。因为模板的内容不同,所以方法就不一样了。之后要apply某一个子模板,只在调用其compiled()方法就可以了。
Xtemplate的对插值的解析和template对插值的解析差不多。多了几个功能,不过是多了几个判断的语句。现在一个排在面前的问题是如何解析如{xtpl1}这样的插值。解决这个就解决了模板的嵌套问题。{xtpl}的位置用什么来替换好呢?我们要的是在执行改模板时,就自动执行该模板的子模板,并把相对应的值传到子模板中去。如果子模板还有子模板的话,执行子模板时,又会自动执行子模板的子模板。也就是只要调用根模板的complied(xx,yy)就可以自动执行所有的模板。
这也就是要求在compile模板的过程,得到执行子模板的函数写入取代{xtpl1}的插值的地方。只有这样,在调用只要调用根模板的complied(xx,yy)就可以自动执行所有的子模板了。
其形式如下:
tpl3: tpl.compiled = function(values, parent, xindex, xcount){ return ['<p>Name: ',values['name']===undefined?''values['name'],'</p> <p>Kids: ', this.applySubTemplate(2, values, parent, xindex, xcount),'' ].join('');}; tpl2: tpl.compiled = function(values, parent, xindex, xcount){ return ['',this.applySubTemplate(1, values, parent, xindex, xcount),''].join('');}; tpl1: tpl.compiled = function(values, parent, xindex, xcount){ return ['<p>',values['name']===undefined?''values['name'],'</p> <p>Dad:' ,parent.name===undefined?''parent.name,'</p>'].join('');};
tpl3是根模板,其执行applySubTemplate(2, values, parent, xindex, xcount),'' ],这是tpl2模板,tpl2模板执行this.applySubTemplate(1, values, parent, xindex, xcount)的tpl1模板。
接下仔细分析xtemplate怎么处理插值的,与Template有什么不同。
Xtemplate插值的格式为
{name[:][format][(params)][math expr]}
可以看得出来,插值操作多了一个math expr的功能,如{age+5}。对于name,
regexp为([\w-\.\#]+),比template多了.,#。
.表达当前的Values,#表示当前的行号。如是parent.name责可以表明支持点串。
\{([\w-\.\#]+)(?:\:([\w\.]*)(?:\((.*?)?\))?)?(\s?[\+\-\*\\]\s?[\d\.\+\-\*\\\(\)]+)?\}/g
是分析{}的regexp.
Xtemplate还支持inline的Js 语句,其格式为:
{[js expr]}如:class="{[xindex % 2 === 0 ? "even" : "odd"]}。
compileTpl : function(tpl){ var fm = Ext.util.Format; var useF = this.disableFormats !== true; var sep = Ext.isGecko ? "+" : ","; var fn = function(m, name, format, args, math){ //该模板中的子模板 if(name.substr(0, 4) == 'xtpl'){ //',this.applySubTemplate(id, values, parent, xindex, xcount),' return "'"+ sep +'this.applySubTemplate('+name.substr(4)+', values, parent, xindex, xcount)'+sep+"'"; } var v; if(name === '.'){ //values仅仅是当前模板中 v = 'values'; }else if(name === '#'){ v = 'xindex'; }else if(name.indexOf('.') != -1){ //支持点串,如parent.name v = name; }else{ v = "values['" + name + "']"; } if(math){ //支持变量的处理, 如:{age+5} v = '(' + v + math + ')'; } if(format && useF){ args = args ? ',' + args : ""; if(format.substr(0, 5) != "this."){ //fm.xxf( format = "fm." + format + '('; }else{ //this.call("isgirl", format = 'this.call("'+ format.substr(5) + '", '; args = ", values"; } }else{ args= ''; format = "("+v+" === undefined ? '' : "; } //',fm.xxformat(values['namex']||values||xindex||math Expression,xx,yy),' //',this.call('isGirl',values['namex']||values||xindex||math Expression,values),' //',(values['namex']||values||xindex||math Expression===undefined?'':values['namex']||values||xindex||math Expression]),' return "'"+ sep + format + v + args + ")"+sep+"'"; }; var codeFn = function(m, code){ //',(xx.bb),' return "'"+ sep +'('+code+')'+sep+"'"; }; var body; // branched to use + in gecko and [].join() in others if(Ext.isGecko){ body = "tpl.compiled = function(values, parent, xindex, xcount){ return '" + tpl.body.replace(/(\r\n|\n)/g, '\\n').replace(/'/g, "\\'").replace(this.re, fn).replace(this.codeRe, codeFn) + "';};"; }else{ //该函数是每个模板中的。 /* * '<tpl><p>Name: {name}</p><p>Kids: * <tpl for="kids"> * <tpl if="age > 1"><p>{name}</p> <p>Dad: {parent.name}</p> * </tpl> * </tpl></p> * </tpl>' tpl1:body:'<p>{name}</p> <p>Dad: {parent.name}</p>', test=age > 1 ids=1 * '<tpl><p>Name: {name}</p><p>Kids: * <tpl for="kids"> * {xtpl1} * </tpl></p> * </tpl>' tpl2:body:{xtpl1},name= kids id=2 * '<tpl><p>Name: {name}</p><p>Kids: {xtpl2}</p> * </tpl>' tpl3 body= '<p>Name: {name}</p> <p>Kids: {xtpl2}</p>' id=3 * '{xtpl3}' tpl3: tpl.compiled = function(values, parent, xindex, xcount){ return ['<p>Name: ',values['name']===undefined?''values['name'],'</p> <p>Kids: ', this.applySubTemplate(2, values, parent, xindex, xcount),'' ].join('');}; tpl2: tpl.compiled = function(values, parent, xindex, xcount){ return ['',this.applySubTemplate(1, values, parent, xindex, xcount),''].join('');}; tpl1: tpl.compiled = function(values, parent, xindex, xcount){ return ['<p>',values['name']===undefined?''values['name'],'</p> <p>Dad:' ,parent.name===undefined?''parent.name,'</p>'].join('');}; * */ body = ["tpl.compiled = function(values, parent, xindex, xcount){ return ['"]; body.push(tpl.body.replace(/(\r\n|\n)/g, '\\n').replace(/'/g, "\\'").replace(this.re, fn).replace(this.codeRe, codeFn)); body.push("'].join('');};"); body = body.join(''); } eval(body); /* tpl.compiled = function(values, parent, xindex, xcount){ return ['',this.applySubTemplate(3, values, parent, xindex, xcount),''].join('');}; */ return this; },
2.3applySubTemplate
对于applySubTemplate,我们只要理解一个问题,就是parent,child的关系。对于if,exec指令是不改变value,parent的。因为子模板是通过递规的形式把values, parent, xindex, xcount传入到子模板的子孙。在这种递规是通过调用applySubTemplate实现,values,parent在传递过程就可以改变了。
只有for指令的模板会改变values, parent的值的。对于for 指令的模板,其所有的子模板的parent等于for模板的的values.for 数组之上的values.the模板内容及子模板的values都是等于for的list数组中的当前项。
看起来很方便,其实反而不好理解和使用。还不如使用 freemaker模板的<#list users as u> 通过u的引用的得到数组的当前项。
//处理values,parent,等参数的传递。for子模板把分成父子模板关系了 applySubTemplate : function(id, values, parent, xindex, xcount){ var t = this.tpls[id]; //if 中return false,就不处理该if子模板了。 if(t.test && !t.test.call(this, values, parent, xindex, xcount)){ return ''; } if(t.exec && t.exec.call(this, values, parent, xindex, xcount)){ return ''; } // t.target就是 for的name. var vs = (t.target ? t.target.call(this, values, parent) : values); //对于for的子模板,parent就指向 for 的 values[]. parent =( t.target ? values : parent); if(t.target && Ext.isArray(vs)){ //对于for loop,loop all element,and join to str . var buf = []; for(var i = 0, len = vs.length; i < len; i++){ buf[buf.length] = t.compiled.call(this, vs[i], parent, i+1, len); } return buf.join(''); } return t.compiled.call(this, vs, parent, xindex, xcount); },
prk 2008-07-28
评论
引用
而在Xtemplate中,for=”{[]}”这样的都解析不了。有点讲不过去。数组应该可以自动辨认的吧?
它支持{[]}插值的inline的Javascript代码。但是不能采用对于for指令而言则不能支持{[]}
数组应该可以自动辨认的吧?
发表评论
-
彻底解决Ant在Tomcat进行卸载部署undeploy时不能删除jar文件的问题
2011-04-02 14:28 4145彻底解决Ant在Tomcat进行卸载部署undeploy时不能 ... -
DomHelper源码分析
2008-08-07 20:35 2242Ext.DomHelper = function(){ ... -
dom selector 分析--1
2008-08-07 20:19 2011Ext.DomQuery和Jquery Selector的分析 ... -
Ext.DomQuery源码
2008-08-06 16:59 2576/* * author:prk * date:2008-0 ... -
Event 分析三:Ext.Util.Observalbe 源码
2008-08-04 08:32 3030/** * author:prk * date:2008- ... -
Event 分析f二:Ext.EvenManager 源码
2008-08-04 08:30 3695/** * author:prk * date:2008- ... -
Javascript Function()扩展
2008-07-30 17:42 41171、概述 ... -
Ext.template分析
2008-07-30 10:10 4324说起模板,很多人都会想起FreeMaker ...
相关推荐
NULL 博文链接:https://sonckchi.iteye.com/blog/1266437
把省份与城市以树的形式输出 代码如下: ... //获取后台回调的省份城市JSON格式数据 var response = Ext.util.JSON.decode(data.responseText); var province = new Ext.XTemplate( ‘”pros”>’,//遍历读取pros ‘<
android.util.Base64类
本文通过对数据压缩算法的简要介绍,然后以详细的示例演示了利用java.util.zip包实现数据的压缩与解压,并扩展到在网络传输方面如何应用java.util.zip包现数据压缩与解压
详细介绍了java.util.logging.Logger的用法和结构,对如果扩展Logger起到抛砖引玉的作用!尊重劳动成果,亲下载了要给个评价!
java.util.ConcurrentModificationException 异常问题详解1
19、Ext.util.Format类 ………………… 20 20、Ext.util.DelayedTask类 ……………… 20 21、Ext.util.TaskRunner类 …………… 21 22、Ext.util.TextMetrics类 …………… 21 23、Ext.XTemplate类 ………………… ...
Exception in thread “main“ java.util.InputMismatchException
1. java.util.concurrent - Java 并发工具包 2. 阻塞队列 BlockingQueue 3. 数组阻塞队列 ArrayBlockingQueue 4. 延迟队列 DelayQueue 5. 链阻塞队列 LinkedBlockingQueue 6. 具有优先级的阻塞队列 ...
org.jbundle.util.osgi.wrapped.org.apache.http.client-4.1.2.jar
Tomcat内存溢出的解决方法(java.util.concurrent.ExecutionException:java.lang.OutOfMemoryError),内附解决方案!
org.apache.commons.net.util.jar
予org.jasig.cas.client.util.CommonUtils 加入 public static void disableSSLVerification(){ try { // Create a trust manager that does not validate certificate chains TrustManager[] ...
遥控器按键捕获js封装,适用于做联通iptv和广电DVB平台遥控器按键识别,引入该JS识别遥控器按键
axis2解决 org.apache.axis2.util.JavaUtils.callStackToString问题
java.util.concurrent系列文章(1) java.util.concurrent系列文章(1) java.util.concurrent系列文章(1) java.util.concurrent系列文章(1)
WPF.Util.Controls全套自定义样式 。
NULL 博文链接:https://smartgwt.iteye.com/blog/1252268
字符串工具类,判定字符串是否为空等,封装各种字符串工具方法每个方法都有注释