JS模板引擎 :ArtTemplate
2015-10-29 00:48
645 查看
JS模板引擎 :ArtTemplate
/article/5555781.html上一篇初略的介绍了一下javascript中的模板引擎,有兴趣的可以戳 这里 。
这一篇将带着大家一起做一个简易的模板引擎,
上一篇介绍到:模板引擎其实做的就是两件事。
根据一定的规则,解析我们所定义的模板
根据数据以及模板生成html(其实背后也是用的字符串拼接)
那么,首先,我们要有一个模板,一份数据,以及想生成的结果。
例如:模板:
1 <script id="test" type="text/html"> 2 <p><%=title%></p> 3 <p><%=msg%></p> 4 <ul> 5 <% for (var i = 0; i < list.length; i ++) { %> 6 <li><%= list[i] %></li> 7 <% } %> 8 </ul> 9 </script>
数据:
<script> var data = { title: '基本例子', msg: "这是一个例子", list: ['文艺', '博客', '摄影', '电影', '民谣', '旅行', '吉他'] }; var html = template('test', data); document.getElementById('content').innerHTML = html; </script>
结果:
现在,我们就来实现上面这个例子。
首先,我们需要定义我们的template方法。
var template = function (templateName, data) { return renderFile(templateName, data); }; var renderFile = function (templateName, data) { var render = template.get(templateName); return render(data); };
然后,获取我们缓存的template 的render方法
template.get = function (templateName) { var cache; if (defaults.cache && cacheStore[templateName]) { cache = cacheStore[templateName]; } else if (typeof document === 'object') { // 加载模板并编译 var elem = document.getElementById(templateName); if (elem) { var source = elem.innerHTML; cache = compile(source); if (templateName && defaults.cache) { cacheStore[templateName] = cache; } } } return cache; };
上面的代码,相信大家也都看得懂,主要是对渲染方法进行缓存,以提升效率。接下来是其中最重要的编译方法。
var compile = template.compile = function (source, options) { var options = extend(options, defaults); var render = compiler(source, options); return render; }; var compiler = function (source, options) { var openTag = options.openTag; var closeTag = options.closeTag; var cache = options.cache; //此处开始解析模板,并生成渲染函数 var headerCode = "'use strict';" + "\n" + "var "; var mainCode = "$out='';"; var footerCode = "return new String($out);"; var uniq = {}; //对模板中html代码的处理 var html = function (code) { if (code) { code = "$out+=" + stringify(code) + ";" + "\n"; } return code; }; //对模板中逻辑部分的处理 var logic = function (code) { // 输出语句. 编码: <%=value%> 不编码:<%=#value%> if (code.indexOf('=') === 0) { code = code.replace(/^=[=#]?|[\s;]*$/g, ''); code = "$out+=" + code + ";"; } // 提取模板中的变量名 each(getVariable(code), function (name) { // name 值可能为空,在安卓低版本浏览器下 if (!name || uniq[name]) { return; } var value; // 声明模板变量 value = "$data." + name; headerCode += name + "=" + value + ","; uniq[name] = true; }); return code + "\n"; }; each(source.split(closeTag), function (code) { //此时代码已被截取成两部分,一部分是纯html, //一部分是逻辑代码,即是包含在html<%logic%>html里面的部分 code = code.split(openTag); var htmlStr = code[0]; var logicStr = code[1]; mainCode += html(htmlStr); if (code.length > 1 && logicStr) { mainCode += logic(logicStr); } }); var code = headerCode + mainCode + footerCode; try { var Render = new Function("$data", code); return Render; } catch (e) { e.temp = "function anonymous($data) {" + code + "}"; throw e; } };
这个方法,便是将模板引擎中的内容解析,并生成渲染方法。
生成之后的渲染方法大概是下面这个样子。
View
Code
模板引擎的解析细节:
大家知道,想生成上面的方法,无非就是通过evel 或者Funciton 之类的方法,将一个字符串生成成一个function。
这里采用的是 var Render = new Function("$data", code);来生成渲染方法。其中$data为参数,code为字符串。 Function方法的具体使用可以参考官方文档 点我
那么,我们想要生成这个Render方法,最重要的事便是 拼接 code 了。
拼接code时,headerCode 和 footerCode 是不变的,对任何模板都是一样的。所以重点工作在于中间的mainCode。
这里,mainCode主要分为两部分,一部分是模板中的html部分,一部分是模板中的逻辑部分(也就是包含在<%><%>里面的)
compiler通过分割<%>,将里面的逻辑部分和html部分分离出来,然后再分别处理。
html部分无需特殊处理,只需要拼接进mainCode就可以了。
logic部分,就需要特殊处理了。例如 例子中的title,这个值,我们需要判断是变量还是关键字(for if ..,这个稍后会讲如何提取),
如果是变量,就必须先赋值:var title = $data.title,$data即为渲染方法的参数,也就是用户到时候会传进来的。
然后再直接将title追加到 mainCode中去就可以了。
至于logic部分,如何提取变量主要是通过正则表达式来提取。
View
Code
这里,主要各个正则的用处都写了注释了。
主要做了:
过滤掉系统关键字,
过滤掉数字开头的变量(不合法变量)
由于1,2部,此时可能首尾有逗号,故,去除首尾的逗号
根据一个或多个逗号,分隔成参数数组 如:param1,param2,,param3=> ["param1","param2","param3"]
就这样,渲染方法就拼接完了。
最后,这里只是实现了js模板中简易的功能。后期诸如helper,include,还会在继续讲。
完整源码地址 : https://github.com/chen4342024/andyTemplate
如果有哪一方面讲的有问题。望不吝指教~
最后问个问题,电脑是win10系统,用什么博客编辑器比较好?官方推荐的window live writer 安装不了!!!
一艘船如果没有目标,那无论海面上哪个方向的风,都是逆风! 个人主页: http://chenblog.sinaapp.com/
相关文章推荐
- javascript在html中的加载顺序------为什么window.alert(document.getElementById("time").innerTex)无法弹出对话框
- js中回调函数的运用
- Javascript-history.go()和history.back()的用法和区别
- JSP针对表单重复提交的处理方法
- jsp获取客户端IP地址的方法
- 迷你MVVM框架 avalonjs 入门教程
- Javascript基础之window
- js实现完美兼容各大浏览器的人民币大小写相互转换
- JavaScript操作URL的相关内容集锦
- JS实现网页右侧带动画效果的伸缩窗口代码
- 如何根据百度地图计算出两地之间的驾驶距离(两种语言js和C#)
- JS模拟酷狗音乐播放器收缩折叠关闭效果代码
- 图解JavaScript中的this关键字
- 异步JS框架的作用以及实现方法
- js实现跨域的4种实用方法原理分析
- 几种简单的js语句(延时函数,回车事件)
- javascript事件流
- jsp一些异常总结(转自校内--2008-11-26 20:01 (分类:默认分类))
- Holder.js 使用说明
- js控制div展开和收回