论坛首页 Web前端技术论坛

决定在Lite XML中集成编译客户端模板功能

浏览 6826 次
精华帖 (0) :: 良好帖 (0) :: 新手帖 (0) :: 隐藏帖 (0)
作者 正文
   发表时间:2009-04-01   最后修改:2009-04-07

直接在服务断模板中划出一块做客户端模板

在模板编译过程中,会把<c:client节点下的模板内容编译成js代码。渲染到客户端中可以直接通过js调用,因为不需要在客户端直接解析模板源代码,所以,能达到一个更高的性能。

 

支持的方式大概是这样的:



<html>
    <head>
      <title>模板测试</title>
       <!-- 申明一段客户端模板 -->
       <c:client id="userListTemplate ">
            <h3>用户列表</h3>
            <c:for items="${userList}" var="user">
                 <p>用户名:${user.name}</p>
                 <p>所在公司:${user.company}</p>
                 <hr/>
            </c:for>
       </c:client>

    </head>
<body>
    。。。。。。
    <script>
    function onPageChange(userList){
        E("userList").innerHTML = userListTemplate (userList)
    }
    </script>
</body>
</html>

 

 

 

 

 

 

   发表时间:2009-04-02  
发现很多人一开始就想错了。
<c:client节点是不会到达客户端的,
客户端看到的只是
<script>
function userListTemplate (context){
    //这里是生成的模板源代码
}
</script>
0 请登录后投票
   发表时间:2009-04-06  
呵呵,泼点冷水:

你这个想法和我几年前的想法不谋而合,总体的思路是:通过一层中间层,提供更简便灵活的视图书写方法。
但是现在回头来看,这种思路颇有隔靴搔痒的感觉,因为很难用 Firebug 直接 Debug 我写的代码,我最多能 Debug “你的通过我写的代码而生成的代码” 你的框架就是靴子,我再怎么样,都要隔着靴子去解决我的问题(找我的 Bug)。所以,在开发时,还不如直接写几个真正有用的 jQuery 的插件来的痛快。

但同时,是我也真心期望你的项目能够成功,因为你的成功就意味着你成功的改变了别人的使用习惯,能做到这一点很不简单。我现在设计的框架,基本上都本着“不改变或者尽量不改变用户的使用习惯”为原则的,起码,在这点上,你很用勇气,所以赞一个先,期待你的突破。
0 请登录后投票
   发表时间:2009-04-07   最后修改:2009-04-07
已经在Lite XML1.0Alpha7中实现了。

用法如下:
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:c="http://www.xidea.org/ns/lite/core">
	<head>
		<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
		<title>前后端统一模板实例</title>
		<link href="tablecloth.css" rel="stylesheet" type="text/css" media="screen" />
	</head>
	<body>
		<div id="container">
			<h1>前后端统一模板实例</h1>
			<div id="content">
				<h2>${title}</h2>
				<table cellspacing="0" cellpadding="0">
					<tr>
						<th>姓名</th>
						<th>公司</th>
						<th>年龄</th>
						<th>城市</th>
					</tr>
					<c:for var="item" items="${data}">
						<tr>
							<td>${item.name}</td>
							<td>${item.company}</td>
							<td>${item.age}</td>
							<td>${item.city}</td>
						</tr>
					</c:for>
				</table>
			</div>
			<div>
				<c:for var="item" items="${[1,2,3,4,5,6]}">
					<a href="#" onclick="reset(${item});return false;">${item}</a>
				</c:for>
			</div>
		</div>
		<!-- 这里的内容会编译成JS函数 -->
		<c:client id="userTemplate">
			<!-- 偷懒有道,xpath直接包含前面那段模板片断 -->
			<c:include xpath="//*[@id='content']/*" />
		</c:client>
		<script>/*<![CDATA[*/
		function reset(id){ 
			var content = document.getElementById('content');
			var model = ${JSON.stringify({title:"客户端模板",data:data})}
			//我们对模型做一点简单的修改(当能你也可以XHR从服务断获取数据,或者从客户端数据模型获取)
			model.title +=id;
			for(var i=0;i!=model.data.length;i++){
				var item = model.data[i];
				for(var n in item){
					item[n]+=id;
				}
			}
			content.innerHTML = userTemplate(model);
		}/*]]>*/
		</script>
	</body>
