第9天response 响应渲染 —动态渲染插件开发
动态渲染插件开发
下面列出view插件源代码,然后对其进行讲解。
lib/view.js
源代码
var fs = require("fs"), path = require("path"); // 过滤 \r\n function filterRN(s){ s = s.replace("\'","\""); s = s.replace(/\n/g,"\\n"); s = s.replace(/\r/g,"\\r"); return "result += \'"+s+"\';\n\r"; } module.exports = function(viewPath){ var viewCache = {} fs.readdir(viewPath, function(err,files){ files.forEach(function(fn){ var filePath = path.join(viewPath,fn); fs.readFile(filePath,function(err,data){ var str = data.toString(); var buf = []; buf.push('var result = "";') var htmlPart= ""; for(var i=0,len = str.length;i<len;){ if(str.slice(i,i+2) === "<%"){ var end = str.indexOf("%>",i); var jsPart = str.slice(i+2,end); i = end+2; buf.push(filterRN(htmlPart)); htmlPart = ""; if(jsPart.slice(0,1) === "="){ buf.push("\r\nresult += "+jsPart.slice(1)+";\r\n") }else{ buf.push("\r\n"+jsPart+"\r\n"); } }else{ htmlPart += str.slice(i,i+1); i += 1; } } buf.push(filterRN(htmlPart)); buf.push("return result;") viewCache[fn] = new Function("locals",buf.join("")); }); }) }) return function(req,res,next){ res.view = function(fileName,locals){ res.write(viewCache[fileName](locals)); res.end(); } next(); } }
这个插件的原理,上节分析过了,下面对细节进行讲解。插件用到了核心库的两个模块 fs
和path
,fs都很熟悉了,path.join
方法是把字符串连接为一个完整目录的方法,可以参考附录。viewCache用来储存模板页面Function形式的。插件在调用app.use(view(viewPath))时,会读取这个目录下的全部文件,然后转换为javascript Function对象,保存到viewCache之中。
转换一个模板文件的方法是从头读取,当遇到<%
时会通过indexOf找到配对的%>
,然后抽离出中间的javascript代码,保存到buf中。而启动它部分都转换为字符串对象result += ......
,接着添加return result;
字符串。而这些字符串储存在 var buf = [];
中,在最后通过 buf.join("')把这些字符串数组合并为一个字符串,就构成了view函数体,最后通过viewCache[fn] = new Function("locals",buf.join(""));
转换为javascript Function对象保存到viewCache中。
filterRN函数是用来过滤 \n\r 并且把它们转换为 \\n \\r 形式,目的是保证函数体能正确执行。因为如果不过滤,就会出现以下的函数体:
result += " abc "
这是错误的,javascript不支持这种写法,所以通过转换后就会得到如下形式:
result += "\r\n abc \r\n";
代码不是太复杂,仔细分析后就能理解。重要的是自己要动手去开发,想一想如果模板文件不是<%%>这种形式,换成其他的写法应该如何做这个插件,比如模板文件是缩进写法等等。当然转换后的形式应该都是javascript Function对象形式。
最后,我们在index.js
文件中加入以下代码,view插件就算告一段落了。
exports.view = require("./lib/view");
下一节,将用一个实例进行说明。
相关文章
- nodeJs基础教程系列(9)——CO库
- nodeJs基础教程系列(4)——CommonJS规范
- nodeJs基础教程系列(7)——generator
- [转]让你的 Node.js 应用跑得更快的 10 个技巧
- Node.js API实例——Node.js 控制台
- Node.js 入门
- nodeJs基础教程系列(3)——建立githubs项目
- nodeJs基础教程系列(1)——安装Node.js
- nodeJs基础教程系列(6)——Promise 模式的Q库
- Atom 更为先进的文本代码编辑器 - 由 Github 打造的下一代编程开发利器
- bootstrap 3.3 模态框垂直居中问题
- js字符串操作