当前位置: 代码迷 >> JavaScript >> 仿服务器端脚本形式的JS模板实现方法
  详细解决方案

仿服务器端脚本形式的JS模板实现方法

热度:687   发布时间:2012-11-06 14:07:00.0
仿服务器端脚本方式的JS模板实现方法

http://bbs.51js.com/thread-65160-1-1.html?

?

?

?

<html xmlns="http://www.w3.org/1999/xht...?
<head>?
<meta http-equiv="Content-Type" content="text/html; charset=gb2312" />?
<title>jssp演示</title>?
<script language="javascript">?
/**?
* @description:?
* 使用javascript模仿JSP的页面解析和运行,运行于客户端?
* 允许应用人员象开发JSP页面一样使用<%..%>?
* 允许页面动态包括子页面(同步读取页面)?
*?
**/?

//@--------------------------------- JSSP声明?
var jssp=function(){};?

/**?
* 页面缓存管理实例对象?
*/?
jssp.cacheInstance=null;?
/**?
* 页面加载实例对象?
*/?
jssp.pageLoaderInstance=null;?

/**?
* 在指定dom插入pagePath的执行后的页面内容?
*/?
jssp.render=function(pagePath,dom){?
if(typeof dom=="string") dom=document.getElementById(dom);?
var content=jssp.Core.run(pagePath);?
dom.innerHTML=content;?
}?

//@------------------------------------ JSSP运行配置?
/**?
* 引擎运行全局配置?
*/?
jssp.Config={};?
/**?
* 如果在客户端运行,是否缓存解析的页面?
*/?
jssp.Config.cachable=true;?
/**?
* 当jssp.Config.cacheable为true且在?
*/?
jssp.Config.cacheClass="jssp.Cache.DefaultCache";?
/**?
* 页面内容读取器?
*/?
jssp.Config.pageLoaderClass="jssp.Core.PageLoader.Ajax";?

//@------------------------------------ JSSP页面缓存类?
/**?
* 页面缓存类?
*/?
jssp.Cache=function(){}?
/**?
* 设置缓存?
*/?
jssp.Cache.prototype.set=function(key,cache){}?
/**?
* 得到缓存?
*/?
jssp.Cache.prototype.get=function(key){}?
/**?
* 默认的缓存实现类?
*/?
jssp.Cache.DefaultCache=function(){?
this.caches={};?
}?
jssp.Cache.DefaultCache.prototype.set=function(key,cache){?
this.caches[key]=cache;?
}?
jssp.Cache.DefaultCache.prototype.get=function(key){?
return this.caches[key];?
}?