</html>

0 请登录后投票
   发表时间:2009-04-07   最后修改:2009-04-07
zozoh 写道
呵呵,泼点冷水:

你这个想法和我几年前的想法不谋而合,总体的思路是:通过一层中间层,提供更简便灵活的视图书写方法。
但是现在回头来看,这种思路颇有隔靴搔痒的感觉,因为很难用 Firebug 直接 Debug 我写的代码,我最多能 Debug “你的通过我写的代码而生成的代码” 你的框架就是靴子,我再怎么样,都要隔着靴子去解决我的问题(找我的 Bug)。所以,在开发时,还不如直接写几个真正有用的 jQuery 的插件来的痛快。

但同时,是我也真心期望你的项目能够成功,因为你的成功就意味着你成功的改变了别人的使用习惯,能做到这一点很不简单。我现在设计的框架,基本上都本着“不改变或者尽量不改变用户的使用习惯”为原则的,起码,在这点上,你很用勇气,所以赞一个先,期待你的突破。


太晚了,明天再来答复你的疑问吧,先概括一下:
你的担心不是没有道理,但是根据以往经验。我们没有碰到,也许基于Lite的实现就很难碰到。
0 请登录后投票
   发表时间:2009-04-07   最后修改:2009-04-07
zozoh 写道
呵呵,泼点冷水:

你这个想法和我几年前的想法不谋而合,总体的思路是:通过一层中间层,提供更简便灵活的视图书写方法。
但是现在回头来看,这种思路颇有隔靴搔痒的感觉,因为很难用 Firebug 直接 Debug 我写的代码,我最多能 Debug “你的通过我写的代码而生成的代码” 你的框架就是靴子,我再怎么样,都要隔着靴子去解决我的问题(找我的 Bug)。所以,在开发时,还不如直接写几个真正有用的 jQuery 的插件来的痛快。

但同时,是我也真心期望你的项目能够成功,因为你的成功就意味着你成功的改变了别人的使用习惯,能做到这一点很不简单。我现在设计的框架,基本上都本着“不改变或者尽量不改变用户的使用习惯”为原则的,起码,在这点上,你很用勇气,所以赞一个先,期待你的突破。



回来解释一下这些疑问吧。


