此版本有如下改进:
- 吸取众人的意见,防止与ASP等后台模板的界定符冲突,默认左右界定符为<&,&>
- 加入新的操作符<&~,至此整个操作符体系为:
<& JS逻辑 &> <& for(var i=0,tl = @trs.length,tr;i < tl;i++){ &> <&= JS输出内容 &> <&= tr.name &> < 这是注释 &> < 导入子模板 &> <&: CSS选择符 &> <&: tds_tmpl &> <&~ URL地址 &> <&~ /aaa/bbb.html &> - 为了迎合大规模开发的需要,后台数据统统增加@标识,一来便于修改,二来内部实现抛弃了with语句,强行让它们依附于data对象,让我们可以使用||设置默认值。
//dom.ejs v6 by 司徒正美 //http://www.cnblogs.com/rubylouvre/archive/2010/10/04/1841933.html ;(function(){ this.dom = { quote : String.quote || function (str) { str = str.replace(/[\x00-\x1f\\]/g, function (chr) { var special = metaObject[chr]; return special ? special : '\\u' + ('0000'+chr.charCodeAt(0).toString(16)).slice(-4); }); return '"' + str.replace(/"/g, '\\"') + '"'; } } if(!String.prototype.trim){ String.prototype.trim = function(){ return this.replace(/^[\s\xa0]+|[\s\xa0]+$/g, ''); } } ;(function(w,s){ //http://blogs.msdn.com/xmlteam/archive/2006/10/23/using-the-right-version-of-msxml-in-internet-explorer.aspx s = ["XMLHttpRequest", "ActiveXObject('Msxml2.XMLHTTP.6.0')", "ActiveXObject('Msxml2.XMLHTTP.3.0')", "ActiveXObject('Msxml2.XMLHTTP')", "ActiveXObject('Microsoft.XMLHTTP')"]; //IE专有的JScript方法:ScriptEngine,ScriptEngineBuildVersion,ScriptEngineMajorVersion,ScriptEngineMinorVersion,CollectGarbage,RuntimeObject和GetObject。 if( !-[1,] && w.ScriptEngineMinorVersion() === 7 && location.protocol === "file:"){ s.shift(); } for(var i = 0 ,el;el=s[i++];){ try{ if(eval("new "+el)){ dom.xhr = new Function( "return new "+el); break; } }catch(e){} } })(window); var metaObject = { '\b': '\\b', '\t': '\\t', '\n': '\\n', '\f': '\\f', '\r': '\\r', '\\': '\\\\' }, _startOfHTML = "\t__views.push(", _endOfHTML = ");\n", _rAt = /(^|[^\w\u00c0-\uFFFF_])(@)(?=\w)/g, _partial = function(url){ var xhr = dom.xhr(); xhr.open("GET",url,false); xhr.setRequestHeader("If-Modified-Since","0"); xhr.send(null); return xhr.responseText|| "" } dom.ejs = function(obj,usePart){ if(!usePart){//如果普通模板,则要整理配置文件 obj.left = obj.left || "<&"; obj.right = obj.right || "&>"; obj.rLeft = obj.rLeft || new RegExp("\\s*"+ obj.left+"\\s*"); obj.rRight = obj.rRight || new RegExp("\\s*"+ obj.right+"\\s*"); } var key = obj.selector || obj.url, rAt = _rAt, startOfHTML = _startOfHTML, endOfHTML = _endOfHTML, partial = _partial, self = arguments.callee, buff = ["var __views = [];\n"],str,logic; if(obj.selector){ var el = document.getElementById(key); if (!el) throw "can not find the target element"; str = el.text; }else { str = partial(obj.url); if (!str) throw "the target file does not exist"; } if(!self[key]){ var arr = str.trim().split(obj.rLeft),temp = [],url,selector,i=0,n=arr.length,els,segment; while(i<n){ segment = arr[i++]; els = segment.split(obj.rRight); if(segment.indexOf(obj.right) !== -1){//这里不使用el.length === 2是为了避开IE的split bug switch (els[0].charAt(0)) { case "~"://include局部模板 以URL方式引入 delete obj.selector; obj.url = els[0].substring(1).trim(); self[url] = self[url] || self(obj,true); temp = temp.concat(self[url] ); break; case ":"://include局部模板 以元素选择符方式引入 delete obj.url; selector = obj.selector = els[0].substring(1).trim(); self[selector] = self[selector] || self(obj,true); temp = temp.concat(self[selector] ); break; case "="://处理后台返回的变量(输出到页面的); logic = els[0].substring(1); if(logic.indexOf("@")!==-1){ temp.push(startOfHTML, logic.replace(rAt,"$1data."), endOfHTML); }else{ temp.push(startOfHTML, logic, endOfHTML); } break; case "#"://处理注释 break; default://处理逻辑 logic = els[0]; if(logic.indexOf("@")!==-1){ temp.push(logic.replace(rAt,"$1data."), "\n"); }else{ temp.push(logic, "\n"); } } //处理静态HTML片断 els[1] && temp.push(startOfHTML, dom.quote.call(null,els[1]), endOfHTML) }else{ //处理静态HTML片断 temp.push(startOfHTML, dom.quote.call(null,els[0]), endOfHTML) } } if(usePart){//局部模板 return (self[key] = temp); }else{ self[key] = new Function("data",buff.concat(temp).join("")+';return __views.join("");'); } } return self[key](obj.data || {}); } })();
重申一次,并不是前台模板系统无能,只是你我做的项目不同,访问量大小决定着代码需要用另一种截然不同的方式实现。我想到一个例子,就是腾讯的QQ群,里面80%的内容都是JS模板。