//@----------------------------------- JSSP运行上下文类?
/**?
* jssp页面的执行上下文对象?
* @member params 请求参数数组?
* @member cookies 操作cookies对象 jssp.Cookies?
* @member out 页面流输出对象 jssp.Out?
* @method setAttribute 设置上下文参数?
* @method getAttribute 得到上下文参数?
* @method removeAttribute 删除上下文参数?
* @method include 动态包含子页面?
* @method getCookies,getParameter,getParameters,getOut?
* @param pageUrl 运行的上下文参数?
* @param context 父页面的上下文对象?
*/?
jssp.Context=function(pageUrl,context){?
this.params=this._resolveParam(pageUrl);?
if(!context){?
this.cookies=jssp.Cookies;?
this.out=new jssp.Out();?
this.attributes=[];?
}else{?
this.context=context;?
this.isIncluded=true;?
}?

}?
/**?
* 解析页面后缀参数?
*/?
jssp.Context.prototype._resolveParam=function(pageUrl){?
var i1=pageUrl.indexOf("?");?
if(i1<=0) return [];?
pageUrl=pageUrl.substring(i1+1);?
var s1=pageUrl.split("&");?
var params=[];?
for(var i=0;i<s1.length;i++){?
var s2=s1[i].split("=");?
var key=s2[0];var value=s2[1];?
var ps=params[key];?
if(!ps) ps=[];?
ps[ps.length]=value;?
params[key]=ps;?
}?
return params;?
}?
/**?
* 设置参数值?
*/?
jssp.Context.prototype.setAttribute=function(key,value){?
if(!this.context)?
this.attributes[key]=value;?
else?
this.context.setAttribute(key,value);?
}?
/**?
* 得到参数值?
*/?
jssp.Context.prototype.getAttribute=function(key){?
if(!this.context)?
return this.attributes[key];?
else?
return this.context.getAttribute(key);?
}?
/**?
* 删除指定键的参数值?
*/?
jssp.Context.prototype.removeAttribute=function(key){?
if(!this.context)?
this.attributes[key]=undefined;?
else?
this.context.removeAttribute(key);?
}?
/**?
* 得到请求参数值?
*/?
jssp.Context.prototype.getParameter=function(key){?
var ps=this.params[key];?
if(!ps) return this.context?this.context.getParameter(key):undefined;?
return ps.join(",");?
}?
/**?
* 得到有重复参数的值?
*/?
jssp.Context.prototype.getParameters=function(key){?
var pss=this.params[key];?
if(!pss) pss=this.context?this.context.getParameters(key):undefined;?
return pss;?
}?
/**?
* 得到cookies对象?
*/?
jssp.Context.prototype.getCookies=function(){?
if(!this.context)?
return this.cookies;?
else?
return this.context.getCookies();?
}?
/**?
* 得到输出流OUT对象?
*/?
jssp.Context.prototype.getOut=function(){?
if(!this.context)?
return this.out;?
else?
return this.context.getOut();?
}?
/**?
* 动态包含子页面?
*/?
jssp.Context.prototype.include=function(childPageUrl){?
this.getOut().print(jssp.Core.run(childPageUrl,this));?
}?

jssp.Context.prototype.isIncluded=false;//判断当前页面是否被包含的?