[list]
 
  • 语法错误让编译器解决。
  •   如果你模板中表达式本身有错,那么,你的编译器就会报告给你。
     
  • 不应该有太多调试的需求
  •   保持模板简单的原则,如果你的模板需要调试,那我可以认为你的模板设计的不好。
      半年前,那就那着LiteXML的早期版本做开发。压根就没有遇到调试需求。
      设计这个模板的时候,有一个目标,那就是尽量不需要文档。
      我们在开发过程中,没有做过任何相关培训,只有极少的关于语法的私下询问(貌似只有一次,当能,这也说明我们团队成员的水平还是非常不错的^_^)
     
  • 就算有调试需求,那就打开Firebug去Debug
  •   模板处理的逻辑是简单的,生成的代码结构也就是简单的。
      可以看一下对比:模板源代码
        <!-- 这里的内容会编译成JS函数(函数名userTemplate) -->
        <c:client id="userTemplate">
          <h1>前后端统一模板实例</h1>
          <div id="content">
            <h2>${title}</h2>
            <table cellspacing="0" cellpadding="0">
              <tr>
                <th>姓名</th>
                <th>公司</th>
                <th>年龄</th>
                <th>城市</th>
              </tr>
              <c:for var="item" items="${data}">
                <tr>
                  <td>${item.name}</td>
                  <td>${item.company}</td>
                  <td>${item.age}</td>
                  <td>${item.city}</td>
                </tr>
              </c:for>
            </table>
          </div>
        </c:client>
    

    这是自动生成的JS代码
    <script>/*<![CDATA[*/function userTemplate(_$0,_$1,_$2){
    	_$1={};
    	for(_$2 in _$0){_$1[_$2]=_$0[_$2]};
    	_$0=_$1,_$1=[];
    	_$2=function(c){return "&#"+c.charCodeAt()+";";}
    	with(_$0){
    		_$1.push("\t\t<h2>");
    		_$1.push(String(title).replace(/[<>&]/g,_$2));
    		_$1.push("</h2><table cellpadding=\"0\" cellspacing=\"0\">\t<tr>\t<th>姓名</th>\t<th>公司</th>\t<th>年龄</th>\t<th>城市</th>\t</tr>\t");
    		
    		var _$3=data;
    		var _$2=0;
    		if(typeof _$3 == 'number'){
    			_$3= new Array(_$3);
    		}else if(!(_$3 instanceof Array)){
    			var _$4= [];
    			for(item in _$3){
    				_$4.push({key:item,value:_$3[item]});
    			}
    			_$3=_$4;
    		}
    		for(;_$2<_$3.length;_$2++){
    			var item=_$3[_$2];
    			_$1.push("\t<tr>\t<td>");
    			_$1.push(String(item.name).replace(/[<>&]/g,_$2));
    			_$1.push("</td>\t<td>");
    			_$1.push(String(item.company).replace(/[<>&]/g,_$2));
    			_$1.push("</td>\t<td>");
    			_$1.push(String(item.age).replace(/[<>&]/g,_$2));
    			_$1.push("</td>\t<td>");
    			_$1.push(String(item.city).replace(/[<>&]/g,_$2));
    			_$1.push("</td>\t</tr>\t");
    		}
    		_$1.push("\t</table>\t");
    	}
    	return _$1.join('');
    }/*]]>*/</script>
    

    [/list]
    0 请登录后投票
       发表时间:2009-04-07  
    zozoh 写道
    呵呵,泼点冷水:

    你这个想法和我几年前的想法不谋而合,总体的思路是:通过一层中间层,提供更简便灵活的视图书写方法。
    但是现在回头来看,这种思路颇有隔靴搔痒的感觉,因为很难用 Firebug 直接 Debug 我写的代码,我最多能 Debug “你的通过我写的代码而生成的代码” 你的框架就是靴子,我再怎么样,都要隔着靴子去解决我的问题(找我的 Bug)。所以,在开发时,还不如直接写几个真正有用的 jQuery 的插件来的痛快。

    但同时,是我也真心期望你的项目能够成功,因为你的成功就意味着你成功的改变了别人的使用习惯,能做到这一点很不简单。我现在设计的框架,基本上都本着“不改变或者尽量不改变用户的使用习惯”为原则的,起码,在这点上,你很用勇气,所以赞一个先,期待你的突破。



    回来解释一下这些疑问吧。


    [list]
     
  • 语法错误让编译器解决。
  •   如果你模板中表达式本身有错,那么,你的编译器就会报告给你。
     
  • 不应该有太多调试的需求
  •   保持模板简单的原则,如果你的模板需要调试,那我可以认为你的模板设计的不好。
      半年前,那就那着LiteXML的早期版本做开发。压根就没有遇到调试需求。
      设计这个模板的时候,有一个目标,那就是尽量不需要文档。
      我们在开发过程中,没有做过任何相关培训,只有极少的关于语法的私下询问(貌似只有一次,当能,这也说明我们团队成员的水平还是非常不错的^_^)
     
  • 就算有调试需求,那就打开Firebug去Debug
  •   模板处理的逻辑是简单的,生成的代码结构也就是简单的。
      可以看一下对比:模板源代码
        <!-- 这里的内容会编译成JS函数(函数名userTemplate) -->
        <c:client id="userTemplate">
          <h1>前后端统一模板实例</h1>
          <div id="content">
            <h2>${title}</h2>
            <table cellspacing="0" cellpadding="0">
              <tr>
                <th>姓名</th>
                <th>公司</th>
                <th>年龄</th>
                <th>城市</th>
              </tr>
              <c:for var="item" items="${data}">
                <tr>
                  <td>${item.name}</td>
                  <td>${item.company}</td>
                  <td>${item.age}</td>
                  <td>${item.city}</td>
                </tr>
              </c:for>
            </table>
          </div>
        </c:client>
    

    这是自动生成的JS代码
    <script>/*<![CDATA[*/function userTemplate(_$0,_$1,_$2){
    	_$1={};
    	for(_$2 in _$0){_$1[_$2]=_$0[_$2]};
    	_$0=_$1,_$1=[];
    	_$2=function(c){return "&#"+c.charCodeAt()+";";}
    	with(_$0){
    		_$1.push("\t\t<h2>");
    		_$1.push(String(title).replace(/[<>&]/g,_$2));
    		_$1.push("</h2><table cellpadding=\"0\" cellspacing=\"0\">\t<tr>\t<th>姓名</th>\t<th>公司</th>\t<th>年龄</th>\t<th>城市</th>\t</tr>\t");
    		
    		var _$3=data;
    		var _$2=0;
    		if(typeof _$3 == 'number'){
    			_$3= new Array(_$3);
    		}else if(!(_$3 instanceof Array)){
    			var _$4= [];
    			for(item in _$3){
    				_$4.push({key:item,value:_$3[item]});
    			}
    			_$3=_$4;
    		}
    		for(;_$2<_$3.length;_$2++){
    			var item=_$3[_$2];
    			_$1.push("\t<tr>\t<td>");
    			_$1.push(String(item.name).replace(/[<>&]/g,_$2));
    			_$1.push("</td>\t<td>");
    			_$1.push(String(item.company).replace(/[<>&]/g,_$2));
    			_$1.push("</td>\t<td>");
    			_$1.push(String(item.age).replace(/[<>&]/g,_$2));
    			_$1.push("</td>\t<td>");
    			_$1.push(String(item.city).replace(/[<>&]/g,_$2));
    			_$1.push("</td>\t</tr>\t");
    		}
    		_$1.push("\t</table>\t");
    	}
    	return _$1.join('');
    }/*]]>*/</script>
    
    

     
  • “不改变或者尽量不改变用户的使用习惯”
  •   这一点确实很明智!!
    [/list]



    0 请登录后投票
       发表时间:2009-04-08  
    原来是这样啊,呵呵。 看来我理解错了,你说的没错,这里基本不包括复杂的逻辑,当然不太会出错。

    如果 <c:client> 的就是把自己的 body 那些内容变成一个字符串返回的话,你为啥每次都拼接呢? 为啥不在 document onload 的时候放在一个全局的 object 里面,key 就是你的 client id, values 就是这段 innerHTML。 如果这个全局变量叫做 window.$patterns  我在使用的时候,直接调用 window.$patterns[modleId]
    就能取得我要的 innerHTML,这样我在使用的时候,会更方便吧?
    0 请登录后投票
       发表时间:2009-04-08  
    zozoh 写道
    原来是这样啊,呵呵。 看来我理解错了,你说的没错,这里基本不包括复杂的逻辑,当然不太会出错。

    如果 <c:client> 的就是把自己的 body 那些内容变成一个字符串返回的话,你为啥每次都拼接呢? 为啥不在 document onload 的时候放在一个全局的 object 里面,key 就是你的 client id, values 就是这段 innerHTML。 如果这个全局变量叫做 window.$patterns  我在使用的时候,直接调用 window.$patterns[modleId]
    就能取得我要的 innerHTML,这样我在使用的时候,会更方便吧?


    呵呵,这个建议太技术人员了吧^_^。用户体验不要求性能的极限,只是要求性能问题不要让用户体验到。
    在这种要求下,微乎其微的可能的性能提升远没有保持代码的简单优雅重要。
    0 请登录后投票
       发表时间:2009-04-09  
    恩,这个不是关键,但是这个解决方案只能跑在 JSP 容器, 如果你用纯 JS 来作会不会更好。
    因为你这个框架要作的事情就是替别人来缓存一组 HTML 字符串,一个不超过 50 行的 JS 文件就能全部搞定,而根本不用任何服务器端的代码才对。
    0 请登录后投票
    论坛首页 Web前端技术版

    跳转论坛:
    Global site tag (gtag.js) - Google Analytics