JScript 快速开发框架 Edk:模板

简介: 网页模板是把动态的数据和静态的表现组装到一起的工具,使得内容与表现方式可以分离,是 Web 开发中的重要技术手段。早期的 Web 开发很简单,还没“模板 ”的概念。只需把数据提取出来,放在 HTML 里面显示就达到程序的目的。

网页模板是把动态的数据和静态的表现组装到一起的工具,使得内容与表现方式可以分离,是 Web 开发中的重要技术手段。早期的 Web 开发很简单,还没“模板 ”的概念。只需把数据提取出来,放在 HTML 里面显示就达到程序的目的。HTML代码混合于逻辑代码之中,HTML 就是直接显示的内容,内嵌在 HMTL 中<% ... %>表示为后台(服务端)执行代码,但很多情况<% ... %>中又有 HTML 的片段,至于怎么拼凑出 HTML 片段的方式方法各式各样、与多种的后台语言掺杂一起( ASP、PHP、JSP )各显神通。

$$.tpl = {
	fillData : function(tpl, data){
		// 匹配闭合tag的正则。
		var divBlock = '<{0}\\s*[^>]*>((?:(?=([^<]+))\\2|<(?!{0}\\s*[^>]*>))*?)<\/({0})>';
		var matchValue = (function(){
			var
			 regexp    = /{([^}\n]*)}/ig
			,execJS	   = /^\[([^\]]*)\]$/
			,getParent = /^parent\.\b(\w*)\b$/i
			,getRoot   = /^root\.\b(\w*)\b$/i;
		
		/**
		 * @private
		 * @param {mixed} v
		 * @return {Boolean} 是否hash(是否对象)。
		 */
		function isObject(v){
			return !!v && isObject.toString.call(v) == isObject.token;
		}
		isObject.toString = Object.prototype.toString
		isObject.token    = '[object Object]';
		
		/**
		 * 替换置,如果未发现匹配的值,返回什么?一般原模版的格式({xxx}),即m1。
		 * 注意那些无意义的值除外。
		 */
		function falsey(value, tpl){
			switch(value){
				case false:
				return 'false';
				case '':
				return value;
				case 0:
				return value;
			}
			
			return !!value ? value : tpl;
		}
		
	 	function replace(m1, m2){
			var 
			 jsCode
			,parent  = arguments.callee.parent 
			,root	 = arguments.callee.root;
				
			if(execJS.test(m2)){
				execJS.lastIndex = 0;
				jsCode = execJS.exec(m2);
				jsCode = jsCode[1];
				
				try{ // 写try之目的为容错性的设计。
					with(this){
						jsCode = eval(jsCode);
					}
					return jsCode;
				}catch(e){
					return '空值';
				}
			}
			
			if(isObject(parent) && getParent.test(m2)){ /* 父级寻址 */
				getParent.lastIndex = 0;
				m2 = m2.match(getParent);
				m2 = m2[1];
				return falsey(parent[m2], m1);
			}else if(isObject(root) && getRoot.test(m2)){ /* 全称寻址 */
				getRoot.lastIndex = 0;
				m2 = m2.match(getRoot);
				m2 = m2[1];
				return falsey(root[m2], m1);
			}else{
				return falsey(this[m2], m1);
			}
		}
		
		 /**
		  * Lazy function
		  * @param {String} tpl
		  * @param {Object} dataObj
		  * @param {Object} parentObj
		  * @return {String}
		  */
		return function(tpl, dataObj, parentObj){
			if(!replace.root){
				replace.root = $$.tpl.root;
			}
			
			replace.parent = parentObj || 'itself'; // 无else部分,即表示全部就是trueBlock
			replace.scope  = dataObj;
			return tpl.replace(regexp, replace.delegate());// set scope object!
		}
		})();
		
		var matchIf = (function(){
			var 
			 elseReg = /<else\s*\/?>/i
			,evalReg = /<if\s*(?:eval="([\w\d=<>\.!'\|\(\)]*)")[^>]*>/i
			,tabReg  = /\t{2}/g
			,ifReg   = new RegExp(divBlock.format('if'), 'ig');
		
		/**
		 * 运算<if eval="exp">内容。
		 * @param {Object} data
		 * @param {Object} parent
		 * @param {String} ifTag
		 * @return {Boolean}
		 */
		function evalExp(data, parent, ifTag){
			var exp;
			
			evalReg.lastIndex = 0;
			if(!evalReg.test(ifTag)){
				$$.console.error('输入的标签{0}不是一个标准的if tag'.format(ifTag));
				throw '不是一个标准的if tag';
			}
			evalReg.lastIndex = 0;
			exp = evalReg.exec(ifTag);
			exp = exp[1];
			exp = '(' + exp +')'; // make it as the Expression 表达式
	//		debugger;
			// 通过with(data){}给定对象可见的范围。如果没有matchedObj,则为this。这也是有可能的。
			with(data || parent || this){
				try{
					exp = !!eval(exp);
				}catch(e){
					exp = false;
				}
			}
			return exp;
		}
		
		/**
		 * @this {OBject} 值对象
		 */
		function replace(m1, m2){
			var 
			 evalResult 		// 运算表达式后的结果
			,trueBlock			// true块
			,falseBlock = null	// false块,默认没有
			
			elseReg.lastIndex = 0;
			
			if(elseReg.test(m2)){// 有else部分
				var arr = m2.split(elseReg);
				if(!arr || arr.length < 2){
					$$.console.error('if-else不完整');
					throw "if-else不完整";
				};
				 
				trueBlock  = arr[0];
				falseBlock = arr[1];
			}else{
				trueBlock  = m2; // 无else部分,即表示全部就是trueBlock
			}
			
			trueBlock  = $$.trim(trueBlock);
			trueBlock  = trueBlock.replace(tabReg, '\t');// 消除多余tab符。
			// 求 if 的表达式
			evalResult = evalExp(this, arguments.callee.parent, m1);
			
			if(evalResult){
				return trueBlock;
			}else if(!evalResult && falseBlock == null){
				return '';
			}else if(!evalResult && falseBlock){
				return falseBlock;
			}else{
				// 不应该会走到这里的。若真的走到便抛出一个异常。
				$$.console.error('求if-else块时发生致命错误!');
				throw '求if-else块时发生致命错误!';							
			}
		}
		
			return function(tpl, data, parentData){
				ifReg.lastIndex = 0;// 有global时需要注意 lastIndex的问题。
				
				if(ifReg.test(tpl)){
					replace.parent = parentData;
					replace.scope  = data;
					return tpl.replace(ifReg, replace.delegate());
				}else{
					return tpl;
				}
			}
		})();
	
		function replace(m1, m2, m3, m4){
			var 
		     parentData = this
			,values		= parentData[m4]
			,callee		= $$.tpl.fillData
	    	,str 		= ''
			,arrTpl;
		    
		    if(values && !values.pop){
		    	return callee(m2, values);			// 递归 for sub
		    }else if(values && values.pop){/* 有时候会因为大小写问题,无法匹配。请检查key即(m4)是否一致 */
		        m2 = callee(m2, values);			// 递归 for sub
	        		
				for(var i = 0, j = values.length; i < j; i++){
					value  = values[i];
					m2	   = matchIf(m2, value, parentData); 
					arrTpl = callee(m2, value);
					
					str += matchValue(arrTpl, value, parentData);
				} 
				return str;
				
		    }else if(values == false /* 特定为false的情况 */ ){
		    	return str;
		    }else{
		    	$$.console.warn('No data provided');// 怎么数据源没提供数据? 宜debug之
		    	return 'edkTpl_nothing';
		    }
		}
		
		/**
		 * @param  {String} tpl
		 * @param  {Object} data
		 * @return {String}
		 */
		$$.tpl.fillData = function (tpl, data){
			if(!$$.tpl.root){
				$$.tpl.root = data;
			}
	
		    if(data && !data.pop){
		    	replace.scope = data;
		    	var _replace = replace.delegate();
		    	
		    	for(var i in data){
					tpl = tpl.replace(new RegExp(divBlock.format(i), 'i'), _replace);
		    	}
		    	
		    	tpl = matchIf(tpl, data, data); 
		    	
			    return matchValue(tpl, data);
		    }else if(data && data.pop){
		    	return tpl;
		    }else if(!data){
//	    		throw '没有输入数据的参数 data?';
		    }
		    return '';
		}
		
		return $$.tpl.fillData(tpl, data);
	}

};
这是我第一次写的模板,纯练手,因此非常粗糙。


