每天一剂Ext良药(二)

四十、创建一个在线HTML编辑器的最简单方法

如以下的HTML(就是一个textarea来放置内容)和JS:

<textarea class="edk-htmlEditor">fvgssdfsd</textarea>

Ext.onReady(function(){ Ext.QuickTips.init(); new Ext.form.HtmlEditor({ applyTo : Ext.select('textarea.edk-htmlEditor').item(0) ,width : 600 ,height : 500 }); });

当然,如果加入容器中的话,也可以不需要tags。

 

每天一剂Ext良药(二)_第1张图片

 

四十一、"0"/"1" 与 "false"/"true"的不同

刚看这个题目,大家可能觉得有些无聊。因为我们一般会是这样想,0即false,1即true,可完全视作等价,没什么好说的,其实,在JS中倒是有细微区别的。

如果:"1"  == 1 是成立的,即表达式是true,如果: "false" == false则是false。"false"当然不是false值,——那么可以用在什么场合呢?答案在于,可避免使用eval()函数。以当前我遇到的为例子,我把XML取出的属性value="1"是返回字符串的,——这点毫无疑问,再与数字类型1比较,机器中肯定这是等价的"1" ==1。JS中就是有这么奇怪的判定,明明两者类型都不一样,但看上去“是数字就是数字”了,即有Number("1")==1自动的转换操作。那如果不用数字表示,换false/true表示的话,却又不成立,除非eval('false') ==false方可为true,但内部又没有自动的eval操作。一般而言不提倡使用eval()函数,所以使用数字1/0就可以很好规避了这个问题。

话又说回来,怎么才可以准确判定"1"不是1呢?那就是"1"===1使用===三个等号判定,即返回false。

四十二、序列化表单取得JSON数据

序列化表单全体字段,可以使用Ext内建方法Ext.lib.Ajax.serializeForm(form);。但是现在要求返回对象返回对象而非字符串。

/** * 该方法源自Ext.lib.Ajax.serializeForm(form),原来返回字符,现改为返回JSON。 * @param {el} form * @return {Objct} */ function serializeForm(form) { var fElements = form.elements || (document.forms[form] || Ext.getDom(form)).elements, hasSubmit = false, encoder = encodeURIComponent, element, options, name, val, data = {}, type; Ext.each(fElements, function(element) { name = element.name; type = element.type; if (!element.disabled && name) { if (/select-(one|multiple)/i.test(type)) { Ext.each(element.options, function(opt) { if (opt.selected) { data[encoder(name)] = encoder((opt.hasAttribute ? opt.hasAttribute('value') : opt.getAttribute('value') !== null) ? opt.value : opt.text); } }); } else if (!/file|undefined|reset|button/i.test(type)) { if (!(/radio|checkbox/i.test(type) && !element.checked) && !(type == 'submit' && hasSubmit)) { data[encoder(name)] = encoder(element.value); hasSubmit = /submit/i.test(type); } } } }); return data; }

修改Ext.Ajax.serializeForm。原来返回字符,现改为返回JSON,其过程是筛选控件的类型el.type,例如submit的input就不采集数据。

四十三、JavaScript Tips:用split()代替遍历字符串

将字符串逐个转变为数组的元素,一般可以这样:

var nNum ='ABCDEF'; for(var i = 0, wordWidth = nNum.length; i < wordWidth; i++){ arDg[i] = nNum.charAt(i); }

但这样要写一次循环,使用split()就可以不要写循环,直接的js engine方法,如下例:

p.s:String.charAt()用法:chart(index:Number):String

var nNum ='ABCDEF'; arDg = nNum.split(''); // 这样得到的数组是一样的,而且速度较快。

四十四、JavaScipt点滴:取得随机数Thanks to shawl.qiu

如fRandomBy(上标, 下标)

function fRandomBy(nUnder, nOver){ switch(arguments.length){ case 1 : return parseInt(Math.random()*nUnder+1); case 2 : return parseInt(Math.random()*(nOver-nUnder+1) + nUnder); default: return 0; } }

作为反面教材,另附一个蹩脚的随机生成公式:

String(Math.random()).replace(/[^0-9]/g, '').substr(1, 8)

四十五、源码ext.js中的document.execCommand('BackgroundImageCache', false, true) 其作用何在?

这是一个对浏览器bug修正的语言,针对 ie6背景图片不缓存bug处理的问题。Edit:经过高人的指点,IE浏览器并不是不缓存图片,实际的HTTP也只有一次,而是IE内部的bug会轻微闪烁一下图片,仅此而已。

四十六、JavaScript小Tips:escape、encodeURI、encodeURIComponent等方法的区别

这三个函数的作用都是将字符转换成百分比编码(Percent-encoding ),区别是各自排除编码的字符不同:

escape() will not encode: @*/+

encodeURI() will not encode: ~!@#$&*()=:/,;?+'

encodeURIComponent() will not encode: ~!*()'

四十七、JavaScript小Tips:改变eval()作用域

eval()只有一个参数,可以函数或字符串两种类型:

eval(function(){this.xxx...}); // 或 eval('this.xxx...')

改变其作用域?除了apply()/call()方法之后还有一个更优雅的方法,就是with(){},如:

with ( objContext ){ eval(strScript); }

各浏览器通用,谁说过with不好的,呵呵。

四十八、JavaScript小Tips:数值进制的转换

js的数值进制转换都是围绕我们最熟悉的十进制设计的。Number本身表征是十进制的,返回16进制有包含a/b/c/d/e/f的字母,所以进制的转换就干脆安排在toString()身上。toString(进制)完成了十进制到其他进制的转换,js支持2~36之间的进制转换。其他进制到十进制转换呢?使用parseInt(其他进制,说明第一参数是何种进制的),js直接支持八进制、十进制、十六进制的字母表示。当然parseInt()可作为取整数的方法。

Thanks to 无心。

四十九、Ext的JSON2HTML方法简介

利用JavaScript创建HTML的内容,一般可以使用以下两种方法:
一、拼凑字符串,然后交由document.write/writeln()的方法输出;
二、使用标准的DOM方法,如createElement(),appendChild等等。
三、也是拼凑字符串,不过定义innerHTML属性输出。

