版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
1、javascript是一门精巧的语言,可大可小,可伸可缩,如意金箍棒一般,运用恰当,可敌千夫。比如一个场景,有的人要写上百行代码,但是有的人寥寥几笔即可实现,思路就在弹指间。要想学好一门语言,就要掌握其要义,归纳其精髓,方可如鱼得水,运筹帷幄。 js在开发大型组件库的时候经常会碰到很多的逻辑分支情况。比如博客园的编辑框编写:if(target = "font") someFunction().else if(target = "code") someFunction(). else if(target = "table")
2、someFunction().else if(target = "images") someFunction().else if(target = "link") someFunction(). else if(target = "file") someFunction(). 为了逻辑清晰当然也可以这样写:switch(target) case : "font" : someFunction(). break; case : "code" : someFunction(). bre
3、ak; case : "table" : someFunction(). break; case : "images" : someFunction(). break; case : "link" : someFunction(). break;case : "file" : someFunction(). break;当然这样的一层逻辑很容易书写和维护,但是,如果碰到下面还有多重分支的情况改如何处理呢,大部分人都是继续if else或者switch case。于是代码就变的越来越长,越来越难维护。就像下面的代码一
4、样:switch(target) case : "font" : someFunction(). break; case : "code" : switch(code) case : "java" : someFunction(). break; case : "c" : someFunction(). break; case : "c+" : someFunction(). break; break; case : "table" : someFunction(). bre
5、ak; case : "images" : someFunction(). break; case : "link" : someFunction(). break;case : "file" : someFunction(). break; js是一门面向对象的语言,我们能不能用面向对象的思想来解决这个问题呢?请看下面的源码: editor = "font" : function(). "code" : function(). "table" : fu
6、nction(). "images" : function(). "file" : function().editortarget(); 这样是不是清晰明了了很多?而且效率也肯定提升了,因为是对象直接寻址。大致思路如下:先创建一个对象,把所有的判断分支都放到这个对象里,然后再调用。 那么是么时候需要用这个方法,什么时候不需要用呢?先说需要用的:一、在判断分支很多的情况下建议使用。条理清晰。二、在分支里的逻辑很复杂的情况下,可以起到逻辑拆分的作用。 再说不需要用的情况:一、简单的逻辑判断。二、分支比较少的情况。js模版对于一
7、个健壮的组件库来说,至关重要。犹如建筑一栋大楼,模版就是钢筋,数据就是水泥,事件就是布线和弱电。本文将从一个小函数讲起,然后重点探讨js模版的实现模式、易用性、可扩展性,然后再对ext的模版体系做简单分析。 由于工作原因,本人一直在维护一个datagrid组件,datagrid的需求千变万化,大概60%的需求都是对单元格的处理,刚刚开始的时候需要一个功能就加一个功能,比如单元格需要根据数据改变背景颜色,于是我便在表格生成之后直接操作dom,比如带checkbox的datagrid,翻页后需要保存已选状态,于是我便在表格生成之后查找checkbox然后再选中。需要在增加,datagri
8、d也慢慢变的臃肿起来,不堪重负,leader也决定开始重构了。在重构之初,我便决定,在表格生成之前把需要处理的都完成,这样就可以节省查询dom的时间。这样以来,前期创建需要处理的逻辑就会很多,所以这里就需要一个很完善的模版体系来做支持,否则玩到最后又会变的很臃肿。 于是我尝试着写了一个简单的基于对象模式的模版,代码如下: /* * * 对象模式创建模版 * * param Array attrs 生成的节点数组 * param String type 类型 * param Array|Object attr 属性 * param Array|Object child 子节点
9、 * param Number num 子节生成个数 * param Function func 处理函数 * param Array data 数据 * * param Element|String target */var tpl = function(ats, target) target = fast.id(target); if (fast.isArray(ats) && ats.length > 0 && target.appendChild) for (var i = 0, len = ats.length; i < len; i+)
10、var attrs = atsi, tag = attrs.tag, attr = attrs.attr | , data = attrs.data, func = attrs.func, child = attrs.child, num = attrs.num ? attrs.num : 1, j = 0; var fragment = document.createDocumentFragment(); for (; j < num; j+) var isFunc = false; if (data) if (child) if (fast.isArray(child) for (v
11、ar k = 0, l = child.length; k < l; k+) childk.data = dataj; else child.data = dataj; else if (func) attr = func(j, attr, data); isFunc = true; else data = fast.values(data); attr.text = dataj; (isFunc = false) && func && ( attr = func(j, attr, data); var nodes = fast.node(tag, att
12、r); fragment.appendChild(nodes); child && tpl(child, nodes); target.appendChild(fragment); ; 另外创建了一个基类,这个基类后面的例子都会用到,希望读者注意。View Code var doc = window.document, _toString = Ototype.toString;var fast = isString : function(obj) return !(obj = '' | (obj && obj.char
13、CodeAt && obj.substr); , isNumber : function(obj) return _toString.call(obj) = 'object Number' , isArray : .isArray | function(obj) return _toString.call(obj) = 'object Array' , isObject : function(obj) return obj = null ? String(obj) = 'object' : _toString.call(obj)
14、= 'object Object' | true; , isEmptyObject : function(obj) for (var name in obj) return false; return true; , getID : function() var num1 = new Date().getTime(); var num2 = parseInt(Math.random() * 100000, 10); return num1 + num2; , id : function(id) if (this.isString(id) return doc.getElemen
15、tById(id); else if (id.nodeType) return id; return; , html : function(el, html) el = this.id(el); if (html) if (el != null && 'innerHTML' in el) el.innerHTML = html; else return el.innerHTML; , values : function(obj) var ret = ; for (var key in obj) ret.push(objkey); return ret; , se
16、tCssText : function(el, cssText) el.style.cssText = cssText; , setAttr : function(element, attrObj) var me = this, mapObj = "class" : function() element.className = attrObj"class" , "style" : function() me.setCssText(element, attrObj"style"); , "text"
17、; : function() if (attrObj"text".nodeType) element.appendChild(attrObj"text"); else element.appendChild(document.createTextNode(attrObj"text"); for (p in attrObj) if (mapObjp) mapObjp(); else element.setAttribute(p, attrObjp); , node : function(type, attrObj) var elemen
18、t = doc.createElement(type); if (!this.isEmptyObject(attrObj) this.setAttr(element, attrObj); return element; , testTime : function(get_as_float) var now = new Date().getTime() / 1000; var s = parseInt(now, 10); return (get_as_float) ? now : (Math.round(now - s) * 1000) / 1000) + ' ' + s; ,
19、/ext*/ _indexOf : Atotype.indexOf, inArray : function(elem, arr, i) var len; if (arr) if (this._indexOf) return this._indexOf.call(arr, elem, i); len = arr.length; i = i ? i < 0 ? Math.max(0, len + i) : i : 0; for (; i < len; i+) if ( i in arr && arri = elem) return i; return -
20、1; , isDate : function(o) return (null != o) && !isNaN(o) && ("undefined" != typeof o.getDate); , Format : , decodeHTML : function(str) str = String(str).replace(/"/g, '"').replace(/</g, '<').replace(/>/g, '>').repla
21、ce(/&/g, "&"); /处理转义的中文和实体字符 return str.replace(/&#(d+);/g, function(_0, _1) return String.fromCharCode(parseInt(_1, 10); ); , apply : function(object, config, defaults) if (defaults) this.apply(object, defaults); var enumerables = true, enumerablesTest = toString : 1 ; for
22、 (i in enumerablesTest) enumerables = null; if (enumerables) enumerables = 'hasOwnProperty', 'valueOf', 'isPrototypeOf', 'propertyIsEnumerable', 'toLocaleString', 'toString', 'constructor' if (object && config && typeof config =
23、 'object') var i, j, k; for (i in config) objecti = configi; if (enumerables) for ( j = enumerables.length; j-; ) k = enumerablesj; if (config.hasOwnProperty(k) objectk = configk; return object; ; 在模版使用之前,我们需要预先定义一组数据,这组数据后面的几个模版体系都会用到:View Code var data = name : "test1",sex :
24、 "man",age : "20",date : "2011-10-13 12:00:00:0",uid : "1", name : "test2",sex : "man",age : "20",date : "2011-10-13 12:00:00:0",uid : "2", name : "test3",sex : "man",age : "20",da
25、te : "2011-10-13 12:00:00:0",uid : "3", name : "test4",sex : "man",age : "20",date : "2011-10-13 12:00:00:0",uid : "4", name : "test5",sex : "man",age : "20",date : "2011-10-13 12:00:00:0",u
26、id : "5", name : "test6",sex : "man",age : "20",date : "2011-10-13 12:00:00:0",uid : "6", name : "test7",sex : "man",age : "20",date : "2011-10-13 12:00:00:0",uid : "7", name : "test8&q
27、uot;,sex : "man",age : "20",date : "2011-10-13 12:00:00:0",uid : "8", name : "test9",sex : "man",age : "20",date : "2011-10-13 12:00:00:0",uid : "9", name : "test10",sex : "man",age : "
28、20",date : "2011-10-13 12:00:00:0",uid : "10"for(var i = 10; i < 1000; i+) data.push(name : "test"+i,sex : "man",age : "20",date : "2011-10-13 12:00:00:0",uid : i); 这个模版的使用事例如下:var td = tag:"td",num:5,attr:text:"
29、text"var tr = tag:"tr",num:1000,child:td,data:data;var tbody = tag:"tbody",child:tr;tpl(tag:"table",attr:style:"width:100%",border:"1",child:tbody,"example");当然,您也可以这样写:tpl(tag:"table",attr:style:"width:100%",border
30、:"1", child:tag:"tbody", child:tag:"tr",num:1000, child:tag:"td",num:5,attr:text:"text", data:data , "example"); 该模版的核心思路就是递归创建dom,支持对每个dom绑定数据,支持外部函数调用(helper),支持内嵌数据处理,支持一次创建多个平级dom。对于一个组件库来说,感觉这样很完美了,于是我兴致冲冲的想拿其他的模版体系做对比。找了一大圈,发现别人玩
31、模版不是这样玩的,大部分都是先拼装字符串,然后再放到一个闭包里来处理,再返回。于是我模仿着别人写了一个原型,代码如下: /* * 字符串模式创建模版 * */var tp = function(str, data) var str = fast.id(str) ? fast.html(str) : str, str = str.replace(/<#(s|S)*?#>/g, function(p) return p.replace(/("|)/g, "$1").replace("<#", '_s.push(&
32、quot;').replace("#>", '");').replace(/<%(sS*?)%>/g, '",$1,"') ).replace(/r|n/g, ""), keys = , values = , i; for (i in data) keys.push(i); values.push(datai); return (new Function(keys, "var _s=;" + str + " return _s;"
33、;) ).apply(null, values).join("");调用方式大致如下:<div id="tptest" style="height:100px;overflow-y: auto"></div><script id="t1" type="text/tpl"><#<table width="100%" border="1">#> for (var i = 0, l = list.len
34、gth; i < l; i +) <#<tr>#> for(var p in listi) <#<td> <%listip%> </td>#> <#</tr>#> <#</table>#></script><script>var tpdata = list: data;fast.html("tptest",tp("t1",tpdata); 做了一下性能对比,乖乖,这个性能比对象模式更快,而且对象模
35、式能实现的,这个基本都能实现。但是对于处理单个dom的方式上,总感觉缺点什么,想来想去,原来这种方式不能把一个dom拿出来单独玩,需要跳到模版里面去,这里就需要注意环境变量以及逻辑关系了。 还是不死心,于是一狠心把ext的模版抽筋剥皮拿了出来,代码如下(运行需要上面的fast基类,未经详细测试,不建议用于生产环境):View Code extpl = constructor: function(html) var me = this, args = arguments, buffer = , i = 0, length = args.length, value; me.initial
36、Config = ; if (length > 1) for (; i < length; i+) value = argsi; if (typeof value = 'object') fast.apply(me.initialConfig, value); fast.apply(me, value); else buffer.push(value); html = buffer.join(''); else if (fast.isArray(html) buffer.push(html.join(''); else buffer.
37、push(html); / private me.html = buffer.join(''); if (piled) pile(); , isTemplate: true, disableFormats: false, re: /(w-+)(?:(w.*)(?:(.*?)?)?)?/g, _apply: function(values) var me = this, useFormat = me.disableFormats != true, fm = fast.Format, tpl = me, ret; if (piled) return piled(values).jo
38、in(''); function fn(m, name, format, args) if (format && useFormat) if (args) args = valuesname.concat(fast.functionFactory('return '+ args +'')(); else args = valuesname; if (format.substr(0, 5) = "this.") return tplformat.substr(5).apply(tpl, args); else r
39、eturn fmformat.apply(fm, args); else return valuesname != undefined ? valuesname : "" ret = me.html.replace(me.re, fn); /ret = pile(ret); /console.log(ret); return ret; , /* * Appends the result of this template to the provided output array. * param Object/Array values The template values.
40、 See link #apply. * param Array out The array to which output is pushed. * return Array The given out array. */ _applyOut: function(values, out) var me = this; if (piled) out.push.apply(out, piled(values); else out.push(me.apply(values); return out; , apply: function(values) return this.applyOut(val
41、ues, ).join(''); , applyOut: function(values, out) var me = this; if (!me.fn) me.fn = pile(me.html); /console.log(me.fn); /console.log(values); out = me.fn(values); /这里玩的很精妙,以后有时间再分析一下 /console.log(me.fn); /try / me.fn.call(me, out, values, , 1, 1); / catch (e) /console.log(out); return out;
42、 , /* * method applyTemplate * member Ext.Template * Alias for link #apply. * inheritdoc Ext.Template#apply */ applyTemplate: function () return this.apply.apply(this, arguments); , /* * Sets the HTML used as the template and optionally compiles it. * param String html * param Boolean compile (optio
43、nal) True to compile the template. * return Ext.Template this */ set: function(html, compile) var me = this; me.html = html; piled = null; return compile ? pile() : me; , compileARe: /g, compileBRe: /(rn|n)/g, compileCRe: /'/g, /* * Applies the supplied values to the template and inserts the new
44、 node(s) as the first child of el. * * param String/HTMLElement/Ext.Element el The context element * param Object/Array values The template values. See link #applyTemplate for details. * param Boolean returnElement (optional) true to return a Ext.Element. * return HTMLElement/Ext.Element The new nod
45、e or Element */ insertFirst: function(el, values, returnElement) return this.doInsert('afterBegin', el, values, returnElement); , /* * Applies the supplied values to the template and inserts the new node(s) before el. * * param String/HTMLElement/Ext.Element el The context element * param Ob
46、ject/Array values The template values. See link #applyTemplate for details. * param Boolean returnElement (optional) true to return a Ext.Element. * return HTMLElement/Ext.Element The new node or Element */ insertBefore: function(el, values, returnElement) return this.doInsert('beforeBegin',
47、 el, values, returnElement); , /* * Applies the supplied values to the template and inserts the new node(s) after el. * * param String/HTMLElement/Ext.Element el The context element * param Object/Array values The template values. See link #applyTemplate for details. * param Boolean returnElement (optional) true to return a Ext.Element. * return HTMLElement/Ext.Element The new node or Element */ insertAfter: function(el, v
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- 2025年劳动仲裁裁决和解协议
- 2025年加盟商业合同
- 2025年大数据智能分析合作协议
- 2025年冷藏海鮮運送合同
- 2025年创业投资协议解除协议
- 2025版信托投资公司绿色金融借款合同规范2篇
- 二零二五年度五人共同投资人工智能技术研发协议3篇
- 二零二五年度大型公共场所监控网络升级改造合同3篇
- 2025年度舞蹈教师舞蹈教材编写与出版合同
- 2025年度房地产项目银行过桥垫资借款合同
- 物业民法典知识培训课件
- 2023年初中毕业生信息技术中考知识点详解
- 2024-2025学年八年级数学人教版上册寒假作业(综合复习能力提升篇)(含答案)
- 《万方数据资源介绍》课件
- 第一章-地震工程学概论
- 《中国糖尿病防治指南(2024版)》更新要点解读
- 交通运输类专业生涯发展展示
- 大健康行业研究课件
- 租赁汽车可行性报告
- 计算机辅助设计AutoCAD绘图-课程教案
- 老年护理学-老年人与人口老龄化-课件
评论
0/150
提交评论