
2008年8月16日
一、理解Html DOM、Ext Element及Component
要学习及应用好Ext框架,需要理解Html DOM、Ext Element及Component三者的区别。
Ext是基于Web的富客户端框架,其完全是基于标准W3C技术构建设的,使用到的都是HTML、CSS、DIV等相关技术。Ext最杰出之处,是开发了一系列非常简单易用的控件及组件,我们只需要使用这些组件就能实现各种丰富多彩的UI的开发。
无论组件有多少配置属性、还是事件、方法等等,其最终都会转化为HTML在浏览器上显示出来,而每一个HTML页面都有一个层次分明的DOM树模型,浏览器中的所有内容都有相应的DOM对象,动态改变页面的内容,正是通过使用脚本语言来操作DOM对象实现。
仅仅有DOM是不够的,比如要把页面中的某一个节点移到其它位置,要给某一个节点添加阴影效果,要隐藏或显示某一个节点等,我们都需要通过几句javascript才能完成。因此,Ext在DOM的基础上,创建了Ext Element,可以使用Element来包装任何DOM,Element对象中添加了一系列快捷、简便的实用方法。
对于终端用户来说,仅仅有Element是不够的,比如用户要显示一个表格、要显示一棵树、要显示一个弹出窗口等。因此,除了Element以外,Ext还建立了一系列的客户端界面组件Component,我们在编程时,只要使用这些组件Componet即可实现相关数据展示及交互等,而Component是较高层次的抽象,每一个组件在渲染render的时候,都会依次通过Element、DOM来生成最终的页面效果。
在使用Ext开发的应用程序中,组件Component是最高层次的抽象,是直接给用户使用的,Ext Element是Ext的底层API,主要是由Ext或自定义组件调用的,而DOM是W3C标准定义的原始API,Ext的Element通过操作DOM来实现页面的效果显示。
在Ext中,组件渲染以后可以通过访问组件的el属性来得到组件对应的Element,通过访问Element的dom属性可以得到其下面的DOM对象。另外,我们可以通过通过Ext类的快捷方法getCmp、get、getDom等方法来得组件Component、Ext元素Element及DOM节点。比如:
var view=new Ext.Viewport();//创建了一个组件Component
view.el.setOpacity(.5);//调用Element的setOpacity方法
view.el.dom.innerHTML="Hello Ext";//通过Element的dom属性操作DOM对象
再看下面的代码:
var win=new Ext.Window({id:"win1",title:"我的窗口",width:200,height:200});
win.show();
var c=Ext.getCmp("win1");//得到组件win
var e=Ext.get("win1");//根据id得到组件win相应的Element
var dom=Ext.getDom("win1");//得到id为win1的DOM节点
二、熟悉ext组件体系
Ext2.0对整个框架进行了重构,最为杰出的是推出了一个以Component类为基础的组件体系,在Component类基础上,使用面向对象的方法,设计了一系列的组件及控件。因此,要能游刃有余地使用Ext,熟悉Ext组件体系是最基本的。
在《ExtJS实用开发指南》中,有如下面一幅组件图:
通过组件结构图我们可以一目了然的看出整个Ext组件继承及组成体系,当使用一个组件的时间,了解他的继承体系,这样可以便于我们掌握组件的各种特性。
三、掌握核心控件
控件其实也是组件,比如用于显示树信息的TreePanel、用于显示表格的GridPanel及EditorGridPanel,还有代表应用程序窗口的Ext.Window等都属于Ext控件。在使用Ext的时候,一定要掌握一些核心控件,特别是处于基类的控件。比如上面提到的几个控件,他们都是继承于面板Panel,所以我们要重点掌握面板这个核心控件的特性。比如面板由以下几个部分组成:一个顶部工具栏(tbar)、一个底部工具栏(bbar)、面板头部(header)、面板尾部(bottom)、面板主区域(body)几个部分组成。面板类中还内置了面板展开、关闭等功能,并提供一系列可重用的工具按钮使得我们可以轻松实现自定义的行为,面板可以放入其它任何容器中,面板本身是一个容器,他里面又可以包含各种其它组件。只要掌握了Panel的应用,那么学习TreePanel、Window等就会变得简单得多。
同样的道理,对于Ext的表单字段来说,不管是ComboBox,NumberField、还是DateField,他们其它都是Ext.form.Field类的子类,在他上面定义了表单字段的各种基本操作及特性。在学习使用表单字段组件时,一定要重点研究Field这个类,掌握他的主要方法、事件等,就能有助于更好的学习使用其它的字段。
四、学习及研究示例
由于javascript语言非常灵活,不像静态强类型语言(比如Java)那样有固定的代码设计模式,而往往是不同的人就有不同的编程风格。在实际应用开发中,只有见多识广,才能在自己的在脑中建立一个开发库。
学习别人的示例对于我们开发帮助会非常大,示例包括基本组件的应用、综合应用等多个方面。在此,简单推荐几个。
1、Ext官方示例,在ext项目下载包的examples目录中,包括各个控件的基本应用演示,同时还有一些比较复杂的组合示例,有简有繁,非常适合初学者认真研究。
2、Vifir推出的示例,Vifir推出的一些示例主要包括两类,一种是开源的示例应用,另外一种是针对VIP用户的实用示例。开源的示例主要是指wlr单用户blog系统,这个一个集合了前后台技术的ext综合示例,而针对VIP用户的实用示例则是可以作为开发骨架或扩展组件的示例。
3、其它示例,在ext社区中还有很多比较优秀的ext应用示例,有些只是一个应用演示,虽然没有提供源码下载,但我们可以直接下载引用的js文件来得到这些示例的ext应用代码,同样能取起到非常好的学习效果。
五、多运用
Ext看起来是非常简单的东西,稍有点编程知识的人,按照《ExtJS实用开发指南》中的入门指南,半小时就能学会使用Ext。然而,当准备使用Ext开发一个项目时,却不知道从何处入手,或者是在使用Ext的时候,出了一点小问题自己不知道该如何解决。编程是一门实践性的科学,仅仅靠看书、看别人写的代码是远远不够的,因此,必须多做实践才行,只有通过不断的练习,大量的使用,才能对Ext的组件特性、事件、事件处理机制以及与服务器端交互接口等深入的掌握,只有多做运用,深入了解ext的组件的工作原理及机制,才能编写出高级的Ext的应用。
六、熟读Ext项目的源代码
如果要想深入应用Ext,那么阅读Ext项目的源代码这是必不可少的环节,Ext的代码质量非常高,通过阅读他的代码我们可以更加深刻的了解javascript面向对象编程,Ext代码中包含了很多高级的js技巧以及设计模式。在使用Ext的过程中,我们经常根据项目的需要对Ext组件进行扩展,设计自己的组件或控件,而如何实现一个自定义的Ext组件,我们可以从Ext的各个组件源代码中找到答案。
Ext的源代码在Ext项目的source目录。读Ext源码,并不一定非要从某一个地方开始,而组件核心代码Component.js、容器组件代码Container.js、面板Panel.js等这些是必看的; core目录中的Element.js、Ext.js等也是必看的。当需要从一个控件进行扩展的时候,最好能简单看一看这个控件的源代码。
posted @ 2008-08-16 17:48 岁寒づ古枫 阅读(294) 评论(0)
编辑
PHP版破解QQ聊天纪
namespace Van.Utility.QQMsg
{
public enum QQMsgType
{
BIM, C2C, Group, Sys, Mobile, TempSession //Disc
}
class QQMsgMgr
{
private static readonly int s_MsgTypeNum = (int)QQMsgType.TempSession + 1;
private static readonly string[] s_MsgName = new string[] {
"BIMMsg", "C2CMsg", "GroupMsg", "SysMsg", "MobileMsg", "TempSessionMsg"
};
private IStorageWrapper m_Storage;
private byte[] m_Password;
private List<string>[] m_MsgList = new List<string>[s_MsgTypeNum];
public void Open(string QQID)
{
Open(QQID, null);
}
public void Open(string QQID, string QQPath)
{
if (QQPath == null)
{
using (Microsoft.Win32.RegistryKey reg = Microsoft.Win32.Registry.LocalMachine.OpenSubKey(@"Software\Tencent\QQ"))
{
QQPath = reg.GetValue("Install") as string;
}
if (QQPath == null) return;
}
for (int i = 0; i < m_MsgList.Length; ++i)
{
m_MsgList = new List<string>();
}
m_Storage = null;
m_Password = null;
m_Storage = new IStorageWrapper(QQPath + QQID + @"\MsgEx.db");
m_Password = QQMsgMgr.GetGlobalPass(m_Storage);
if (m_Password == null) m_Storage = null;
foreach (IBaseStorageWrapper.FileObjects.FileObject fileObject in m_Storage.foCollection)
{
if (fileObject.FileType == 1)
{
for (int i = 0; i < m_MsgList.Length; ++i)
{
if (fileObject.FilePath == s_MsgName)
{
m_MsgList.Add(fileObject.FileName);
}
}
}
}
}
public void OutputMsg()
{
for (int i = 0; i < s_MsgTypeNum; ++i)
{
OutputMsg((QQMsgType)i);
}
}
public void OutputMsg(QQMsgType type)
{
if (m_Storage == null) return;
if (m_Password == null) return;
int typeIndex = (int)type;
if (typeIndex < 0 || typeIndex >= s_MsgTypeNum)
{
throw new ArgumentException("Invalid QQMsgType", "type");
}
string filePath = s_MsgName[typeIndex] + "\\";
Directory.CreateDirectory(filePath);
foreach (string QQID in m_MsgList[typeIndex])
{
string fileName = filePath + QQID + ".msj";
OutputMsg(type, QQID, fileName);
}
}
public void OutputMsg(QQMsgType type, string QQID)
{
if (m_Storage == null) return;
if (m_Password == null) return;
int typeIndex = (int)type;
if (typeIndex < 0 || typeIndex >= s_MsgTypeNum)
{
throw new ArgumentException("Invalid QQMsgType", "type");
}
string filePath = s_MsgName[typeIndex] + "\\";
Directory.CreateDirectory(filePath);
string fileName = filePath + QQID + ".msj";
OutputMsg(type, QQID, fileName);
}
private void OutputMsg(QQMsgType type, string QQID, string fileName)
{
string msgPath = s_MsgName[(int)type] + QQID;
IList<byte[]> msgList = QQMsgMgr.DecryptMsg(m_Storage, msgPath, m_Password);
Encoding encoding = Encoding.GetEncoding(936);
using (FileStream fs = new FileStream(fileName, FileMode.Create))
{
using (StreamWriter sw = new StreamWriter(fs))
{
for (int i = 0; i < msgList.Count; ++i)
{
using (MemoryStream ms = new MemoryStream(msgList))
{
using (BinaryReader br = new BinaryReader(ms, Encoding.GetEncoding(936)))
{
#if false
fs.Write(msgList, 0, msgList.Length);
#else
int ticks = br.ReadInt32();
DateTime time = new DateTime(1970, 1, 1) + new TimeSpan(0, 0, ticks);
switch (type)
{
case QQMsgType.BIM:
case QQMsgType.C2C:
case QQMsgType.Mobile:
ms.Seek(1, SeekOrigin.Current);
break;
case QQMsgType.Group:
ms.Seek(8, SeekOrigin.Current);
break;
case QQMsgType.Sys:
ms.Seek(4, SeekOrigin.Current);
break;
case QQMsgType.TempSession: //?
ms.Seek(9, SeekOrigin.Current);
break;
}
if (type == QQMsgType.TempSession)
{
int gLen = br.ReadInt32();
string groupName = encoding.GetString(br.ReadBytes(gLen));
if (groupName.Length > 0) sw.WriteLine("{0}", groupName);
}
int nLen = br.ReadInt32();
string id = encoding.GetString(br.ReadBytes(nLen));
sw.WriteLine("{0}: {1}", id, time.ToString());
int cLen = br.ReadInt32();
string msg = encoding.GetString(br.ReadBytes(cLen));
msg.Replace("\n", Environment.NewLine);
sw.WriteLine(msg);
sw.WriteLine();
#endif
}
}
}
}
}
}
public void OutputFileList()
{
if (m_Storage == null) return;
Dictionary<string, long> dic = new Dictionary<string, long>();
foreach (IBaseStorageWrapper.FileObjects.FileObject fileObject in m_Storage.foCollection)
{
if (fileObject.FileType == 2 && fileObject.FileName == "Index.msj")
{
dic[fileObject.FilePath] = fileObject.Length / 4;
}
}
for (int i = 0; i < m_MsgList.Length; ++i)
{
Console.WriteLine("{0}", s_MsgName);
foreach (string ID in m_MsgList)
{
Console.WriteLine("\t{0}: {1}", ID, dic[s_MsgName + ID]);
}
}
}
private static IBaseStorageWrapper.FileObjects.FileObject GetStorageFileObject(IStorageWrapper iw, string path, string fileName)
{
foreach (IBaseStorageWrapper.FileObjects.FileObject fileObject in iw.foCollection)
{
if (fileObject.CanRead)
{
if (fileObject.FilePath == path && fileObject.FileName == fileName) return fileObject;
}
}
return null;
}
private static byte[] Decrypt(byte[] src, byte[] pass, long offset)
{
RedQ.QQCrypt decryptor = new RedQ.QQCrypt();
return decryptor.QQ_Decrypt(src, pass, offset);
}
private static IList<byte[]> DecryptMsg(IStorageWrapper iw, string path, byte[] pass)
{
List<byte[]> msgList = new List<byte[]>();
int num = 0;
int[] pos = null;
int[] len = null;
using (IBaseStorageWrapper.FileObjects.FileObject fileObject = GetStorageFileObject(iw, path, "Index.msj"))
{
if (fileObject == null) return msgList;
int fileLen = (int)fileObject.Length;
num = fileLen / 4;
pos = new int[num + 1];
using (BinaryReader br = new BinaryReader(fileObject))
{
for (int i = 0; i < num; ++i)
{
pos = br.ReadInt32();
}
}
}
using (IBaseStorageWrapper.FileObjects.FileObject fileObject = GetStorageFileObject(iw, path, "Data.msj"))
{
if (fileObject != null)
{
int fileLen = (int)fileObject.Length;
len = new int[num];
pos[num] = fileLen;
for (int i = 0; i < num; ++i)
{
len = pos[i + 1] - pos;
}
using (BinaryReader br = new BinaryReader(fileObject))
{
for (int i = 0; i < num; ++i)
{
fileObject.Seek(pos, SeekOrigin.Begin);
byte[] data = br.ReadBytes(len);
byte[] msg = Decrypt(data, pass, 0);
msgList.Add(msg);
}
}
}
}
return msgList;
}
private static byte[] GetGlobalPass(IStorageWrapper iw)
{
System.Security.Cryptography.MD5 md5 = System.Security.Cryptography.MD5.Create();
string QQID = "254614441";
byte[] dataID = new byte[QQID.Length];
for (int i = 0; i < QQID.Length; ++i) dataID = (byte)(QQID);
byte[] hashID = md5.ComputeHash(dataID);
IBaseStorageWrapper.FileObjects.FileObject fileObject = GetStorageFileObject(iw, "Matrix", "Matrix.db");
if (fileObject != null)
{
using (BinaryReader br = new BinaryReader(fileObject))
{
byte[] data = br.ReadBytes((int)fileObject.Length);
long len = data.Length;
if (len < 6 || data[0] != 0x51 || data[1] != 0x44) return null;
if (len >= 32768) return null;
bool bl = false;
int i = 6;
while (i < len)
{
bl = false;
byte type = data[i++];
if (i + 2 > len) break;
int len1 = data + data[i + 1] * 256;
byte xor1 = (byte)(data ^ data[i + 1]);
i += 2;
if (i + len1 > len) break;
for (int j = 0; j < len1; ++j) data[i + j] = (byte)(~(data[i + j] ^ xor1));
if (len1 == 3 && data == 0x43 && data[i + 1] == 0x52 && data[i + 2] == 0x4B)
{
bl = true;
}
i += len1;
if (type > 7) break;
if (i + 4 > len) break;
int len2 = data + data[i + 1] * 256 + data[i + 2] * 256 * 256 + data[i + 3] * 256 * 256 * 256;
byte xor2 = (byte)(data ^ data[i + 1]);
i += 4;
if (i + len2 > len) break;
if (type == 6 || type == 7)
{
for (int j = 0; j < len2; ++j) data[i + j] = (byte)(~(data[i + j] ^ xor2));
}
if (bl && len2 == 0x20)
{
byte[] dataT = new byte[len2];
for (int j = 0; j < len2; ++j) dataT[j] = data[i + j];
return Decrypt(dataT, hashID, 0);
}
i += len2;
}
if (i != len) return null;
}
}
return null;
}
}
}
posted @ 2008-08-16 17:33 岁寒づ古枫 阅读(2730) 评论(12)
编辑