这里介绍的方法和第二种方法类似,也是通过脚本标准的方式去构建页面中的元素。由于Ext是高度封装的API库,因此API中的又有它自己定义的元素控制方法,这些方法可以代替标准的DOM方法实现构建页面元素的底层功能。当然,在设计Ext元素方法的时候,就已经考虑到许多浏览器兼容的方方面面问题。另外,Ext提供Ext Core小型库,很大程度上就是满足了一般用户对修改DOM元素的需求。

一般的元素操控方法可以参考API和其他例子,这里时间有限^_^,我们先介绍其中的一个方面: JSON2HTML(其中的“2”谐音,念作英文的“to”)。

Ext.namespace('Ext.ux.searchWin'); Ext.ux.searchWin = Ext.extend(Ext.Window, { title : '请输入搜索内容' ,iconCls : 'icon16-search' ,width : 300 ,height : 150 ,html : { tag : 'form' , style : 'text-align:center;padding:10px;' , action : '?' ,children: [ { tag : "div" ,html : "请输入搜索的关键字:" } ,{ tag: 'input',type : 'text', name : "myText", cls : 'edk-input-2',size : 30 } ,{ tag : 'div', style: 'padding-top:5px;font-size:9pt;' ,children: [ { tag : 'a', href: "###", cls:'selectAll', html: '全选' } ,{ tag : "span", html: "  " } ,{ tag : 'a', href: "###", cls:'resetForm', html: '复位' } ] } ] } ,afterRender: function(){ Ext.ux.searchWin.superclass.afterRender.apply(this, arguments); var form_El = this.getEl().child('form'); var input_El = this.getEl().child('form/input'); var selectAll_El = this.getEl().child('div/a[@class=selectAll]'); selectAll_El.on('click', function(){ this.dom.select();}, input_El); var selectAll_El = this.getEl().child('div/a[@class=resetForm]'); selectAll_El.on('click', function(){ this.reset();}, form_El.dom); this.form_El = form_El; // 表单元素作为一属性。 } ,buttons : [ { text : '提交查询' ,handler : function(btn){ var winObj = btn.ownerCt.ownerCt; // 通过两次ownerCt.ownerCt可获取当前“窗体”的实例。 winObj.form_El.dom.submit(); } } ] });

我们可以将此步骤理解成为“通过JSON去定义一组HTML片段”!提示,afterRender这一步是重写Ext.Window的方法,但不是覆盖掉它,故需要执行Ext.ux.searchWin.superclass.afterRender.apply(this, arguments);。

测试代码是一行(new Ext.ux.searchWin).show();,下面是在IE6成功运行后的截图:

 

五十、HTML元素小Tips:隐藏元素的两个思路

一般CSS这样附加样式类就可以隐藏元素了:

.hide { display: none; }

另外一种方法隐藏,摘自Ext:

.hide2{ left:-1000px; position:absolute; top:-1000px; visibility:hidden; }

聪明的您看到了其中的“奥秘”了把:)

五十一、Ext.Direct中的Raw POST小解。

我们很熟悉所谓的HTTP POST是什么,那便是表单的提交,其结构是一清二楚的,每一个name对应着一个value,就好像<input name="userName" value="Jack" />那样。不用多说,Form一旦提交,里面所有的name/vlaue将提交到action指定的url位置。可是Raw POST却又是什么呢?Raw POST顾名思义,就是最原始的POST数据,没有经过进一步封装的,所以也不分什么name/value,就是一堆数据。相对的,HTTP标准POST也就是我们经常接触的POST,之所以呈现name/value的结构,是经过“浏览器”进一步封装才得出的结果。这样的话,不但不是一堆杂乱无章的数据,而且提供了一个简单的数据结构,同时程序员看起来也会比较清晰。我们之前不了解Raw POST是因为不常接触,不过不多了解罢了。

name/vlaue结构不能满足Ext.Direct复杂的数据要求,应该说,不能满足复杂业务需求。这样JSON的结构就取而代之name/value。我们知道JSON可以在客户端就可以编码字符串的,所以,也不用什么标准POST提交,在AJAX请求时把编码好的JSON填入HTTP Head就可以发送出去了,——也就是一堆字符串,明文报码,没有什么复杂性。

五十二、Ext.namepsace命名空间函数的改进

第一代的Ext.namespace函数写法比较奇怪,甚至动用了eval反射字符串。eval名声不太好,呵呵 能避免就避免吧,于是,Ext3的namespace()作了如下的改进:

function namespace(){ var o, d; Ext.each(arguments, function(v) { d = v.split("."); o = window[d[0]] = window[d[0]] || {}; Ext.each(d.slice(1), function(v2){ o = o[v2] = o[v2] || {}; }); }); return o; }

但是,上面的代码用了两个Ext.each,也就是两个循环。下面有一个相同作用的方法,我重新写过的:

// 到时把oo该window即可 var oo = {}; function ns(a){ (function(arr){ var obj = (this[arr.shift()] = {}); if(arr.length){ arguments.callee.call(obj, arr); } }).call(oo, a.split('.')); } ns('dd.d.d');

自吹自擂一下,呵呵,自己写的不仅没有出现循环代码,而且更简洁,更可读。这是在写一个递归节点的时候,顺便想到的。请注意一定得用call/apply方法,配合this指针移位,——此乃一个JS的秘密哦。

五十三、如何取得窗体Win里面的Button对象?

如一个Win的配置如下:

win = new Ext.Window({ buttons : [{ text : "同意/提交" }, { text : "退出" }] });

如何取得Win 里面的Button对象?答:放置一个id, 然后调用Ext.getCmp("ID");获取EXT.COMPONENT对象。如果取到button1对象后给对象加上一个click 事件,可以这样写:

var obj = Ext.getCmp("ID"); obj.on('click',function(){});

五十四、字符串十六进制的编码形式in JavaScript

和escape()差不多,后面的一组数字xxx都是表示该字符在字符集表里面的编码的16进制数字,即%XXXX和/uXXXX都是一样的。比如输入十六进制5BA0,我们可用/u5BA0表示,又可以用%u5BA0的字符串表示,转换成十进制是23456,再转unicode则是“宠”字。结果都一样。下面给出相关的转换函数。

to16 = { on : function (str) { var arr = []; for (var i = 0 ; i < str.length ;i++) { arr.push( ("00" + str.charCodeAt(i).toString(16)).slice(-4) ); } return "//u" + arr.join("//u"); } ,un : function (str) { return unescape(str.replace(////g, "%")); } };

注意,尽管/uXXXX仍然是以字符串形式表示,但js中不支持'/uXX'+'XX'这样的拼凑,至少在IE中如是。

Tips:在一些不支持unicode编码格式的文本中/uXXXX非常方便。

五十五、JavaScript客户端控件:目录选择器

使用<input type="file" />控件可以很方便地选择客户端的文件是哪个文件,奇怪的是,却没有其他哪个目录的选择控件,不能不说有麻烦。既然安全机制可允许选择文件,那么何解又不可以选择目录呢?我在弄一个HTA的小程序的时候,都是没有找到一个目录选择控件。不过,踏破铁鞋无觅处,我在一个名叫easysr.hta的Search & Replace HTA程序中,找到了这个目录选择控件!还得多谢dh20156这样的高手,不但提高了这么优秀的hta代码,还关键在于HTA本身便是开源!认识dh20156,记得是在Google JavaScrpt 十六进制的字符编码的时候认识dh20156大大的,其JS代码质量可谓令人刮目!好,回到主题,下面给出目录选择控件的Code Sinpnet:

var objShell = new ActiveXObject("Shell.Application") // 借助MS通用库Shell.Application对象 ,objFolder = objShell.BrowseForFolder(0, '请选择目录', 0, 0x11) // 有个参数可参考下面的资料 ,path = objFolder.Self.Path; // 返回字符串的目录

关于Shell.Application的用法如下:

打开文件浏览对话框,BrowseForFolder是最实用的一种方法,它可以定位文件或文件夹,或定位系统文件夹,具体形式如下:

                Oh.BrowseForFolder(Hwnd,Title,Options,[RootFolder]);

                具体参数:

                Hwnd,这里必须为0

                Title,对话框标题字符串

                Options,浏览方式,见下:
                0x0001  For finding a folder to start document searching
                0x0002  For starting the Find Computer
                0x0004  对话框加宽
                0x0008  确定按钮变灰失效
                0x0010  在对话框顶部加入编辑框
                0x0020  insist on valid result (or CANCEL)
                0x1000  确定按钮变灰失效
                0x2000  可选当前文件,不包括子目录文件,确定按钮变灰失效,(可同时选0x0001使确定按钮有效)
                0x4000  浏览所有项,可选文件或文件夹

                RootFolder,起始根目录,可选项,可以自己指定目录字符串,也可以是系统目录的数字表示,数字含义见下:
                0x0000        桌面
                0x0001        IE浏览器
                0x0002        C:/WINDOWS/Start Menu/Programs目录
                0x0003        控制面板
                0x0004        打印机
                0x0005        我的文档
                0x0006        收藏
                0x0007        启动
                0x0008        Recent文档
                0x0009        发送到
                0x000a        回收站
                0x000b        开始菜单
                0x000c        桌面(打开在我的电脑)      
                0x0010        C:/WINDOWS/Desktop桌面目录
                0x0011        我的电脑(包括所有驱动器)
                0x0012        整个网络
                0x0013        NetHood
                0x0014        字体目录
                0x0015        C:/WINDOWS/ShellNew目录
                0x001a        C:/WINDOWS/Application Data目录
                0x001b  printHood
                0x0020        C:/WINDOWS/Temporary Internet Files目录
                0x0021        cookie目录
                0x0022        IE浏览历史

                如:
                Oh.BrowseForFolder(0,"测报软件:",0x1000|0x0001,"D://OSSMO 2004");
                Oh.BrowseForFolder(0,"垃圾文件:",0x4000,0x000a);
                Oh.BrowseForFolder(0,"请选择目录:",0x0000 ,"c://");

 BrowseForFolder 最后将返回用户所选的文件或文件夹的Folder类目标,通过对Folder类目标的处理得到所选目标的完整路径,例如:

var Oh= new ActiveXObject("Shell.Application"); var ob=Oh.BrowseForFolder(0,"我的文件夹:",0x1000|0x0001,0x0000); // 返回Folder目标ob if(ob&&ob.Items()&&ob.Items().Item()) alert("你选择了目录:"+ob.Items().Item().Path); else alert("你未做选择");

每天一剂Ext良药(二)_第2张图片

就是这个小小目录选择控件,因为自己写不可能,所以必须得找一个系统提供的方案,有就有,没有就没有。找的过程中也比较辛苦,但终于也解决了。同时不禁让我想起AIR的目录选择控件,它是原生的。

(注:AJAX网页下不可用该控件。)

五十六、Ext TableLayout概念

Ext的TableLayout的布局概念正是参照HTML Table的方式。其实Table有它独特的布局方式,不一定Div就可完全期待Table。HTML布局我们可能都接触接触,下面就给出一个经典的例子,全面演示了HTML各个Tag的用法。在使用Ext TableLayout的时候也有一定的参考意义。

<table width="200" border="1"> <thead> <caption>标题</caption> <tr> <th colspan="2">ddddddddddddds</th> </tr> </thead> <tbody> <tr> <td style="word-break:break-all;word-wrap: break-word;" mce_style="word-break:break-all;word-wrap: break-word;"> <div style="overflow:auto;height:100px;"> 博客正文内容博客正文内容博客正文内容博客正文内容博客正文内容博客正文内容博客正文内容博客正文内容博客正文内容博客正文内容博客正文内容博客正文内容博客正文内容博客正文内容 </div> </td> <td>dddd</td> </tr> <tr> <td rowspan="2">ss</td> <td>ss</td> </tr> <tr> <td>dddddd</td> </tr> </tbody> </table>

 

每天一剂Ext良药(二)_第3张图片

五十七、Grid与Spring MVC结合的例子

见:http://loianegroner.com/2010/03/extjs-and-spring-mvc-framework-crud-datagrid-example/

五十八、DataStore适配第三方数据结构一例

如图,要将Store中的数据转换Tree的一种,即如图的“组织结构图”,我们必须先经过Store-》DataTable转换过程。详细过程参见Ext.ux.GDataTableAdapter源码。

出处: Ext Charting and Mapping with Google Visualizations

五十九、Ext继承小解

Ext.tree.TreePanel.superclass.initComponent.call(this);

这句话是什么意思
XX.superclass.constructor.call(this);
这句话又是什么意思。为什么要传参数this啊?

调用父类。可以理解为ext的继承方式。superclass保留了访问父类的引用,后面的是方法,因为方法的类型是Function,所以可以使用call/apply的方法。为什么需要call/apply呢?因为如果不使用,将不能保证父类方法执行的时候,它的作用域是在当前实例之中,也就是通过强制call/apply指明了实例对象为this。

六十、 window.close 跟window.destroy 区别在哪?

按照不同的应用场景来使用close/destroy方法吧。close之后,如果我们需要再显示窗体,还可以show一次,把窗体显示出来,此时可以说窗体对象还驻留在内存中;然而destroy不同,destroy()之后,包括窗体的DOM树、登记的事件、JS对象等等都被清除,回收资源。这样再显示窗体,就要new对象一次了。

六十一、禁止鼠标右键、选择的JS

虽然没啥技术含量,但是做了总比没做了好,在一些比较正规的网站上。对比过网上的不同代码,综合一个通用性较好,可支持IE&FF的并忽略input/select/textarea的元素。

// 禁止选择,形成可复制的选区 document.onselectstart = function(){ var el = event.srcElement; if (!((el.tagName == "INPUT" && el.type.toLowerCase() == "text") || el.tagName == "TEXTAREA"|| el.tagName == "SELECT")){ return false; } } // for FF if(window.Event){ Ext.onReady(function(){ document.getElementsByTagName('body')[0].style.MozUserSelect = 'none'; }); Ext.fly(document).on('mousedown', function(e){ if (/(input|textarea|select)/ig.test(e.target.tagName)){ document.getElementsByTagName('body')[0].style.MozUserSelect = 'text'; }else{ document.getElementsByTagName('body')[0].style.MozUserSelect = 'none'; } }); } // 禁止鼠标右键 document.oncontextmenu = function(){ return false; };

六十二、URL解析函数

作者是Steven Levithan <stevenlevithan.com>大大。本来与Ext主题不相关,虽如此,觉得比较有趣,一时又有无可容纳该代码之处,就放在这儿咯。

/* parseUri 1.2.1 (c) 2007 Steven Levithan <stevenlevithan.com> MIT License */ function parseUri (str) { var o = parseUri.options, m = o.parser[o.strictMode ? "strict" : "loose"].exec(str), uri = {}, i = 14; while (i--) uri[o.key[i]] = m[i] || ""; uri[o.q.name] = {}; uri[o.key[12]].replace(o.q.parser, function ($0, $1, $2) { if ($1) uri[o.q.name][$1] = $2; }); return uri; }; parseUri.options = { strictMode: false, key: ["source","protocol","authority","userInfo","user","password","host","port","relative","path","directory","file","query","anchor"], q: { name: "queryKey", parser: /(?:^|&)([^&=]*)=?([^&]*)/g }, parser: { strict: /^(?:([^://?#]+):)?(?:////((?:(([^:@]*):?([^:@]*))?@)?([^://?#]*)(?::(/d*))?))?((((?:[^?#//]*//)*)([^?#]*))(?:/?([^#]*))?(?:#(.*))?)/, loose: /^(?:(?![^:@]+:[^:@//]*@)([^://?#.]+):)?(?:////)?((?:(([^:@]*):?([^:@]*))?@)?([^://?#]*)(?::(/d*))?)(((//(?:[^?#](?![^?#//]*/.[^?#//.]+(?:[?#]|$)))*//?)?([^?#//]*))(?:/?([^#]*))?(?:#(.*))?)/ } };

六十三、JS硬反射

JS的硬反射,用正则的强硬手段得到函数名称,函数的参数列表。一般调试的时候才会使用反射,所以不推荐在实际编码中使用反射,尤其是这种硬反射。

Edk.Util.Function = { /** * 先反射函数对象,去掉函数的头尾,返回body部分。 * @return {String} */ getBody: function() { // Get content between first { and last } var m = this.toString().match(//{([/s/S]*)/}/m)[1]; // Strip comments return m.replace(/^/s*////.*$/mg, Edk.String.emtpyCharacter); } /** * 返回函数的参数。如果为匿名函数则返回null。ONLY works like "function foo(){}". * if a function is passed, return the name of its function(class) . * @return {String} */ ,getParam: function() { var m = this.toString().match(/function.*/((.*)/)/); return m ? m[1] : null; } /** * 返回函数的名称。如果为匿名函数则返回字符串"anonymousFn"。ONLY works like "function foo(){}". * @return {String} */ ,getName: function() { var m = this.toString().match(/^function/s(/w+)/); return m ? m[1] : "anonymousFn"; } };

六十四、用Ext Core插入Flash电影

插入Flash电影文件到页面。原本Robert Nyman的是用字符串拼凑的,现改为JSON2HTML。 例子:(在插入的地方)<script>Edk.setFlash({src:'images/ani.swf'});</script>

/** * 插入Flash电影文件到页面。原本Robert Nyman的是用字符串拼凑的,现改为JSON2HTML。 * 例子:(在插入的地方)<mce:script type="text/javascript"><!-- Edk.setFlash({src:'images/ani.swf'}); // --></mce:script> * @param {Object} config 配置参数 * @cfg {String} src Flash电影的文件路径(SWF) * @cfg {String} id Flash电影元素的id(可选的) * @cfg {Nubmer} width Flash电影的宽度(可选的) * @cfg {Nubmer} height Flash电影的高度(可选的) * @cfg {Object} params 参数(可选的) * credit: Robert Nyman, http://code.google.com/p/flashreplace/ */ function setFlash(config){ /** * 检测Flash是否安装 * @param {Number} version * @return {Boolean} True表示已安装符合版本要求的Flash */ function checkForFlash (version){ if(Ext.isIE){ try{ new ActiveXObject("ShockwaveFlash.ShockwaveFlash." + version); return true; }catch(e){ return false; } }else{ var _plugins = navigator.plugins; if( _plugins && navigator.mimeTypes.length > 0){ if(_plugins["Shockwave Flash"] && _plugins["Shockwave Flash"]['description'].replace(/.*/s(/d+/./d+).*/, "$1") >= version) { return true; } }else{ return false; } } } if(!checkForFlash(config.version || 7 /*defaultFlashVersion*/)){ throw 'Flash is NOT Readly!'; } var children = [ { tag : 'param' ,name : 'movie' ,value : config.src } ,{ tag : 'embed' ,type : "application/x-shockwave-flash" ,src : config.src ,width : config.width ,height: config.height } ]; var _params = config.params; if(_params){ for(var i in _params){ children.push({ tag : 'param' ,name : i ,value: _params[i] }); } } Ext.fly(config.el).createChild(Object.apply({ tag : 'object' ,classid : "clsid:D27CDB6E-AE6D-11cf-96B8-444553540000" ,data : config.src ,children : children }, config)); }

六十五、请问Ext里的属性和配置项有什么区别?

一般属性是相对于“某一实例”、“某一对象”的说法。配置项(

config item)在Ext中多用于初始化时候,传入到组件的配置项情况。配置项一般传入后则不作变化,也不一定可以访问值是如何。但属性可以读、也可以写。

六十六、JavaScript字符串反序列化的函数

输入str('/nHello World!/n')仍然得到'/nHello World!/n',有幕等性,呵呵。Thx to Lich Ray

function cdr (l) { return l.slice(1) } function str (t) { var tb = { '/"':'//"', '//':'////', '/b':'//b', '/f':'//f', '/n':'//n', '/r':'//r', '/t':'//t', '/v':'//v' } function iter (s) { if (s == "") return '' if (tb[s[0]] != undefined) return tb[s[0]]+iter(cdr(s)) return s[0]+iter(cdr(s)) } return '"'+iter(t)+'"' } // test alert(str('/nHello World!/n'));

六十七、如何检测得知Firebug已安装?

登陆GMail的服务,如果安装了firebug,系统会提示你关闭Firebug以提示。如果要为我们自己的B/S程序安排这样的功能,加入下面的代码即可(应去掉$$)。

/** * 返回True表示已安装Firebug。 * @return {Boolean} */ $$.detectFirebug = function(){ if((console && console.firebug) || document.getElementById('_firebugConsole')){ // 你已经按照Firebug的插件,这样会引致浏览页面的速度减慢。我们建议你针对我们关闭Firebug。 return true; } }

六十八、显示调用父类的作用

搞不懂的就是,B继承自A,为什么不像Java那样,在B构造函数调用刚开始的时候,A的构造函数都要被默认调用? 我的问题是,既然有继承链,那么最底层类的构造时就要把所有父类都初始化一遍,为什么这里没有?

这个例子:

function A(){ alert('A constructor'); } function B() { alert('b con'); } Ext.extend(B, A, {}); new B();

输出是 b con
——虽然有继承链,但继承链是在原型链(prototype)的基础上实现的,每一个“类”都是仍是一个个function+protoype,这时候,Ext继承方法Ext.extened像一个工厂方法,对输入的父类和子类产生prototype的链接关系,并分配父类的引用。
——分配父类的引用,目的在于能够让子类调用父类的时候,可以寻址,也就是显式调用父类、
Java里面,SubClass() { }里是默认有个super();的。我确实也知道javascript的prototype-based OO和java的class-based OO有不同,但是感觉子类构造过程上都出现差异了。。 感觉有点晕。

——对super() java里面可以不写,ext中要写出来 。

六十九、JavaScript是OO语言该论点是可以证明的。

OO经典的特征,一切皆是对象。JS亦然。证明如下:

// 如果定義: function Test() { } // 相當於: var Test = {}; Test.constructor = Function; Function.call(Test); // 而建立物件: var test = new Test(); // 相當於: var test = {}; test.constructor = Test; Test.call(test); // 注意:Function 中是 Native code,但其中有些部份,相當於: this.prototype = {}; this.prototype.constructor = this;

感谢来自台湾一位朋友的提示!

七十、未知参数的长度如何完整送入?

如果参数是动态的,怎么保证每个参数都逐个逐个送入到函数中去?——“参数”列表是Array,想办法用apply(适合的对象, args)即可,如下例:

Base64_decode = function(cs){ var ds = ['dd', 'aa']; return String.fromCharCode.apply("", ds); // 动态参数列表的传入,试试比较 // return eval("String.fromCharCode(" + ds.join(",") + ")"); }

七十一、RegExp在IE与FF中不同的表现

项目需要读取Cookie的脚本,发现Ext Core居然没有包含脚本。自己写写,首先是最简单的:

var arr = document.cookie.split(';'); for(...){ arr[i] // get key.... }

不过最后还是要经过JSON或eval的转换,显得比较dry,于是重新考虑,所以就有了下面的方案。另外补充一个知识点:关于 RegExp.exec()是逐次逐次命中匹配结果,因此必须进行遍历的操作。而match()则是返回所有不分组的结果,没有分组的话结果不及 exec()精细。特别注意,RegExp有静态成员作为其遍历的堆栈,即index = 0,特别的test()也算一次,也就是test()不会复位index=0。有网友作了这样的总结:

    在ie核心瀏覽器中, replace後不會重設為0
    而非ie核心瀏覽器中, replace後則會重設為0
    因此, 解決方法很簡單,就是在replace後加上reg.lastIndex=0;
    所以一般來說都不建議使用/g

var cookieStr = document.cookie + ';' // 在最后加分号作为“补码”。 ,get_Reg = //s?(.[^=]*)/=(.[^;]*);/g ,match = true, key, value; // ,sStr = cookieStr.replace(get_Reg,'key_$1 : "value_$2",'); // 序列化 while((match = get_Reg.exec(cookieStr)) != null){ key = match[1], value = match[2]; if(key == _key){ return unescape(value); } } return null;

最后在我代码库中,其实都没有加入以上的方案……还是月影的new RegExp(xxx);来得好。

七十二、Grid自动填充列

不少人都碰到过的问题。如图:

 

首先,在CM里,需要自动填充gird的列 + 一个ID;然后指定autoExpandColumn:'detailedinfo';跟着在grid里面增加:

..... viewConfig: { forceFit:true,//当行大小变化时始终填充满 enableRowBody:true//可以用两行tr来表示一行数据 }, ....

七十三、请问在extjs中类的继承中constructor和initComponent()的区别

关于constructor和initComponent之间,两者有相似,却让人感觉容易混淆,当然它们比较起来有一定的差异的,首先我想可以从以下来分析,其次还有运行http://book.ajaxjs.com/correct/ 第四点的例子看看。

  1. constructor是类的构造器方法,initComponent的全称是Ext.Component.initComponent();。它们的定义不尽相同,一个是每一个类均带有的必备方法,即构造器constructor;另外一个是Ext组件类方用调用的方法。这是的定义上的差异,也可以说语义上的不同。
  2. 传入的参数不同。构造器的参数是否有new Class(arg1, arg2)过程决定?对,参数被送入到构造器中我们可以进一步的处理;而initCompontnt()是API控制的,Ext组件类定义。默认没用传入参数。这样,如要对参数进行加工或者自定义类参数的时候(比如需要重写这个类的时候),一般通过构造器constructor获得参数,而且调用的顺序应该constructor于initComponent之前。
  3. 回到第一个问题上。为什么会有语义上的不同呢?我想还得回忆一下Ext API的改进历程是怎么的。首先依据Ext.Component.initComponent文档,摘抄如下:

// Traditional constructor: Ext.Foo = function(config){ // call superclass constructor: Ext.Foo.superclass.constructor.call(this, config); this.addEvents({ // add events }); }; Ext.extend(Ext.Foo, Ext.Bar, { // class body } // initComponent replaces the constructor: Ext.Foo = Ext.extend(Ext.Bar, { initComponent : function(){ // call superclass initComponent Ext.Container.superclass.initComponent.call(this); this.addEvents({ // add events }); } }

上述是传统的集成方式,主要表现在initComponent代替了Ext.Foo = function(config){}构造器,这相对于也就是回答了initComponent与constructor的相似性在哪里,因为Ext.Foo = function(config){}便是一个构造器,虽然写法上不同,但却是等价的作用——只是在新版中对这一写法作了改进,成为:

sub = Ext.extend(superClass, { constructor: function(){ // ....构造器here } }); (p.s:如果从历史的线性角度看,记忆所及,constructor似乎是后来加入Ext.extend继承的关键字的,也就是后来的版本提供的。若再说的透一点,估计是当时没认识到,尽管constructor属于JS保留字的一员,但JS中的自由度离奇地大,就连作为js hash中的key中也是没用问题,呵。但这一发现,已是在initComponet已经成为API一部分之后)。

七十四、如何将JavaScript里面写好的文档生成HTML资料格式?

一份良好质量的源码怎么能少了清晰可读的注释呢?没错,不要偷懒,都给你的公共的方法、公共属性、配置项的等写上注释。哪怕是自己弄的程序,也要最好养成写注释的习惯。无论是自己还是别人,看文本肯定要比看计算机代码舒服,尤其是你在隔几个天后回头看代码的时候。Ext是采用类似JSDoc,(但有不一致的些地方,译者注)规范的注释。你可以使用Ext Doc这个项目来生成你自己写好的注释。(p.s Ext官方的文档生成器是用PHP写的,可惜不对外公开)

七十五、数字类型的识别转换。

在使用JavaScipt脚本代码本身识别一个字符串是否数字的时候,想到了两个方法,它们的作用都是一样的:

function(v){ if(v == Number(v)) v = Number(v); if(/^/d+$/.test(v)) v = Number(v); return v; }

假设字符串数字经过转换后就是数字,那么就表示可以放心转换,否则则不是一个字符类型的数字。第二个办法,就是通过正则来判断,不知是否比较费时?这是一个小问题啦,不知道怎么去讲清楚,就发在这里吧。

七十六、JavaScript的匿名对象及其用法

如代码:

alert({a:1,b:2}['a']);

惊艳!

七十七、节约 DOM 操作

转自:http://www.gracecode.com/archives/741/

Javascript 对 DOM 的处理,可能是最耗费时间的操作之一。每次 Javascript 对 DOM 的操作,浏览器都会改变页面的表现、重新渲染页面,从而有明显的时间损耗。比较环保的做法就是尽可能不在 DOM 中进行 DOM 操作。

请看下面的例子,为 ul 添加 10 个条目:

var oUl = document.getElementById("ulItem"); for (var i = 0; i < 10; i++) { var oLi = document.createElement("li"); oUl.appendChild(oLi); oLi.appendChild(document.createTextNode("Item " + i); }

乍看起来似乎无懈可击,但是这段代码的确有问题。首先是循环中的 oUl.appendChild(oLi);的调用,每次执行过后浏览器就会重新渲染页面;其次,给列表添加添加文本节点(oLi.appendChind(document.createTextNode("Item " +i);),也这会造成页面重新渲染。每次运行都会造成两次页面重新渲染,总计 20 次。要解决这个问题就如上面所言的,减少 DOM 操作,将列表项目在添加好文本节点以后再添加。下面的代码就可以与上述的代码完成同样的任务。

var oUl = document.getElementById("ulItem"); var oTemp = document.createDocumentFragment(); for (var i = 0; i < 10; i++) { var oLi = document.createElement("li"); oLi.appendChild(document.createTextNode("Item " + i); oTemp.appendChild(oLi); } oUl.appendChild(oTemp);

七十八、Ext.TaskMgr的用法

你好,看了你的关于一篇定时器的文章,Ext.TaskMgr的用法!我想问一下,如果我定义的时间间隔为2s,但是我定时运行的那个函数某次运行了超过了2s,比如达到了5s,这样会产生什么问题呢?对于我下次取得的会不会是错误的结果呢?

答:Ext.TaskMgr相当于setTimeout()的封装。setTimeout我估计也可以是一种“异步”的操作。如果超过了某个时限,那应该是怎么控制超时的问题。Ext.Ajax中就有对AJAX请求超时不能答复的处理,可以参照一下其代码:)不知道这样对您有没有帮助。

 

七十九、Ext+ASP: Access数据库不支持Ext.PagingBar的Start、limit怎么办?

从网上收集到方法有三个,都是通过转换SQL的方法,列举如下(……不过是服务端的JS)。

方法一:

/** * @param {String} sql 传入的SQL查询SELECT语句。 */ function accessPaging(sql){ // 假设原本的sql语句为SELECT * FROM news,改装SQL字符串如下: var start = Request("start")() ,limit = Request("limit")() || 5; // 默认的page size if( !start ||start =='0' ){ sql = "select top " + limit + " * from news order by createDate" }else{ var l = "select top " + limit + " * from news " var s = "select top " + start + " * from news "; sql = l + "where (createDate>(select max(createDate) from ("+s+") as T)) order by createDate" } return sql; }

方法二:

/** * @param {String} sql 传入的SQL查询SELECT语句。 */ function accessPaging(sql){ // 假设原本的sql语句为SELECT * FROM news,改装SQL字符串如下: var start = Request("start")() ||1 ,limit = Request("limit")() || 5 ,begin_n = start + 1; ,end_n = start + limit; if(end_n > limit) { var l ="Select * From (select top 10 news.id from news inner join newsclass on news.ClassID = newsClass.ID)" var s = "select top news.id from news inner join newsclass on news.ClassID = newsClass.ID" sql = l + " AS a where Not Exists(Select * From (" + s + ") AS b Where b.id=a.ID)"; }else{ //sql = "select top " + limit + " * from news" sql = sql.replace(/SELECT/i, 'SELECT TOP ' + limit); } return sql; }

方法三:

/** * @param {String} sql 传入的SQL查询SELECT语句。 */ function accessPaging(sql){ // 假设原本的sql语句为SELECT * FROM news,改装SQL字符串如下: var pageSize = 8 ,start = Number(start || Request.QueryString('start')() || 0) ,limit = Number(limit || Request.QueryString('limit')() || pageSize) ,count_sql = sql.replace(/(SELECT)(.*)(FROM)/i, '$1 COUNT(*) AS totalCount $3') ,count_sql = $$.sql(count_sql).rsObj ,count = count_sql('totalCount').value // 该方法必须要这样查询总数 ,sql = sql.replace(/SELECT/i, 'SELECT TOP ' + (start + limit)) ,sql = ('SELECT * FROM (' + 'SELECT TOP {0} news.* FROM (' + '{1} ORDER BY {2} ASC' + ') ORDER BY {2} DESC' + ') ORDER BY {2} ASC').format(limit, sql, id_fieldName); return sql; }

方法三的原理参考下面的SQL语句:

// 参考一 SELECT * FROM ( SELECT TOP x * FROM ( SELECT TOP y fields FROM table WHERE conditions ORDER BY table.field ASC) as foo ORDER by field DESC) as bar //ORDER by field ASCx is the number of rows you want returned and y is x+offset. // http://josephlindsay.com/archives/2005/05/27/paging-results-in-ms-sql-server/ // 参考二 select * from ( select top $pagesize from ( select top %curpage*pagesize id from table order by id desc ) as a order by id desc) as b order by id asc

八十、Ext+ASP: Access数据库不支持Ext.PagingBar的Start、limit怎么办?(补充)

上面介绍的Ext分页Access数据库方法,无论哪一种,都不是太好。特别在最后一页的时候,竟然偏移不正确。总之涉及修改SQL都会有副作用,要查询么集合有问题,要么排序有问题。于是,还得靠老办法,使用Rs.absolutePage/Rs.pageSize来分页,也就是传统的ADO游标的分页算法。虽然由于每次加载页面都要重新读取数据表的全部数据,性能十分低下,但是能够保证记录显示正确,这是首先要可以做到的。

var conn = $$.sql.execute(null, true); var matchCount ,page ,page = Request.QueryString("page")() // 当前页码,在第几页 ,i = 0 ,j; with(new ActiveXObject("ADODB.Recordset")){ // @dep 传统分页方法 open(sql, conn, 1, 1); if (rs.EOF && rs.BOF) { return '没有记录!'; } pageSize = 3; // 每页大小,这个值应该为常量 matchCount = recordCount; // 匹配查询结果总数,不分页的总数 // 求page if (!page || page < 1) { page = 1; } if ((page - pageCount) > 0) { // rs.pagecount是总页数,已经根据前面的已知条件算出来了 page = pagecount; } absolutePage = page; // 指定此时的页码 j = rs.recordCount; // j有何作用? j = j - (page - 1) * pageSize; do { Response.write("每条记录信息:" + fields("id") + "<br>"); i++; rs.moveNext(); } while (!EOF && i < pageSize); }

八十一、&字符在Ext模板中转义的问题。

模板保持在XML文件,再由Ext.XTemplate解析。但来问题了,XML中使用&字符要转义!怎么转义呢?既然是经过JS解析,那么便可以从JS String语言中寻找思路。原来String提供了一个fromCharCode(unicode)的方法,输入字符的unicode对应的值,便可返回字符。我们在Ext模板语言写一个运行js的标识就可以了:

< a href="?id=232{[String.fromCharCode(38)]}action=update" …………>查看</a>

String.fromCharCode(38) =='&' // true

八十二、DHTML经典特效:隔行换色,斑马线效果

不多说了,以前用css做,现在也是用css做,不过通过CSS Selector选择符来完成。ExtCSS选择符内部已经考虑到这个经典的需求了。例子如下:

Ext.fly("edk-listComponent").select('li:even/div').addClass('evenRow');

你这需要修改evenRow对应的CSS的定义去修改即可。

八十三、人性化显示日期

有个这个函数,日期不再是一串数字。powered by  John Resig (jquery.com)

/** * JavaScript Pretty Date * Copyright (c) 2008 John Resig (jquery.com) * Licensed under the MIT license. prettyDate("2008-01-28T20:24:17Z") // => "2 hours ago" prettyDate("2008-01-27T22:24:17Z") // => "Yesterday" prettyDate("2008-01-26T22:24:17Z") // => "2 days ago" prettyDate("2008-01-14T22:24:17Z") // => "2 weeks ago" // Takes an ISO time and returns a string representing how // long ago the date represents. */ function prettyDate(time){ var date = new Date((time || "").replace(/-/g, "/").replace(/[TZ]/g, " ")), diff = (((new Date()).getTime() - date.getTime()) / 1000), day_diff = Math.floor(diff / 86400); if (isNaN(day_diff) || day_diff < 0 || day_diff >= 31) return; return day_diff == 0 && (diff < 60 && "刚刚" || diff < 120 && "一分钟之前" || diff < 3600 && Math.floor(diff / 60) + "分钟之前" || diff < 7200 && "一小时之前" || diff < 86400 && Math.floor(diff / 3600) + "小时之前") || day_diff == 1 && "昨天" || day_diff < 7 && day_diff + "日之前" || day_diff < 31 && Math.ceil(day_diff / 7) + "星期之前"; }

八十四、新颖的for写法

今日收到两种for循序的写法,感觉殊特,却又有可取之处,个中优点,请大家细细体会:

// 第一种: for (var i = 0, menu = null; menu = this.registry[i]; i++) { menu.initialize(); } // 第二种: //===================================================================== // IE win memory cleanup //===================================================================== if (window.attachEvent) { var cearElementProps = [ 'data', 'onmouseover', 'onmouseout', 'onmousedown', 'onmouseup', 'ondblclick', 'onclick', 'onselectstart', 'oncontextmenu' ]; window.attachEvent("onunload", function() { var el; for(var d = document.all.length;d--;){ el = document.all[d]; for(var c = cearElementProps.length;c--;){ el[cearElementProps[c]] = null; } } }); }

八十五、查找数组中的最小值比较简洁的实现方法

如题,

function smallest(arr){ return Math.min.apply(Math, arr); }

Powered by 《Secrets of the JavaScript Ninja》

八十六、JS中文十六进制编码

想避免中文编码的烦恼?可以用以下这两个方法,包准可以在纯ASCII环境JS中运行(例如,ASP的global.asa就是特例)。

/** * 想避免中文编码的烦恼?可以用以下这两个方法,包准可以在纯ASCII环境JS中运行(ASP的global.asa就是特例)。 * @param {String} * @return {String} */ var to16 = { on : function (str){ var arr = []; var hex; for (var i = 0 ; i < str.length ;i++) { hex = ("00" + str.charCodeAt(i).toString(16)).slice(-4); if(hex.length < 4){ // 宽度不一致 hex = '0' + hex; } arr.push(hex); } return "//u" + arr.join("//u"); } ,un : function (str) { return unescape(str.replace(////g, "%")); } };

八十七、最最最最最简单的JS继承方法

Prototype继承无误,但不是“最最最……”的。我始终认为,鉴于JS“基于对象”的语言特性,最最最最最简单的JS继承方法就是拷贝属性到某个对象身上,这样这个对象就有那个对象的一切能力啦,不是简单吗?就是那么地简单,娃哈哈。不笑了,代码如下:

/** * 拷贝对象。 * @dep 不要设为一个方法,而是直接写在逻辑过程中! * @param {Object} a destination * @param {Object} b source * @return {Object} a */ Object.apply = function(a, b){ for(var i in b)a[i] = b[i]; return a; }

八十八、觉得写for循环很烦?试试用js的函数搞掂~

看官应该可以自己体会吧?俺觉得缺点就是调试太困难了,每次都要进入函数内部,不爽。

/** * 遍历数组,可代替写循环。 * 如果传入一个非Array类型的参数,也会被自动转换为Array。 * 函数的返回值只会返回到这里,只强调函数的过程而不是函数的结果。 * 如果送入的函数被执行后返回false,表示将结束该次循环。 * @dep 调式极度不方便 * @param {Array} arr 要循环的数组。 * @param {Function} fn 执行的函数。 * @param {Object} scope 函数的作用域。 * @return {Array} 若遍历完毕则返回数组。若遇到中断则返回中断的那个元素。 */ Array.each = function(arr, fn, scope){ if(!arr.pop && !arr.shift)arr = [arr]; for(var i = 0, j = arr.length; i < j; i++){ if(fn.call(scope || obj.globalScope , arr[i], i, j, arr) === false){ break; return arr[i]; } } return arr; }

还可以列出多一个例子,原理嘛~换汤不换药~

/** * 循环。 * @param {Function} loopFn * @return {Function} */ Function.prototype.until = function(loopFn) { var self = this; return function(){ var result; while(!self.apply(this, arguments)){ result = loopFn.apply(this, arguments); } return result; }; }

八十九、函数式的判断?

FP大行其道,要在JS中贯彻FP到底也不是不能做到的。试试一个条件判断的逻辑,勿用if-else,怎么写?

/** * 条件判断。 * @param {Function} trueFn 判断为真时执行的函数。 * @param {Function} falseFn 判断为假时执行的函数。 * @return {Function} */ Function.prototype.split = function(trueFn, falseFn){ var self = this; return function(){ if(self.apply(this, arguments) === true){ return trueFn.apply(this, arguments); }else{ if(falseFn){ return falseFn.apply(this, arguments); }else{ return false; } } } };

九十、转换arguments真正的数组的快速方法

如题,

// 快速转换arguments为真正的数组 ;(function(){ var args = Array.prototype.slice.call(arguments, 0); // 试比较, 结果虽一样,但小弟的问题来了…… var args = [].concat(arguments); // []无中生有的new一个Array对象,而Array.prototype的相当于“静态方法”,不额外占用空间。 // 但Array.prototype.slice有两个“点”,JS中多一个“点”则慢不少…… // 应该怎么权衡呢? debugger; })(2,23,323);

九十一、Ext整合FCKEditor编辑器的例子

请到“JS堂”下载例子,打开demo.html即可观察例子。注意:

  • 必须在服务器上浏览,直接打开不能加载FCKEditor
  • 使用Ext.ux.FCKeditor对ExtJS的插件
  • FCKEditor版本不能太新,插件只支持FCKEditor v2.6
  • 可支持多个FCK实例在同一张页面中。

效果如下图:

 

每天一剂Ext良药(二)_第4张图片

九十二、交换两个变量的值另一种思路

一般这样写:

var foo = 1; var bar = 2; var temp = foo; foo = bar; bar = temp;

但又可以这样地写:

var a =1, b=2; foo = [bar, bar=foo][0]; // 没有使用到临时变量 // a = b+(b=a)*0 a = b + (b = a) * 0; foo = bar | (bar = foo) & 0;

九十三、解码JOSN的另一种用法

eval()的名声不好,臭名昭著。不用eval()换函数的写法也可以达到同样的效果:

// 解码JSON function decode(json) { return new Function("", "return " + json)(); }
呵呵 只是有些JS引擎(如AIR)的法眼会识破此伎俩,换汤不换药嘛~

九十四、如何在列表上面实现隔行换色?

/**
 * 隔行换色。
 */
function row(){
	var listComponent = Ext.fly("edk-listComponent");
	if(listComponent){
	    listComponent =  listComponent.select('li:even/div');
	    if(listComponent.addCls){
	        listComponent.addCls('evenRow');
	    }else{
	        listComponent.addClass('evenRow');
	    }
	}
}

你可能感兴趣的:(JavaScript,sql,function,ext,fckeditor,Constructor)