//@-----------------------------------JSSP运行cookies操作类?
/**?
* 简单操纵cookies方法?
*/?
jssp.Cookies=function(){}?
/**?
* 设置cookie项?
*/?
jssp.Cookies.set=function(key,value){?
document.cookie=key+"="+escape(value)+";";?
}?
/**?
* 得到cookie项?
*/?
jssp.Cookies.get=function(key){?
var aCookie=document.cookie.split("; ");?
for(var i=0;i<aCookie.length;i++){?
var aCrumb=aCookie[i].split("=");?
if(key==aCrumb[0])?
return unescape(aCrumb[1]);?
}?
}?
/**?
* 删除cookies项?
*/?
jssp.Cookies.remove=function(key){?
document.cookie=key+"=null; expires=Fri, 31 Dec 1999 23:59:59 GMT;";?
}?
//@------------------------------------ JSSP页面运行输出流类?
/**?
* 页面流输出对象?
*/?
jssp.Out=function(){?
this.datas=[];//数据流片断?
this._index=0;?
}?
/**?
* 把页面流片断放入缓冲区?
*/?
jssp.Out.prototype.print=function(s){?
this.datas[this._index++]=s;?
}?
/**?
* 输出缓冲区里的数据?
*/?
jssp.Out.prototype.flush=function(){?
var data=this.datas.join("");?
this.datas=[];this._index=0;?
return data;?
}?
//@--------------------------------------JSSP页面核心类声明?
jssp.Core=function(){}?
//@--------------------------------------JSSP页面解析实现类?
/**?
* 页面解析?
* @param pageContent JSSP页面内容?
*/?
jssp.Core.parse=function(pageContent){?

var strBuffer=[];//解析后文本存放的缓冲区?
var point=0;//缓冲区指针?
var lineNumber=1;//解析的当前行?

try{?
var betweenPerc=false;?
var isPrint=false;?
strBuffer[point++]="function($context){\n";?
strBuffer[point++]="var $out=$context.getOut();\n";?
strBuffer[point++]="var $cookies=$context.getCookies();\n";?
strBuffer[point++]="try{\n";?
strBuffer[point++]="$out.print(unescape('";?
var line="";?
var value=pageContent;?
var len=value.length;?
for(var i=0;i<len;i++){?
var nextTwo="";?
if(i<=len-2) nextTwo=value.charAt(i)+value.charAt(i+1);?
var nextThree="";?
if(i<=len-3) nextThree=nextTwo+value.charAt(i+2);?
if(nextTwo=="<%"&&nextThree!="<%="&&nextThree!="<%@"){?
strBuffer[point++]="'));\n";?
betweenPerc=true;?
i+=1;?
}else if(nextTwo=="<%"&&nextThree=="<%="&&nextThree!="<%@"){?
strBuffer[point++]=escape(line)+"'));\n";?
line="";?
strBuffer[point++]=" $out.print( ";?
betweenPerc=true;?
isPrint=true;?
i+=2;?
}else if(nextTwo=="<%"&&nextThree!="<%="&&nextThree=="<%@"){?
i+=3;?
var directive="";?
while(nextTwo!="%>"){?
directive+=value.charAt(i);?
i++;?
if(i<=value.length-2){?
nextTwo=value.charAt(i)+value.charAt(i+1);?
}?
}?
strBuffer[point++]=escape(line)+"'));\n";?
line="";?
strBuffer[point++]=jssp.Core.parse._handleDirective(directive);?
strBuffer[point++]=" $out.print(unescape('";?
i++;?
}else if(nextTwo=="%>"){?
strBuffer[point++]=(isPrint?");":"")+"\n $out.print(unescape('";?
if(!betweenPerc) throw new jssp.Core.parse.ParseException("解析错误","必须用'%>'作为结束标签");?
betweenPerc=false;?
isPrint=false;?
i+=1;?
}else if(value.charAt(i)==String.fromCharCode(10)){?
if(!betweenPerc){?
strBuffer[point++]=escape(line)+"\\n'));\n"+" $out.print(unescape('";?
line="";?
lineNumber++;?
}?
}else if(value.charAt(i)==String.fromCharCode(13)){?
if(betweenPerc) strBuffer[point++]="\n";?
}else{?
if(betweenPerc)?
strBuffer[point++]=value.charAt(i);?
else?
line+=value.charAt(i);?
}?
}?
strBuffer[point++]=escape(line)+"'));\n";?
strBuffer[point++]="}catch(e){\n";?
strBuffer[point++]="return '"+"执行页面发生异常.异常类型:'+e.name+'. 错误消息: '+e.message;\n";?
strBuffer[point++]="}\n";?
strBuffer[point++]="if(!$context.isIncluded) return $out.flush();\n";?
strBuffer[point++]="}\n";?
}catch(e){?
point=0;?
strBuffer=[];?
strBuffer[point++]="function($context){\n";?
strBuffer[point++]="return \""+"An exception occurred while parsing on line "+lineNumber+". Error type: "+e.name+". Error message: "+e.message+"\";";?
strBuffer[point++]="}";?
}?
var out=strBuffer.join("");?
return out;?
}?
/**?
* 解析指示头?
*/?
jssp.Core.parse._handleDirective=function(directive){?

var i = 0;?

var tolkenIndex = 0;?
var tolken = new Array();?

//Skip first spaces;?
while ( directive.charAt(i) == ' ' ) {?
i++;?
}?

tolken[tolkenIndex] = "";?
while ( directive.charAt(i) != ' ' && i <= directive.length ) {?
tolken[tolkenIndex] += directive.charAt(i);?
i++;?
}?

tolkenIndex++;?

//Skip first spaces;?
while ( directive.charAt(i) == ' ' ) {?
i++;?
}?

tolken[tolkenIndex] = "";?
while ( directive.charAt(i) != ' ' && directive.charAt(i) != '=' && i <= directive.length ) {?
tolken[tolkenIndex] += directive.charAt(i);?
i++;?
}?

tolkenIndex++;?

//Skip first spaces;?
while ( directive.charAt(i) == ' ' ) {?
i++;?
}?

if( directive.charAt(i) != '=' )?
throw new jssp.Core.parse.ParseException("Sintax error", "Tolken = expected attribute");?
i++?

//Skip first spaces;?
while ( directive.charAt(i) == ' ' ) {?
i++;?
}?

tolken[tolkenIndex] = "";?
while ( directive.charAt(i) != ' ' && i <= directive.length ) {?
tolken[tolkenIndex] += directive.charAt(i);?
i++;?
}?
tolkenIndex++;?

//Skip first spaces;?
while ( directive.charAt(i) == ' ' && i <= directive.length ) {?
i++;?
}?

tolken[tolkenIndex] = "";?
while ( directive.charAt(i) != ' ' && directive.charAt(i) != '=' && i <= directive.length && i <= directive.length ) {?
tolken[tolkenIndex] += directive.charAt(i);?
i++;?
}?

tolkenIndex++;?

if( directive.charAt(i) != '=' && i <= directive.length )?
throw new jssp.Core.parse.ParseException("Sintax error", "Tolken = expected after attribute" );?
i++?

tolken[tolkenIndex] = "";?
while ( directive.charAt(i) != ' ' && i <= directive.length && i <= directive.length ) {?
tolken[tolkenIndex] += directive.charAt(i);?
i++;?
}?

var file = "";?
var context = "";?

if ( tolken[0] != "include" )?
throw new jssp.Core.parse.ParseException("Sintax error","Directive " + tolken[0] + " unknown.") ;?

if ( tolken[1] != "file" )?
throw new jssp.Core.parse.ParseException("Sintax error", "Attribute file expected after include." );?
else file = tolken[2];?

if ( tolken[3] != "context" && tolken[3] != "" )?
throw new jssp.Core.parse.ParseException( "Sintax error", "Attribute context expected after file.");?
else if ( tolken[3] == "context" )?
context = tolken[4]?
else?
context = "$context";?

var out = "$context.include(" + file + ");\n";?

return out;?
}?

/**?
* 解析异常?
*/?
jssp.Core.parse.ParseException=function(name,message) {?
this.name=name;?
this.message=message;?
}?
//@--------------------------------------------页面内容加载接口定义?
/**?
* 页面内容加载类接口定义?
*/?
jssp.Core.PageLoader=function(){}?
/**?
* 读取页面文本?
*/?
jssp.Core.PageLoader.prototype.loadPage=function(pagePath){throw "不能直接调用接口或您还未实现此方法!";}?
//@--------------------------------------------页面运行实现方法?
/**?
* @param pagePath 加载页面?
* @parma context 上下文对象?
*/?
jssp.Core.run=function(pagePath,context){?

if(!jssp.pageLoaderInstance){?
//jssp引擎初始化?
if(jssp.Config.cachable) jssp.cacheInstance=eval("new "+jssp.Config.cacheClass+"();");?
jssp.pageLoaderInstance=eval("new "+jssp.Config.pageLoaderClass+"();");?
}?

var key=pagePath;if(key.indexOf("?")>0) key=key.substring(0,key.indexOf("?"));?

var processer=jssp.Config.cachable?jssp.cacheInstance.get(key):null;?
if(!processer){?
eval("processer="+jssp.Core.parse(jssp.pageLoaderInstance.loadPage(pagePath)));?
if(jssp.Config.cachable) jssp.cacheInstance.set(key,processer);?
}else{?
//alert("cache")?
}?

if(!context)?
context=new jssp.Context(pagePath);?
else?
context=new jssp.Context(pagePath,context);?
return processer(context);?
}?
//@-----------------------------------------------AJAX加载页面实现?
jssp.Core.PageLoader.Ajax=function(){}?

jssp.Core.PageLoader.Ajax.prototype.loadPage=function(pagePath){?
var content=jssp.Ajax.send(pagePath,"GET",false);?
if(!content) {?
alert("请求页面:"+pagePath+" 返回为null!");return null;?
}?
return content;?
}?
//@-----------------------------------------------AJAX操作实现?
jssp.Ajax=function(){}?
/**?
* 建立HTTP连接?
*/?
jssp.Ajax.createHttpRequest=function(){?
if(window.XMLHttpRequest)?
return new XMLHttpRequest();?
var request=null;?
try{?
request=new ActiveXObject("Msxml2.XMLHTTP.4.0");?
}catch(e){?
try{?
request=new ActiveXObject("Msxml2.XMLHTTP");?
}catch(e){?
try{?
request=new ActiveXObject("microsoft.XMLHTTP");?
}catch(e){?
throw "XMLHTTPRequest组件客户端不支持!";?
}?
}?
}?
return request;?
}?

