欢迎使用CSDN-markdown编辑器
来源:互联网 发布:挠脚心知不及格代价上 编辑:程序博客网 时间:2024/05/17 09:39
/*
*underscore.js的模板方法分析
*by tzw 2015/8/3
*/
var entityMap = { //用于html转义,/<%([\s\S]+?)%>/g 该模式下使用 escape: { '&': '&', '<': '<', '>': '>', '"': '"', "'": ''', '/': '/' }};//匹配的三种模式_.templateSettings = { evaluate: /<%([\s\S]+?)%>/g, interpolate: /<%=([\s\S]+?)%>/g, escape: /<%-([\s\S]+?)%>/g};var nativeKeys = Object.keys; //返回该对象的所有可枚举自身属性的属性名组成的字符串数组["",""]_.keys = nativeKeys || function(obj) { //keys方法实现 if (obj !== Object(obj)) throw new TypeError('Invalid object'); var keys = []; for (var key in obj) if (_.has(obj, key)) keys[keys.length] = key; // 直接用length做为下标,挺好 return keys;};// Regexes containing the keys and values listed immediately above.var entityRegexes = { escape: new RegExp('[' + _.keys(entityMap.escape).join('') + ']', 'g'), unescape: new RegExp('(' + _.keys(entityMap.unescape).join('|') + ')', 'g')};// Functions for escaping and unescaping strings to/from HTML interpolation._.each(['escape', 'unescape'], function(method) { _[method] = function(string) { if (string == null) return ''; return ('' + string).replace(entityRegexes[method], function(match) { return entityMap[method][match]; //转义 }); };});//即生成的_.escape为(这个不是源码的)_.escape = function(string){ if(string == null) return ''; return ('' + string).replace(/[&<>"'\/]/g, function(match) { return entityMap['escape'][match]; });}var escapes = { "'": "'", '\\': '\\', '\r': 'r', '\n': 'n', '\t': 't', '\u2028': 'u2028', '\u2029': 'u2029'};var escaper = /\\|'|\r|\n|\t|\u2028|\u2029/g;//template代码_.template = function(text, data, settings) { var render; settings = _.defaults({}, settings, _.templateSettings); // Combine delimiters into one regular expression via alternation. var matcher = new RegExp([ (settings.escape || noMatch).source, (settings.interpolate || noMatch).source, (settings.evaluate || noMatch).source ].join('|') + '|$', 'g'); //生成后变为 /<%-([\s\S]+?)%>|<%=([\s\S]+?)%>|<%([\s\S]+?)%>|$/g,即三种模式,<%-转义,<%=赋值,<% js // Compile the template source, escaping string literals appropriately. var index = 0; var source = "__p+='"; //replace的function处理 // function函数具有几个参数: // 第一个参数为每次匹配的文本 // 中间参数为子表达式匹配字符串,个数不限,也就是括号中的东西 // 倒数第二个参数为匹配文本字符串的匹配下标位置 // 最后一个参数表示字符串本身 text.replace(matcher, function(match, escape, interpolate, evaluate, offset) { source += text.slice(index, offset) // 根据匹配到的位置,取出不做匹配的代码段 .replace(escaper, function(match) { //做转义 return '\\' + escapes[match]; }); //以下三个if 分别是对匹配到的字符串做转义 if (escape) { source += "'+\n((__t=(" + escape + "))==null?'':_.escape(__t))+\n'"; } if (interpolate) { source += "'+\n((__t=(" + interpolate + "))==null?'':__t)+\n'"; } if (evaluate) { source += "';\n" + evaluate + "\n__p+='"; } index = offset + match.length; //将新index位置后移到match之后 return match; }); source += "';\n"; // If a variable is not specified, place data values in local scope. if (!settings.variable) source = 'with(obj||{}){\n' + source + '}\n'; source = "var __t,__p='',__j=Array.prototype.join," + "print=function(){__p+=__j.call(arguments,'');};\n" + source + "return __p;\n"; try { render = new Function(settings.variable || 'obj', '_', source); } catch (e) { e.source = source; throw e; } if (data) return render(data, _); //如果初期已经传递了data数据,则直接调用render方法生成html var template = function(data) { return render.call(this, data, _); }; // Provide the compiled function source as a convenience for precompilation. template.source = 'function(' + (settings.variable || 'obj') + '){\n' + source + '}'; return template; // 没有传递data数据,则先调用template生成render,然后在传递data生成html};//解析过程(以下面这个模板为例)<ul id="type_id"> <% for (var i = 0, len = data.length; i < len; i++) { %> <li class="type js_type"> <h2><%=data[i].name%></h2> <ul class="product_list"> <% for (var j = 0, len1 = data[i].product.length; j < len1; j++) { %> <li class="product"> <%=data[i].product[j].name%> </li> <% } %> </ul> </li> <% } %></ul>步骤1. <% for (var i = 0, len = data.length; i < len; i++) { %>source = "__p+='<ul id="type_id">\n '; for (var i = 0, len = data.length; i < len; i++) { __p+='"步骤2. <%=data[i].name%>source="__p+='<ul id="type_id">\n '; for (var i = 0, len = data.length; i < len; i++) { __p+='\n <li class="type js_type">\n <h2>'+((__t=(data[i].name))==null?'':__t)+'"步骤3. 模板解析完后source= "__p+='<ul id="type_id">\n '; for (var i = 0, len = data.length; i < len; i++) { __p+='\n <li class="type js_type">\n <h2>'+((__t=(data[i].name))==null?'':__t)+'</h2>\n <ul class="product_list">\n '; for (var j = 0, len1 = data[i].product.length; j < len1; j++) { __p+='\n <li class="product">\n '+((__t=(data[i].product[j].name))==null?'':__t)+'\n </li>\n '; } __p+='\n </ul>\n </li>\n '; } __p+='\n</ul>';"步骤4. 追加with,生成作用于,也可以不适用with,with有性能问题"with(obj||{}){__p+='<ul id="type_id">\n '; for (var i = 0, len = data.length; i < len; i++) { __p+='\n <li class="type js_type">\n <h2>'+((__t=(data[i].name))==null?'':__t)+'</h2>\n <ul class="product_list">\n '; for (var j = 0, len1 = data[i].product.length; j < len1; j++) { __p+='\n <li class="product">\n '+((__t=(data[i].product[j].name))==null?'':__t)+'\n </li>\n '; } __p+='\n </ul>\n </li>\n '; } __p+='\n</ul>';}"5. 组装source,追加_t,_p等变量定义"var __t,__p='',__j=Array.prototype.join,print=function(){__p+=__j.call(arguments,'');};with(obj||{}){__p+='<ul id="type_id">\n '; for (var i = 0, len = data.length; i < len; i++) { __p+='\n <li class="type js_type">\n <h2>'+((__t=(data[i].name))==null?'':__t)+'</h2>\n <ul class="product_list">\n '; for (var j = 0, len1 = data[i].product.length; j < len1; j++) { __p+='\n <li class="product">\n '+((__t=(data[i].product[j].name))==null?'':__t)+'\n </li>\n '; } __p+='\n </ul>\n </li>\n '; } __p+='\n</ul>';}return __p;"6. new Function 来生成一个匿名函数给renderrender = new Function(settings.variable || 'obj', '_', source); //最后一个是函数内容,之前的为参数render:function (obj, _) { var __t, __p = '', __j = Array.prototype.join, print = function() { __p += __j.call(arguments, ''); }; with(obj || {}) { __p += '<ul id="type_id">\n '; for (var i = 0, len = data.length; i < len; i++) { __p += '\n <li class="type js_type">\n <h2>' + ((__t = (data[i].name)) == null ? '' : __t) + '</h2>\n <ul class="product_list">\n '; for (var j = 0, len1 = data[i].product.length; j < len1; j++) { __p += '\n <li class="product">\n ' + ((__t = (data[i].product[j].name)) == null ? '' : __t) + '\n </li>\n '; } __p += '\n </ul>\n </li>\n '; } __p += '\n</ul>'; } return __p;}
0 0
- 欢迎使用CSDN-markdown编辑器
- 欢迎使用CSDN-markdown编辑器
- 欢迎使用CSDN-markdown编辑器
- 欢迎使用CSDN-markdown编辑器
- 欢迎使用CSDN-markdown编辑器
- 欢迎使用CSDN-markdown编辑器
- 欢迎使用CSDN-markdown编辑器
- 欢迎使用CSDN-markdown编辑器
- 欢迎使用CSDN-markdown编辑器
- 欢迎使用CSDN-markdown编辑器
- 欢迎使用CSDN-markdown编辑器
- 欢迎使用CSDN-markdown编辑器
- 欢迎使用CSDN-markdown编辑器
- 欢迎使用CSDN-markdown编辑器
- 欢迎使用CSDN-markdown编辑器
- 欢迎使用CSDN-markdown编辑器
- 欢迎使用CSDN-markdown编辑器
- 欢迎使用CSDN-markdown编辑器
- Android环境搭建
- UIRefreshControl 实现UITableView的下拉刷新
- HDU 1234:开门人和关门人【排序】
- Salesmen
- 数组分割问题-详细版
- 欢迎使用CSDN-markdown编辑器
- Linux进程间通信——使用消息队列
- 最大子序列和的问题
- 如何实现 MySQL 查询结合多个的 count () 和 GROUP BY
- Linux进程间通信——使用命名管道
- vim的基本使用方法
- 拓扑排序 SRM 660 Div2 Medium: PrivateD2party
- hihoCoder 1109 最小生成树三·堆优化的Prim算法
- java类与对象