目录
相关文章
|
JavaScript 前端开发 Linux
.Net开发的跨平台Word模板引擎
项目采用类似Vue、React模板方式,在模板定义相应的变量,再结合数据,快速生成Word文件。比如模板定义{FullName{}},项目会自动匹配键值为FullName的对象,并替换。
228 0
.Net开发的跨平台Word模板引擎
|
JavaScript 前端开发 Java
Web阶段:第三章:JavaScript语言(上)
Web阶段:第三章:JavaScript语言
|
JavaScript 前端开发
Web阶段:第三章:JavaScript语言(下)
Web阶段:第三章:JavaScript语言
|
存储 设计模式 JavaScript
【译】设计一个JavaScript插件系统
【译】设计一个JavaScript插件系统
135 0
【译】设计一个JavaScript插件系统
symfony框架Twig模板语言的使用
symfony框架Twig模板语言的使用
116 0
symfony框架Twig模板语言的使用
|
Web App开发 移动开发 JavaScript
向 Web 开发人员推荐35款 JavaScript 图形图表库
  图表是数据图形化的表示,通过形象的图表来展示数据,比如条形图,折线图,饼图等等。可视化图表可以帮助开发者更容易理解复杂的数据,提高生产的效率和 Web 应用和项目的可靠性。   在这篇文章中,我们收集了35款值得网站开发者收藏的 JavaScript 图形图表库,适合各种图表需求。
1686 0
|
设计模式 XML 资源调度
为什么 Web 开发人员需要学习一个 JavaScript 框架?
为什么 Web 开发人员需要学习一个 JavaScript 框架?
|
JSON 前端开发 JavaScript
怎样在不使用框架的基础上开发一个 Javascript 组件
本文讲的是怎样在不使用框架的基础上开发一个 Javascript 组件,许多开发者(包括我)犯的一个错误是当遇到问题时他们总是自上而下地考虑问题。
1149 0
|
JavaScript 前端开发 API

相关实验场景

更多