/**?
* 发送AJAX请求?
* @param url 请求页面?
* @param method 请求方法 get or post?
* @param async 是否为异步调用?
* @param callback 回调函数?
* @param preHook 调用前执行函数?
* @param postHook 调用后请求返回执行函数?
*/?
jssp.Ajax.send=function(url,method,async,callback,preHook,postHook){?
method=method.toUpperCase();?

if(typeof preHook=="function") preHook();?

var request=jssp.Ajax.createHttpRequest();?
request.open(method,url,async);?
if(async){?
if(typeof callback!="function") throw "必须要设置回调函数";?
request.onreadystatechange=function(){?
jssp.Ajax.callback(request,callback,postHook);?
};?
}?
request.send(null);?
if(!async) {?
if(request.status==200||request.status==304)?
return jssp.Ajax._chartset(request);?
else?
return null;?
}?
}?
/**?
* 接受响应,调用自定义回调函数?
*/?
jssp.Ajax.callback=function(response,callback,postHook){?
if(response.readyState!=4) return;?
var text;?
if(response.status==200||response.status==304){?
text=jssp.Ajax._chartset(response);?
}?
callback(text);?
if(typeof postHook=="function") postHook();?
}?
/**?
* 中文乱码处理?
*/?
jssp.Ajax._chartset=function(r){?
var t=bytes2BSTR(r.responseBody);?
return t;?
}?

</script>?

<script language="javascript">?
jssp.Config.pageLoaderClass="jssp.Core.PageLoader.CustomerInput";//设置页面读取接口?
jssp.Config.cachable=false;?
jssp.Core.PageLoader.CustomerInput=function(){}?
jssp.Core.PageLoader.CustomerInput.prototype.loadPage=function(pagePath){?
if(pagePath.substring(0,10)!="hello.jssp") return "测试包含子页面,路径:"+pagePath;?
return document.getElementById("pageContent").value;?
}?
function showPage(){?
jssp.render("hello.jssp?name="+Math.random(),"pageArea");?
}?
</script>?
<style type="text/css">?
<!--?
.STYLE1 {color: #FFFFFF}?
-->?
</style>?
</head>?

<body>?
输入JSSP脚本内容:?
<textarea id="pageContent" style="width:100%;" rows="15">?
<table width="100%" border="0" align="center" cellpadding="4" cellspacing="2">?
<tr>?
<td align="center" valign="middle" bgcolor="#666699"><span class="STYLE1">order</span></td>?
<td align="center" valign="middle" bgcolor="#666699"><span class="STYLE1">number1</span></td>?
<td align="center" valign="middle" bgcolor="#666699"><span class="STYLE1">number2</span></td>?
<td align="center" valign="middle" bgcolor="#666699"><span class="STYLE1">number3</span></td>?
</tr>?
<%?
var beginTime=new Date();?
for(var i=0;i<100;i++){?
var color=i%2?"#eeeeee":"#aaaaaa";?
%>?
<tr bgcolor="<%=color%>">?
<td align="center" valign="middle" ><%=i%></td>?
<td align="center" valign="middle" ><%=Math.random()%></td>?
<td align="center" valign="middle" ><%=Math.random()%></td>?
<td align="center" valign="middle" ><%=Math.random()%></td>?
</tr>?
<%}%>?
</table>?
<%?
window.alert("耗时:"+(new Date()-beginTime)+"ms");?
%>?
</textarea>?
<button onClick="showPage()">显示内容</button>?
<hr>?
<div id="pageArea"></div>?
</hr>?

</body>?
</html>

1 楼 renjie120 2011-01-17  
没有使用的例子么?这样不容易看出来有什么实际的用途.
  相关解决方案