对于另外一个让我们学习的地方,那就是使用占位符插入我们所要的信息,一般我们都会使用正则,本插件也提供了一种不错的思路。先使用占位符,然后通过split(占位符)来分隔字符串,最后使用join(信息)来再次拼接字符串。这两个方法都是原生的,效率的话,我不太确定,应该还不错,有兴趣的朋友可以写写正则,在不同浏览器下比比看,谁的效率更高一点。
既然它生成了一个匿名函数,我们可以简单地打印一下看看:
function anonymous(jQuery, $item) { var $=jQuery,call,__=[],$data=$item.data; with($data){__.push('<tr> <td>'); if(typeof(ID)!=='undefined' && (ID)!=null){ __.push($.encode((typeof(ID)==='function'?(ID).call($item):(ID)))); } __.push('</td> <td>'); if(typeof(Name)!=='undefined' && (Name)!=null){ __.push($.encode((typeof(Name)==='function'?(Name).call($item):(Name)))); } __.push('</td> </tr>');}return __; }
这里with有延长作用域的作用,在一般的开发中,不建议使用,不太易于维护,那这个with括号里的ID,Name其实都是$data.ID和$data.Name,在没有调用这个匿名函数之前,我们先简单看一下,传入的$item参数拥有data属性,如果这个data的ID和Name不是函数的话就正常显示,如果是函数的话,则这些方法需要通过$item来调用。另外匿名函数中也拥有了这钱我们所写的模版结构,后续的工作就是用真实的数据去替换占位符,前提非空。ok,回到jQuery的tmpl方法中,我们再看一个比较重要的部分。
ret = jQuery.isArray( data ) ? jQuery.map( data, function( dataItem ) { return dataItem ? newTmplItem( options, parentItem, tmpl, dataItem ) : null; }) : [ newTmplItem( options, parentItem, tmpl, data ) ];
data是用户传入的信息元,就是users,是一个数组,调用jQuery.map来进行遍历,来调用newTmplItem方法,其中tmpl则是刚才我们生成的匿名函数。
function newTmplItem( options, parentItem, fn, data ) { newItem = { data: data || (data === 0 || data === false) ? data : (parentItem ? parentItem.data : {}), _wrap: parentItem ? parentItem._wrap : null, tmpl: null, parent: parentItem || null, nodes: [], calls: tiCalls, nest: tiNest, wrap: tiWrap, html: tiHtml, update: tiUpdate }; if ( options ) { jQuery.extend( newItem, options, { nodes: [], parent: parentItem }); } if ( fn ) { // Build the hierarchical content to be used during insertion into DOM newItem.tmpl = fn; newItem._ctnt = newItem._ctnt || newItem.tmpl( jQuery, newItem ); newItem.key = ++itemKey;(stack.length ? wrappedItems : newTmplItems)[itemKey] = newItem;//这里考虑一个页面可能多处使用模版,这里进行的编号,封装。 } return newItem;//最后返回这个newItem对象 }
如果看到newItem的定义方式,或许之前我们对匿名函数的猜测有了一些佐证,没错,最后通过newItem.tmpl(jQuery,newItem)来调用了这个匿名函数,这个方法除了调用执行了匿名函数,还简单的封装了一下,便于以后我们调用$.tmplItem来获取相应的数据元信息。
将生成好的ret传入最后一个加工方法build,完成整个模版的赋值
build( tmplItem, nested, content ) { frag, ret = content ? jQuery.map( content, function( item ) { (typeof item === "string") ? // Insert template item annotations, to be converted to jQuery.data( "tmplItem" ) when elems are inserted into DOM. (tmplItem.key ? item.replace( /(<\w+)(?=[\s>])(?![^>]*_tmplitem)([^>]*)/g, "$1 " + tmplItmAtt + "=\"" + tmplItem.key + "\" $2" ) : item) : // This is a child template item. Build nested template. build( item, tmplItem, item._ctnt ); }) : // If content is not defined, insert tmplItem directly. Not a template item. May be a string, or a string array, e.g. from {{html $item.html()}}. tmplItem; if ( nested ) { return ret; } // top-level template ret = ret.join("");ret.replace( /^\s*([^<\s][^<]*)?(<[\w\W]+>)([^>]*[^>\s])?\s*$/, function( all, before, middle, after) { frag = jQuery( middle ).get(); storeTmplItems( frag ); if ( before ) { frag = unencode( before ).concat(frag); } if ( after ) { frag = frag.concat(unencode( after )); } }); return frag ? frag : unencode( ret ); }
这个里面出现了两条正则,我们分别看一下: