dTree的分析和二次开发
来源:互联网 发布:蓝格珠宝软件 编辑:程序博客网 时间:2024/05/17 21:46
dTree是一个免费的JavaScript树形菜单,使用简单,界面制作的也很专业。
所谓“兵无常势,水无常形”,不同的项目需求,造成菜单树的各种变化,因此在介绍dTree的同时,本文着重讲述如何改造dTree,以达到为不同项目所用的目的。
dTree 分析
dTree的使用非常简单,在下载的dTree压缩文件中(2.05),要用的只有三个:
1. dtree.js : dtree功能脚本
2. dtree.css : 样式文件
3. img文件夹 : 存放dtree使用的图标,参看下图:
很容易就可以编写出类似上面的dtree菜单树,源代码如下:
- <html>
- <head>
- <link rel="StyleSheet" href="dtree.css" type="text/css" />
- <script type="text/javascript" src="dtree.js"></script>
- </head>
- <body>
- <script type="text/javascript" >
- <!–
- d = new dTree( ‘d’ ) ; //创建树,名称为’d'(注意和树的对象变量名称要一致)
- d.add ( 0 ,-1 ,‘My example tree’ ) ; //在树中增加节点。节点id是0,父节点是-1(根节点),节点文字’My example tree’
- d.add ( 1 ,0 ,‘Node 1′ ,‘default.html’ ) ; //根节点的子节点(父节点是0),’default.html’表示节点链接(鼠标点击页面跳转url)
- d.add ( 2 ,0 ,‘Node 2′ ,‘default.html’ ) ;
- d.add ( 3 ,1 ,‘Node 1.1′ ,‘default.html’ ) ;
- d.add ( 4 ,0 ,‘Node 3′ ,‘default.html’ ) ;
- d.add ( 5 ,3 ,‘Node 1.1.1′ ,‘default.html’ ) ;
- d.add ( 6 ,5 ,‘Node 1.1.1.1′ ,‘default.html’ ) ;
- d.add ( 7 ,0 ,‘Node 4′ ,‘default.html’ ) ;
- d.add ( 8 ,1 ,‘Node 1.2′ ,‘default.html’ ) ;
- d.add ( 9 ,0 ,‘My Pictures’ ,‘default.html’ ,‘Pictures I/’ ve taken over the years’ ,” ,” ,‘img/imgfolder.gif’ ) ;//’Pictures I/’ve taken over the years’是链接title,指定图标
- d.add ( 10 ,9 ,‘The trip to Iceland’ ,‘default.html’ ,‘Pictures of Gullfoss and Geysir’ ) ;
- d.add ( 11 ,9 ,‘Mom/’ s birthday’ ,‘default.html’ ) ;
- d.add ( 12 ,0 ,‘Recycle Bin’ ,‘default.html’ ,” ,” ,‘img/trash.gif’ ) ;
- document.write ( d) ; //输出dtree的html(显示)
- //–>
- </script>
- </body>
- </html>
分析dtree.js,在dTree中只有两个结构:”节点”和”树”,dTree的所有功能和构造都在于这两个结构的属性和行为中,Node比较简单,只包含节点的基本属性和一个构造方法,所以对dTree的分析和研究的重点可放在dTree结构中。
- id : int 每个节点都有唯一ID,增加节点时需要手工定义一个ID。
- pid : int 父节点ID,根节点的父节点是-1。
- name : String 节点名称(显示名字)
- url : String 节点URL(鼠标点击跳转地址)
- title : String 鼠标移动到节点上显示的文字
- target : String 页面跳转所在的frame
- icon : String 节点关闭时显示的图标地址
- iconOpen : String 节点打开时显示的图标地址
- _io : boolean 节点是否已打开,默认值false。
- _is : boolean 节点是否被选中,默认值false。
- _ls : boolean 是否是最后一个节点,默认值false。
- _hc : boolean 是否有子节点,默认值false。
- _ai : int 在树的节点数组中的下标(位置),默认值0。
- _p : Node 父节点对象,默认值null。
- Node(id, pid, name, url, title, target, icon, iconOpen, open) : void 构造方法,创建一个节点对象。open对应_io,表示节点是否已经打开。
节点类图
- obj : String 树的名称,在创建树时定义。
- aNodes : Node[] 树中的节点数组。
- aIndent : [] 数组。
- root : Node 根节点。
- selectedNode : Node 当前选择的节点。
- selectedFound : boolean 是否有选中节点,默认false。
- completed : boolean 树构建html是否已完成完成,默认false。
- config : Hash数组 树的配置
- target: 设置所有节点的target,默认null
- folderLinks: 目录节点是否可以有链接,默认true
- useSelection: 节点是否可以被选择(高亮),默认true
- useCookies: 设置使用cookies保存树的状态,默认true
- useLines: 是否显示路径点线,默认true
- useIcons: 是否显示图标,默认true
- useStatusText: 是否在状态栏输出节点文字(替换原来的url显示),默认false
- closeSameLevel: 是否自动关闭兄弟节点(当打开本节点时),注意设置true时,openAll()和closeAll()不能工作,默认false
- inOrder: 如果父节点总是在子节点之前加入树,设置true有更好的效率,默认false
- icon : Hash数组 图标
- root: 根,默认'img/base.gif'
- folder: 关闭的文件夹,默认'img/folder.gif'
- folderOpen: 打开的文件夹,默认'img/folderOpen.gif'
- node: 文件,默认'img/page.gif'
- empty: 空,默认'img/empty.gif'
- line: 竖线,默认'img/line.gif'
- join: 丁线,默认'img/join.gif'
- joinBottom: 直角线,默认'img/joinbottom.gif'
- plus: 加号丁线,默认'img/plus.gif'
- plusBottom: 加号直角线,默认'img/plusbottom.gif'
- minus: 减号丁线,默认'img/minus.gif'
- minusBottom: 减号直角线,默认'img/minusbottom.gif'
- nlPlus: 无线加号,默认'img/nolines_plus.gif'
- nlMinus: 无线减号,默认'img/nolines_minus.gif'
- dTree(objName) : void 构造方法,创建树对象。objName: 树名称。
- add(id, pid, name, url, title, target, icon, iconOpen, open) : void 在树中增加一个节点,节点对象添置到aNodes数组末尾。参数open表示节点是否已经打开。
- openAll() : void 打开树中所有节点。此方法由oAll方法实现。
- closeAll() : void 关闭树中所有节点。此方法由oAll()方法实现。
- toString() : String 构建树的html。此方法主要由addNode()方法实现。返回:html。
- addNode(pNode) : String 构建pNode的所有子节点的html。参数pNode: 父节点对象。返回:html。
- node(node, nodeId) : String 构建node的html。参数node: 节点对象;nodeId: 节点在节点数组aNodes中的位置。返回:html。
- indent(node, nodeId) : String 构建node前面的空格、点线、加减号的html。参数node: 节点对象;nodeId: 节点在节点数组aNodes中的位置。返回:html。
- setCS(node) : void 检查并设置:1. node节点是否有子节点; 2. node节点是否是节点数组aNodes中的最后一个。参数node: 节点对象。
- getSelected() : int 从cookies中获取已选中的节点,返回:节点id或null(没有选中任何节点)。
- s(id) : void 鼠标点击节点发生的动作,高亮选择的节点,并记录在cookies中。参数id: 节点在节点数组aNodes中的位置
- o(id) : void 鼠标点击+-图标发生的动作,打开或关闭指定节点,并记录在cookies中。参数id: 节点在节点数组aNodes中的位置
- oAll(status) : void 打开或关闭所有节点,并将状态记录在cookies中。参数status:true打开 fasle关闭
- openTo(nId, bSelect, bFirst) : void 打开指定节点,并将状态记录在cookies中。参数nId:节点ID或节点在节点数组aNodes中的位置;bSelect:true-打开同时被选中,false-打开不被选中;bFirst:true-nId是在节点数组aNodes中的位置,false-nId是节点ID。
- closeLevel(node) : void 关闭和node同级别以及他们的下级的所有节点。参数node:节点对象。
- closeAllChildren(node) : void 关闭node的所有子节点。参数node:节点对象。
- nodeStatus(status, id, bottom) : void 改变节点的状态(关闭 或 打开)。参数status: 要设置的状态(true:打开 false:关闭);id: 节点ID;bottom: true-是最后一个节点。
- clearCookie() : void 清除cookies。
- setCookie(cookieName, cookieValue, expires, path, domain, secure) : void 记录入cookies。
- getCookie(cookieName) : String 从cookies中读取。
- updateCookie() : void 将所有打开的节点ID记录在cookies中。
- isOpen(id) : boolean 根据cookies的记录,判断一个节点是已经打开。参数id:节点id
树类图
dTree的工作原理
类似dTree这样的动态的客户端web插件,实现起来基本离不开xhtml和javascript,用一段简单的代码来探索一下dTree的工作原理:
- <html>
- <head>
- <link rel="StyleSheet" href="dtree.css" type="text/css" />
- <script type="text/javascript" src="dtree.js"></script>
- </head>
- <body>
- <script type="text/javascript" >
- <!--
- d = new dTree( 'd' ) ; //创建树,名称为'd'
- d.add ( 0 ,-1 ,'根节点' ) ;
- d.add ( 1 ,0 ,'节点 1' ,'node1.html' ) ;
- d.add ( 2 ,0 ,'节点 2' ,'node2.html' ) ;
- d.add ( 3 ,1 ,'节点 1.1' ,'node1_1.html' ) ;
- d.add ( 4 ,3 ,'节点 1.1.1' ,'node1_1_1.html' ) ;
- document.write ( d) ;
- function show( )
- {
- alert ( d) ;
- }
- //-->
- </script>
- <input type="button" value="显示html" onclick="show()">
- </body>
- </html>
显示的“树”如下图:
点击下方的“显示html”按钮,会在alert对话框中显示整个树的html代码,整理后如下:
- <div class ="dtree" >
- <div class ="dTreeNode" >
- <img id ="id0" src ="img/base.gif" alt ="" /> 根节点</a>
- </div>
- <div id ="dd0" class ="clip" style ="display:block;" >
- <div class ="dTreeNode" >
- <a href ="javascript: d.o(1);" > <img id ="jd1" src ="img/minus.gif" alt ="" /> </a>
- <img id ="id1" src ="img/folderopen.gif" alt ="" />
- <a href ="javascript: d.o(1);" class ="node" > 节点 1</a>
- </div>
- <div id ="dd1" class ="clip" style ="display:block;" >
- <div class ="dTreeNode" >
- <img src ="img/line.gif" alt ="" />
- <a href ="javascript: d.o(3);" > <img id ="jd3" src ="img/minusbottom.gif" alt ="" /> </a>
- <img id ="id3" src ="img/folderopen.gif" alt ="" />
- <a href ="javascript: d.o(3);" class ="node" > 节点 1.1</a>
- </div>
- <div id ="dd3" class ="clip" style ="display:block;" >
- <div class ="dTreeNode" >
- <img src ="img/line.gif" alt ="" />
- <img src ="img/empty.gif" alt ="" />
- <img src ="img/joinbottom.gif" alt ="" />
- <img id ="id4" src ="img/page.gif" alt ="" />
- <a id ="sd4" class ="node" href ="node1_1_1.html" onclick ="javascript: d.s(4);" > 节点 1.1.1</a>
- </div>
- </div>
- </div>
- <div class ="dTreeNode" >
- <img src ="img/joinbottom.gif" alt ="" />
- <img id ="id2" src ="img/page.gif" alt ="" />
- <a id ="sd2" class ="node" href ="node2.html" onclick ="javascript: d.s(2);" > 节点 2</a>
- </div>
- </div>
- </div>
仔细观察,树中每个节点的html构造是相似的:
- <!-- 根节点 -->
- <div class ="dTreeNode" >
- <img id ="id0" src ="img/base.gif" alt ="" /> 根节点</a>
- </div>
- <div id ="dd0" class ="clip" style ="display:block;" >
- ......
- </div>
- <!-- 节点 1 -->
- <div class ="dTreeNode" >
- <a href ="javascript: d.o(1);" > <img id ="jd1" src ="img/minus.gif" alt ="" /> </a>
- <img id ="id1" src ="img/folderopen.gif" alt ="" />
- <a href ="javascript: d.o(1);" class ="node" > 节点 1</a>
- </div>
- <div id ="dd1" class ="clip" style ="display:block;" >
- ......
- </div>
- <!-- 节点 1.1 -->
- <div class ="dTreeNode" >
- <img src ="img/line.gif" alt ="" />
- <a href ="javascript: d.o(3);" > <img id ="jd3" src ="img/minusbottom.gif" alt ="" /> </a>
- <img id ="id3" src ="img/folderopen.gif" alt ="" />
- <a href ="javascript: d.o(3);" class ="node" > 节点 1.1</a>
- </div>
- <div id ="dd3" class ="clip" style ="display:block;" >
- ......
- </div>
- <!-- 节点 1.1.1 -->
- <div class ="dTreeNode" >
- <img src ="img/line.gif" alt ="" />
- <img src ="img/empty.gif" alt ="" />
- <img src ="img/joinbottom.gif" alt ="" />
- <img id ="id4" src ="img/page.gif" alt ="" />
- <a id ="sd4" class ="node" href ="node1_1_1.html" onclick ="javascript: d.s(4);" > 节点 1.1.1</a>
- </div>
- <!-- 节点 2 -->
- <div class ="dTreeNode" >
- <img src ="img/joinbottom.gif" alt ="" />
- <img id ="id2" src ="img/page.gif" alt ="" />
- <a id ="sd2" class ="node" href ="node2.html" onclick ="javascript: d.s(2);" > 节点 2</a>
- </div>
每个节点由两个<div>组成,第一个div (class="dTreeNode")描述当前节点,如节点显示文字、节点图标、图标前的加减号、连线等;第二个div (class="clip")描述当前节点的子节点(包括子节点的子节点),注意div的样式 style="display:block;","block"表示显示div,也就是显示子节点,如果样式为 style="display:none;",则隐藏div,也就隐藏了子节点,d.o()函数控制display样式的变换,也就相应实现了子节点的打开和关闭。
"节点 1.1.1" 和 "节点 2" 没有子节点,所以没有第二个<div>。
在dTree中,树中的节点是一次生成的,但在一些应用场景中,节点数非常大,比如我国的行政区划中省、市县两级的数量就超千个,一次性的生成dTree树非常耗资源,速度也慢。针对这种情况需要“异步”构建树,比如在页面上先生成省、自治区的一级节点,当用鼠标点开某个“省”节点时,实时从后台获得该省下级的市县节点。
下面就一步步的完成这个对dTree的改造需求。
改造原则
我在这里要说明的是:不建议对dTree大改,因为改的越多风险越大,毕竟我们只是dTree的使用者,而不是开发者,特别在项目时间紧、压力大的环境中,迅速打造一个能用、稳定的控件尤其重要。
创建一级节点
这里的行政区划不规范,和国家规定的有出入,但作为示例程序比较好理解,从我所在的省份“陕西省”开始,省的下级有“陕北”、“关中”、“陕南”三个子集。
- d = new dTree(’d'); //创建树,名称为’d’
- d.add(0,-1,’陕西省’);
- d.add(1,0,’陕北’);
- d.add(2,0,’关中’);
- d.add(3,0,’陕南’);
- document.write(d);
生成的页面显示:
在dTree中,如果一个节点没有子集,它的前面不会出现“+”图标,我们希望在红色标记处形有“+”或“-”图标,这样就可以动态的从后台获取他们的子集。查看d.add()函数的实现代码:
- dTree.prototype.add = function(id, pid, name, url, title, target, icon, iconOpen, open) {
- //增加到节点数组的末尾
- this.aNodes[this.aNodes.length] = new Node(id, pid, name, url, title, target, icon, iconOpen, open);
- };
在add函数中,new了一个节点对象,aNodes是dTree中的节点数组,下标“this.aNodes.length”是数组末尾的下一个,表示在数组最后增加一个节点。将上面的代码改动一下:
- d = new dTree(’d');
- d.add(0,-1,’陕西省’);
- //陕北
- var shanbei = new Node(1,0,’<input type=/"checkbox/" name=/"where/" value=/"1/">陕北’);
- shanbei._hc = true; //有子节点
- d.aNodes[d.aNodes.length] = shanbei; //加入到树
- //关中
- var guanzhong = new Node(2,0,’<input type=/"checkbox/" name=/"where/" value=/"2/">关中’);
- guanzhong._hc = true;
- d.aNodes[d.aNodes.length] = guanzhong;
- //陕南
- var shannan = new Node(3,0,’<input type=/"checkbox/" name=/"where/" value=/"3/">陕南’);
- shannan._hc = true;
- d.aNodes[d.aNodes.length] = shannan;
- document.write(d);
先new出节点对象,将对象的”_hc”属性置为true,表示有子节点,形成的页面显示如下(手工点开了“关中”节点):
点击“显示html”按钮,观察一下树的html结构:
- <div class ="dtree" >
- <div class ="dTreeNode" >
- <img id ="id0" src ="img/base.gif" alt ="" /> 陕西省</a>
- </div>
- <div id ="dd0" class ="clip" style ="display:block;" >
- <div class ="dTreeNode" >
- <a href ="javascript: d.o(1);" > <img id ="jd1" src ="img/plus.gif" alt ="" /> </a>
- <img id ="id1" src ="img/folder.gif" alt ="" />
- <a href ="javascript: d.o(1);" class ="node" > <input type ="checkbox" name ="where" value ="1"> 陕北</a>
- </div>
- <div id ="dd1" class ="clip" style ="display:none;" > </div>
- <div class ="dTreeNode" > <a href ="javascript: d.o(2);" >
- <img id ="jd2" src ="img/minus.gif" alt ="" /> </a>
- <img id ="id2" src ="img/folderopen.gif" alt ="" />
- <a href ="javascript: d.o(2);" class ="node" > <input type ="checkbox" name ="where" value ="2"> 关中</a>
- </div>
- <div id ="dd2" class ="clip" style ="display:block;" > </div>
- <div class ="dTreeNode" >
- <a href ="javascript: d.o(3);" > <img id ="jd3" src ="img/plusbottom.gif" alt ="" /> </a>
- <img id ="id3" src ="img/folder.gif" alt ="" />
- <a href ="javascript: d.o(3);" class ="node" > <input type ="checkbox" name ="where" value ="3"> 陕南</a>
- </div>
- <div id ="dd3" class ="clip" style ="display:none;" > </div>
- </div>
- </div>
“关中”有子节点div标签,<div id=”dd2″ class=”clip” style=”display:block;”></div>,但没有内部子节点内容。
动态获取下级节点
节点的打开和关闭是由d.o()函数控制的,下来需要对d.o()函数做点小改动,先观察o函数的原始代码(我加上了注释):
- //———————————
- // dTree对象的o()方法
- // 打开或关闭指定节点
- // 参数id: 节点ID
- //———————————
- dTree.prototype.o = function(id) {
- //id对应的节点对象
- var cn = this.aNodes[id];
- //html变化
- this.nodeStatus(!cn._io, id, cn._ls);
- //open状态反转
- cn._io = !cn._io;
- //关闭同级别节点
- if (this.config.closeSameLevel) this.closeLevel(cn);
- //状态更新保存在cookies
- if (this.config.useCookies) this.updateCookie();
- };
下面是改动后的代码:
- //———————————
- // dTree对象的o()方法
- // 打开或关闭指定节点
- // 参数id: 节点ID
- //———————————
- dTree.prototype.o = function(id) {
- //示例程序只处理“关中”的子集
- if (id == 2){
- //子节点标签, “关中”子节点div的id是"dd2"
- var subDIV = document.getElementById("dd" + id);
- //判断子节点标签是否有内容,如果没有内容就从“后台”动态获取,
- //如果有内容则跳过,这样只在第一次打开节点时获取“后台”数据。
- if(subDIV != null && !subDIV.hasChildNodes())
- {
- //一般通过Ajax从后台获取子集信息,示例程序省略了。
- //假定从后台获取“关中”的子节点信息为:
- // 有两个子节点:“西安”节点id=5,有子节点;“咸阳”id=6,无子节点(叶子节点)
- //构造西安节点
- var xian = new Node(5,id,’<input type=/"checkbox/" name=/"where/" value=/"5/">西 安’);
- xian._hc = true; //有子节点
- this.aNodes[this.aNodes.length] = xian; //加入到树
- //构造咸阳节点
- var xianyang = new Node(6,id,’<input type=/"checkbox/" name=/"where/" value=/"6/">咸阳’);
- xianyang._hc = false; //无子节点
- this.aNodes[this.aNodes.length] = xianyang; //加入到树
- }
- }
- //id对应的节点对象
- var cn = this.aNodes[id];
- //html变化
- this.nodeStatus(!cn._io, id, cn._ls);
- //open状态反转
- cn._io = !cn._io;
- //关闭同级别节点
- if (this.config.closeSameLevel) this.closeLevel(cn);
- //状态更新保存在cookies
- if (this.config.useCookies) this.updateCookie();
- };
o函数中增加的的代码模拟了从后台获得“关中”子节点,在一般的应用中通常是通过Ajax技术来获取动态内容,Ajax的实现种类很多,所以这里只模拟而不演示具体的。
不论从后台通过何种技术来动态获取,获取信息必须要包括:
1. 子节点的ID
2. 子节点的名称
3. 子节点是否有下级
20-28行,根据从“后台”获得的子节点信息,在树中添加“西安”和“咸阳”两个节点,但遗憾的是,点开“关中”节点时并没有出现预想的状况,和o函数修改前没什么变化。
同步更新DOM
点击“显示html”按钮,在alret对话框中“关中”子节点的<div>中已经出现了“西安”和“咸阳”的标签代码,页面不响应是因为dTree的实现是基于html的,而不是基于DOM的,当语句 document.write(d); 将树html输出给浏览器后,再去改变”d”的内容,浏览器是不响应的,要达到我们的目的,需要一点技巧:
- <html>
- <head>
- <link rel="StyleSheet" href="dtree.css" type="text/css" />
- <script type="text/javascript" src="dtree.js"></script>
- <script type="text/javascript" >
- <!–
- function show( )
- {
- alert ( d.toString ( ) ) ;
- }
- //–>
- </script>
- </head>
- <body>
- <div id="mydTree">
- <script type="text/javascript" >
- <!–
- d = new dTree( ‘d’ ) ;
- d.add ( 0 ,-1 ,‘陕西省’ ,null ,null ,null ,‘img/globe.gif’ ) ;
- //陕北
- var shanbei = new Node( 1 ,0 ,‘<input type=/” checkbox/” name=/” where/” value=/” 1/” >陕北’ ) ;
- shanbei._hc = true ; //有子节点
- d.aNodes [ d.aNodes .length ] = shanbei; //加入到树
- //关中
- var guanzhong = new Node( 2 ,0 ,‘<input type=/” checkbox/” name=/” where/” value=/” 2/” >关中’ ) ;
- guanzhong._hc = true ;
- d.aNodes [ d.aNodes .length ] = guanzhong;
- //陕南
- var shannan = new Node( 3 ,0 ,‘<input type=/” checkbox/” name=/” where/” value=/” 3/” >陕南’ ) ;
- shannan._hc = true ;
- d.aNodes [ d.aNodes .length ] = shannan;
- document.write ( d) ;
- //–>
- </script>
- </div>
- <input type="button" value="显示html" onclick="show()">
- </body>
在dTree输出的外面包了一层div标签,就是那个 id=”mydTree” 的div标签,然后在o函数中增加一句:
- ……
- //构造咸阳节点
- var xianyang = new Node(6,id,’<input type=/"checkbox/" name=/"where/" value=/"6/">咸阳’);
- xianyang._hc = false; //无子节点
- this.aNodes[this.aNodes.length] = xianyang; //加入到树
- //同步修改DOM
- document.getElementById("mydTree").innerHTML = this.toString();
- }
- }
- //id对应的节点对象
- var cn = this.aNodes[id];
- ……
至此,完成“异步”dTree树的改造,页面显示效果如下:
以上代码,通过了Firefox3.5和IE8.0的测试。
原文的网址见:http://programmerdigest.cn/2009/12/607.html
- dTree的分析和二次开发
- dTree的分析和二次开发(上)
- dTree的分析和二次开发,ajax加载dtree节点(下)(转)
- dtree的使用和扩展
- 关于对dtree的详细分析
- 动态生成dTree和dTree传值
- 静态的dtree改编成动态dtree
- ecshop二次开发 结构分析和代码研究
- dtree的checkbox
- DTree的BUG解决方法
- dTree的使用
- DTree 的相关资料
- dtree的使用
- 带checkbox的dtree
- dtree的使用
- DTree的用法
- Dtree的使用
- dtree的使用
- servlet filters 介绍和使用
- 简单的URL重写
- SQL 修改排序规则
- 掌握ADO.NET的十个热门技巧
- 《ASP.NET本质论》视图状态 ViewState
- dTree的分析和二次开发
- java 2-6
- Android多版本兼容示例
- 深入浅出Linux设备驱动之字符设备驱动程序
- 3G之Android学习第一章节<<开发环境搭建>>
- 直接修改别人jar包里面的class文件 工具:jclasslib
- php输出脚本压缩
- mysql Packets larger than max_allowed_packet are not allowed
- 开发者需知:优秀程序设计的18大原则