<?xml version="1.0" encoding="gb2312"?>
<rss version="2.0">
<channel>
<title><![CDATA[miky的天空]]></title>
        <image>
        <title>http://hi.baidu.com</title>
        <link>http://hi.baidu.com</link>
        <url>http://img.baidu.com/img/logo-hi.gif</url>
        </image>
<description><![CDATA[我是miky，欢迎光临~~~~]]></description>
<link>http://hi.baidu.com/mikyliang</link>
<language>zh-cn</language>
<generator>www.baidu.com</generator>
<ttl>5</ttl>


<item>
        <title><![CDATA[mysql视图简介]]></title>
        <link><![CDATA[http://hi.baidu.com/mikyliang/blog/item/b464dc80ea92c5dd9123d9ab.html]]></link>
        <description><![CDATA[
		
		<div class="articleContent">
<p>一． 视图概述<br>
<br>
视图是一个虚拟表，其内容由查询定义。同真实的表一样，视图包含一系列带有名称的列和行数据。但是，视图并不在数据库中以存储的数据值集形式存在。行和列数据来自由定义视图的查询所引用的表，并且在引用视图时动态生成。<br>
<br>
对其中所引用的基础表来说，视图的作用类似于筛选。定义视图的筛选可以来自当前或其它数据库的一个或多个表，或者其它视图。通过视图进行查询没有任何限制，通过它们进行数据修改时的限制也很少。<br>
<br>
视图是存储在数据库中的查询的sql 语句，它主要出于两种原因：安全原因，视图可以隐藏一些数据，如：社会保险基金表，可以用视图只显示姓名，地址，而不显示社会保险号和工资数等，另一原因是可使复杂的查询易于理解和使用。<br>
<br>
<br>
　　视图：查看图形或文档的方式。<br>
<br>
<br>
　　视图是从一个或多个表或视图中导出的表，其结构和数据是建立在对表的查询基础上的。和表一样，视图也是包括几个被定义的数据列和多个数据行，但就本质而言这些数据列和数据行来源于其所引用的表。<br>
<br>
<br>
　　所以视图不是真实存在的基础表而是一张虚表，视图所对应的数据并不实际地以视图结构存储在数据库中，而是存储在视图所引用的表中。<br>
<br>
<br>
　　视图一经定义便存储在数据库中，与其相对应的数据并没有像表那样又在数据库中再存储一份，通过视图看到的数据只是存放在基本表中的数据。对视图的操作与对表的操作一样，可以对其进行查询、修改(有一定的限制)、删除。<br>
<br>
<br>
　　当对通过视图看到的数据进行修改时，相应的基本表的数据也要发生变化，同时，若基本表的数据发生变化，则这种变化也可以自动地反映到视图中。<br>
<br>
<br>
　　视图有很多优点，主要表现在：<br>
<br>
<br>
　　&#8226;视点集中<br>
<br>
<br>
　　&#8226;简化操作<br>
<br>
<br>
　　&#8226;定制数据<br>
<br>
<br>
　　&#8226;合并分割数据<br>
<br>
<br>
　　&#8226;安全性<br>
<br>
二． 创建视图&mdash;&mdash;create view<br>
<br>
1. 语法<br>
<br>
create [or replace] [algorithm = {undefined | merge | temptable}] view [db_name.]view_name [(column_list)] as select_statement [with [cascaded | local] check option]通过该语句可以创建视图，若给定了[or replace]，则表示当已具有同名的视图时，将覆盖原视图。select_statement是一个查询语句，这个查询语句可从表或其它的视图中查询。视图属于数据库，因此需要指定数据库的名称，若未指定时，表示在当前的数据库创建新视图。<br>
<br>
表和数据库共享数据库中相同的名称空间，因此，数据库不能包含相同名称的表和视图，并且，视图的列名也不能重复。<br>
<br>
2. 使用举例<br>
<br>
eg. 本例创建一个产品表（product）和一个购买记录表（purchase），再通过视图purchase_detail查询出购买的详细信息。<br>
<br>
create table product<br>
<br>
(<br>
<br>
product_id int not null,<br>
<br>
name varchar(50) not null,<br>
<br>
price double not null<br>
<br>
);<br>
<br>
insert into product values(1, 'apple ', 5.5);<br>
<br>
create table purchase<br>
<br>
(<br>
<br>
id int not null,<br>
<br>
product_id int not null,<br>
<br>
qty int not null default 0,<br>
<br>
gen_time datetime not null<br>
<br>
);<br>
<br>
insert into purchase values(1, 1, 10, now());<br>
<br>
create view purchase_detail as select product.name as name, product .price as price, purchase.qty as qty, product .price * purchase.qty as total_value from product, purchase where product.product_id = purchase.product_id;<br>
<br>
创建成功后，输入：select * from purchase_detail;<br>
<br>
运行效果如下：<br>
<br>
+-------+-------+-----+-------------+<br>
<br>
| name | price | qty | total_value |<br>
<br>
+-------+-------+-----+-------------+<br>
<br>
| apple | 5.5 | 10 | 55 |<br>
<br>
+-------+-------+-----+-------------+<br>
<br>
1 row in set (0.01 sec)<br>
<br>
3. 注意事项<br>
<br>
创建视图存在如下注意事项：<br>
<br>
（1） 运行创建视图的语句需要用户具有创建视图（crate view）的权限，若加了[or replace]时，还需要用户具有删除视图（drop view）的权限；<br>
<br>
（2） select语句不能包含from子句中的子查询；<br>
<br>
（3） select语句不能引用系统或用户变量；<br>
<br>
（4） select语句不能引用预处理语句参数；<br>
<br>
（5） 在存储子程序内，定义不能引用子程序参数或局部变量；<br>
<br>
（6）在定义中引用的表或视图必须存在。但是，创建了视图后，能够舍弃定义引用的表或视图。要想检查视图定义是否存在这类问题，可使用check table语句；<br>
<br>
（7） 在定义中不能引用temporary表，不能创建temporary视图；<br>
<br>
（8） 在视图定义中命名的表必须已存在；<br>
<br>
（9） 不能将触发程序与视图关联在一起；<br>
<br>
（10） 在视图定义中允许使用order by，但是，如果从特定视图进行了选择，而该视图使用了具有自己order by的语句，它将被忽略。<br>
<br>
三． 修改视图&mdash;&mdash;alter view<br>
<br>
1. 语法<br>
<br>
alter [algorithm = {undefined | merge | temptable}] view view_name [(column_list)] as select_statement [with [cascaded | local] check option]该语句用于更改已有视图的定义。其语法与create view类似。<br>
<br>
2. 使用举例<br>
<br>
eg. 将上一小节中中创建的视purchase_detail进行修改，去掉qty列，语句如下：<br>
<br>
alter view purchase_detail as select product.name as name, product .price as price, product .price * purchase.qty as total_value from product, purchase where product.product_id = purchase.product_id;</p>
</div> <a href="http://hi.baidu.com/mikyliang/blog/item/b464dc80ea92c5dd9123d9ab.html">阅读全文</a>
		
		<br/><b>类别：</b><a href="http://hi.baidu.com/mikyliang/blog/category/Mysql">Mysql</a>&nbsp;<a href="http://hi.baidu.com/mikyliang/blog/item/b464dc80ea92c5dd9123d9ab.html#comment">查看评论</a>]]></description>
        <pubDate>2009-11-24  12:09</pubDate>
        <category><![CDATA[Mysql]]></category>
        <author><![CDATA[mikyliang]]></author>
		<guid>http://hi.baidu.com/mikyliang/blog/item/b464dc80ea92c5dd9123d9ab.html</guid>
</item>

<item>
        <title><![CDATA[基于squid面向apache作反向代理的php程序设计技巧]]></title>
        <link><![CDATA[http://hi.baidu.com/mikyliang/blog/item/890a17e9316e4535b80e2df7.html]]></link>
        <description><![CDATA[
		
		squid 已经不再仅仅是一个 proxy server了，越来越多的站点采用 squid 作 <br>
前端服务，后方运行着若干台真正的 web server(apache)在服务... (注: 就算只 <br>
有一台服务器, 也可以同时安装squid +apache一起服务)，squid 本身强劲的缓存 <br>
设计大大提升 web 效率。 <br>
<br>
&nbsp;&nbsp;&nbsp;&nbsp; squid, apache 的配置安装均不是本文的重点，在此也不详述。一般情况下这 <br>
些缓存设计都擅长于静态网页或小图片或小文件等，而对于较为复杂的动态页面， <br>
作这样的缓存均可能带来用户浏览效果的不实时，往往导致后端页面更新了前端却 <br>
还没有及时刷新，非常不爽。 <br>
<br>
&nbsp;&nbsp;&nbsp;&nbsp; 其实在 php 脚本中， 结合 HTTP 标准头中有2个重要的标签可以很好的解决 <br>
这个困扰。即服务端发送的 Last-Modifed 和 客户端发送的 If-Modified-From 。 <br>
<br>
&nbsp;&nbsp;&nbsp;&nbsp; 带 cache 的 squid 反向代理的工作关系流程图大致如下： <br>
<br>
<pre><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 返回给用户
<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; +--------------------------------------------+
<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; |&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; (有效)|
<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; \|&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 发出请求&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; |\
<br>&nbsp;&nbsp;&nbsp;&nbsp; [User(Browser)] -------------&gt; [Squid]-------&gt;[缓存仓库]
<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /|&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; \|
<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; |(无效/不存在)
<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; (执行完成)/&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; |/
<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; [WebServer(apache/php)]</pre>
<br>
<br>
&nbsp;&nbsp;&nbsp;&nbsp; 假设 webServer 采用 php 脚本服务，每次的的请求产生的负载比较高(+db...) <br>
当 php 能够在 squid 提交请求时通过 If-Modified-From 得知在 squid 缓存池中 <br>
的数据 Last-Modified 时间的话，通过比较时间戳记就可以知道缓存是否有效，若 <br>
有效那么 php 脚本就不需要从头执行完成，只要简单的输入 Last-Modified 的时间 <br>
即可退出程序 exit(0)，节省不必要的程序开销。实现步骤如下： <br>
<br>
1.  <br>
# squid.conf (squid 的配置文件中确保相关的 URL 刷新写法如下) <br>
# 重点在于&nbsp;&nbsp; 0, 0% 和 reload-into-ims <br>
# 0, 0% 确保每次请求进来的时候 squid 都会向后台 server 提交请求 <br>
# reload-into-ims 选项保证了提交 If-Modified-From: 且会强制缓存数据直到 <br>
# LM 修改才清理... <br>
# <br>
# 特别注意: 不同的URL组成可以写好几条 refresh_pattern, <br>
#&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 仅针对动态+高负荷的 url 作如下处理即可. <br>
# <br>
refresh_pattern ^http:&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 0&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 0%&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 1440&nbsp;&nbsp;&nbsp;&nbsp; reload-into-ims <br>
<br>
<br>
2. <br>
<pre><br>// 基于squid面向apache作反向代理的php程序设计技巧
<br>// 作者: hightman 首次发布于 chinaunix.net PHP 版
<br>// 
<br>// 首先在 php 程序中，确保不要输出 Expires: HTTP 头
<br>//
<br>// 当前 URL结构的最后更新时间，如 BBS 列表的话可以判断最新发贴时间，
<br>// 博客文章可以求出最后发表评论的时间，只要没有新发表或没有新评论不
<br>// 必重新运行 php 脚本...
<br>$chrono = filemtime(__FILE__);
<br>
<br>// 使用 apache 提供的函数，获取 If-Modified-Since
<br>$headers = apache_request_headers();
<br>$client_time = (isset($headers['If-Modified-Since']) ? 
<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; strtotime($headers['If-Modified-Since']) : 0);
<br>
<br>// 比较 client_time 与 当前页面刷新时间
<br>if ($client_time &amp;&amp; $client_time &gt;= $chrono)
<br>{
<br>&nbsp;&nbsp;&nbsp;&nbsp; // 表明 squid 的缓存是新的不必从头运行脚本，简单通过 HTTP 状态通知即可
<br>&nbsp;&nbsp;&nbsp;&nbsp; // 发送 '304 Not Modified'. 然后退出脚本
<br>&nbsp;&nbsp;&nbsp;&nbsp; header('Last-Modified: '.gmdate('D, d M Y H:i:s', $client_time).' GMT', true, 304);
<br>&nbsp;&nbsp;&nbsp;&nbsp; exit(0);
<br>}
<br>else
<br>{
<br>&nbsp;&nbsp;&nbsp;&nbsp; // 表明该页面比客户端提供的更新, 故需要重新运行脚本, 发送 200 状态
<br>&nbsp;&nbsp;&nbsp;&nbsp; // 并提供 最近的 Last-Modified 时间
<br>&nbsp;&nbsp;&nbsp;&nbsp; header('Last-Modified: '.gmdate('D, d M Y H:i:s', $chrono).' GMT', true, 200);
<br>}
<br>
<br>// 对于一些特殊的 client 发起的 HEAD 请求，也不必生成实体内容，直接退出 :-P
<br>if (strtoupper($_SERVER['REQUEST_METHOD']) == 'HEAD') exit(0);</pre> <a href="http://hi.baidu.com/mikyliang/blog/item/890a17e9316e4535b80e2df7.html">阅读全文</a>
		
		<br/><b>类别：</b><a href="http://hi.baidu.com/mikyliang/blog/category/%BC%BC%CA%F5">技术</a>&nbsp;<a href="http://hi.baidu.com/mikyliang/blog/item/890a17e9316e4535b80e2df7.html#comment">查看评论</a>]]></description>
        <pubDate>2009-10-19  17:54</pubDate>
        <category><![CDATA[技术]]></category>
        <author><![CDATA[mikyliang]]></author>
		<guid>http://hi.baidu.com/mikyliang/blog/item/890a17e9316e4535b80e2df7.html</guid>
</item>

<item>
        <title><![CDATA[[转]使用Javascript预览本地图片]]></title>
        <link><![CDATA[http://hi.baidu.com/mikyliang/blog/item/9898c75884f63d8b800a1809.html]]></link>
        <description><![CDATA[
		
		很久很久以前，那时候还是IE的天下，使用Javascript预览本地图片实现起来非常简单，就是设置一下：<br>
<br>
document.getElementById(&quot;image&quot;).src = &quot;file:///&quot; + document.getElementById(&quot;input&quot;).value;<br>
<br>
不过出于安全的考虑，现在的浏览器都不允许...src = file:///...这样的写法，作为替代，IE可以使用&ldquo;DXImageTransform.Microsoft.AlphaImageLoader&rdquo;滤镜的方式，而Firefox则提供了一个getAsDataURL方法。<br>
<br>
01 &lt;html&gt;<br>
02 &lt;head&gt;<br>
03 &lt;meta http-equiv=&quot;Content-Type&quot; content=&quot;text/html; charset=utf-8&quot; /&gt;<br>
04 &lt;title&gt;preview&lt;/title&gt;<br>
05 &lt;style&gt;<br>
06 #preview {<br>
07&nbsp;&nbsp;&nbsp;&nbsp;  width: 270px;<br>
08&nbsp;&nbsp;&nbsp;&nbsp;  height: 129px;<br>
09 }<br>
10 &lt;/style&gt;<br>
11 &lt;!--[if IE]&gt;<br>
12 &lt;style&gt;<br>
13 #preview {<br>
14&nbsp;&nbsp;&nbsp;&nbsp;  filter:progid:DXImageTransform.Microsoft.AlphaImageLoader(sizingMethod=image);<br>
15 }<br>
16 &lt;/style&gt;<br>
17 &lt;![endif]--&gt;<br>
18 &lt;/head&gt;<br>
19<br>
20 &lt;body&gt;<br>
21 &lt;input id=&quot;file&quot; type=&quot;file&quot; /&gt;<br>
22 &lt;div id=&quot;preview&quot;&gt;<br>
23&nbsp;&nbsp;&nbsp;&nbsp;  &lt;img id=&quot;image&quot; src=&quot;http://www.baidu.com/img/baidu_logo.gif&quot; /&gt;<br>
24 &lt;/div&gt;<br>
25 &lt;script&gt;<br>
26 document.getElementById(&quot;file&quot;).onchange = function() {<br>
27&nbsp;&nbsp;&nbsp;&nbsp;  if (&quot;Microsoft Internet Explorer&quot; == navigator.appName) {<br>
28&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  var preview = document.getElementById(&quot;preview&quot;);<br>
29&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  preview.filters.item(&quot;DXImageTransform.Microsoft.AlphaImageLoader&quot;).src = this.value;<br>
30&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  document.getElementById(&quot;image&quot;).style.display = &quot;none&quot;;<br>
31&nbsp;&nbsp;&nbsp;&nbsp;  } else if (&quot;Netscape&quot; == navigator.appName){<br>
32&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  document.getElementById(&quot;image&quot;).src = this.files[0].getAsDataURL();<br>
33&nbsp;&nbsp;&nbsp;&nbsp;  } else {<br>
34&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  alert(&quot;Not Support!&quot;);<br>
35&nbsp;&nbsp;&nbsp;&nbsp;  }<br>
36 }<br>
37 &lt;/script&gt;<br>
38 &lt;/body&gt;<br>
39 &lt;/html&gt;<br> <a href="http://hi.baidu.com/mikyliang/blog/item/9898c75884f63d8b800a1809.html">阅读全文</a>
		
		<br/><b>类别：</b><a href="http://hi.baidu.com/mikyliang/blog/category/Javascript">Javascript</a>&nbsp;<a href="http://hi.baidu.com/mikyliang/blog/item/9898c75884f63d8b800a1809.html#comment">查看评论</a>]]></description>
        <pubDate>2009-10-12  18:02</pubDate>
        <category><![CDATA[Javascript]]></category>
        <author><![CDATA[mikyliang]]></author>
		<guid>http://hi.baidu.com/mikyliang/blog/item/9898c75884f63d8b800a1809.html</guid>
</item>

<item>
        <title><![CDATA[[转]window.location.href不起作用/无效的原因分析]]></title>
        <link><![CDATA[http://hi.baidu.com/mikyliang/blog/item/838eb2c20f0382110ef47725.html]]></link>
        <description><![CDATA[
		
		<p>今天在公司给别的同事改bug，其中一个是window.location.href  不起作用</p>
<div style="border-right: windowtext 0.5pt solid; padding-right: 5.4pt; border-top: windowtext 0.5pt solid; padding-left: 5.4pt; background: #e6e6e6; padding-bottom: 4px; border-left: windowtext 0.5pt solid; width: 95%; padding-top: 4px; border-bottom: windowtext 0.5pt solid">
<div>alert(&rdquo;ok&rdquo;)</div>
<div>window.location.href = &lsquo;/event/index.php?from_city=&rsquo; + site;</div>
</div>
<p>上面的alert(&rdquo;ok&rdquo;);是<strong style="color: white; background-color: #880000">不跳转</strong>后用来调试的，页面反映为现实url的值，但不进行跳转，分析思路是<strong style="color: black; background-color: #ffff66">window.location.href</strong>出问题，所以尝试了常用的调试方式,比如：</p>
<p>判断是否是在包含页里面：采用</p>
<p>window.parent.location.href=url; //这个完全否决，因为不是这种情况</p>
<p>采用 window.href location.href document.href均无效</p>
<p>于是跳出判断函数内部出错，分析页面出发该函数的事件，原来是这样的：</p>
<p>&lt;a href=&rdquo;javascript:void(0)&rdquo; onclick=&rdquo;changeSite(&rsquo;200′)&rdquo;&gt;</p>
<p>发现问题：&lt;a href=&rdquo;<span style="color: #ff0000">javascript:void(0)&rdquo;</span> ，于是修改为：</p>
<p>&lt;a href=&rdquo;javascript:changeSite(&rsquo;200′)&rdquo;&gt;</p>
<p><span style="color: #ff0000">于是一切正常！</span></p>
<p>为什么会发生这个问题呢？我们来看看<span style="color: #ff0000">javascript:void(0) ：</span></p>
<p>JavaScript中void是一个操作符，该操作符指定要计算一个表达式但是不返回值。</p>
<p>void 操作符用法格式如下：<br>
1. javascript:void (expression)<br>
2. javascript:void expression</p>
<p>expression 是一个要计算的 JavaScript 标准的表达式。表达式外侧的圆括号是可选的，但是写上去是一个好习惯。 (实现版本 Navigator 3.0 )</p>
<p>你可以使用 void 操作符指定超级链接。表达式会被计算但是不会在当前文档处装入任何内容。</p>
<p>下面的代码创建了一个超级链接，当用户点击以后不会发生任何事。当用户点击链接时，void(0) 计算为 0，但在 JavaScript 上没有任何效果。</p>
<p>&lt;A HREF=&rdquo;javascript:void(0)&rdquo;&gt;单击此处什么也不会发生&lt;/A&gt;</p>
<p>下面的代码创建了一个超级链接，用户单击时会提交表单。</p>
<p>&lt;A HREF=&rdquo;javascript:void(document.form.submit())&rdquo;&gt;<br>
单击此处提交表单&lt;/A&gt;</p>
<p>对于jquery 和yui等前端框架来说他们都有阻止默认事件的方法，在调用window.location.href 等其他重定向方法之前阻止掉连接的默认事件就可以哈</p>
<p>比如</p>
<p>$(&rsquo;#changesite-panel a.city&rsquo;).click(function(ev){<br>
ev.preventDefault();<br>
changeSite($(this).attr(&rsquo;rel&rsquo;));<br>
});</p>
<p>function changeSite(site){</p>
<p>window.location.href = &lsquo;/event/index.php?from_city=&rsquo; + site;</p>
<p>}<br>
})();</p>
<br>
转：<a href="http://blog.youmila.com/?p=219">http://blog.youmila.com/?p=219</a> <a href="http://hi.baidu.com/mikyliang/blog/item/838eb2c20f0382110ef47725.html">阅读全文</a>
		
		<br/><b>类别：</b><a href="http://hi.baidu.com/mikyliang/blog/category/Javascript">Javascript</a>&nbsp;<a href="http://hi.baidu.com/mikyliang/blog/item/838eb2c20f0382110ef47725.html#comment">查看评论</a>]]></description>
        <pubDate>2009-10-12  10:19</pubDate>
        <category><![CDATA[Javascript]]></category>
        <author><![CDATA[mikyliang]]></author>
		<guid>http://hi.baidu.com/mikyliang/blog/item/838eb2c20f0382110ef47725.html</guid>
</item>

<item>
        <title><![CDATA[将inputfile的选择的文件清空]]></title>
        <link><![CDATA[http://hi.baidu.com/mikyliang/blog/item/35b7ddef6cdc013cacafd59d.html]]></link>
        <description><![CDATA[
		
		<div class="blog_content">
<p><span><span style="font-size: medium"><font size="3">上传文件时,选择了文件后想清空文件路径的两种办法:</font></span></span></p>
<p><span style="font-size: medium"><font size="3">JS代码 <br>
&lt;input type=&quot;file&quot; id=&quot;fileupload&quot; name=&quot;file&quot; /&gt;  </font></span></p>
<p><span style="font-size: medium"><font size="3">第一种: (display:none时不能用)</font></span></p>
<p><span style="font-size: medium"><font size="3">var obj = document.getElementById('fileupload') ;&nbsp;&nbsp;  <br>
obj.select();&nbsp;&nbsp;  <br>
document.selection.clear();  </font></span></p>
<p><br>
<span style="font-size: medium"><font size="3">第二种：(无论display:none或block都可以用)</font></span></p>
<p><span style="font-size: medium"><font size="3">var obj = document.getElementById('fileupload') ;&nbsp;&nbsp;  <br>
obj.outerHTML=obj.outerHTML;</font></span> </p>
</div>





 <a href="http://hi.baidu.com/mikyliang/blog/item/35b7ddef6cdc013cacafd59d.html">阅读全文</a>
		
		<br/><b>类别：</b><a href="http://hi.baidu.com/mikyliang/blog/category/Javascript">Javascript</a>&nbsp;<a href="http://hi.baidu.com/mikyliang/blog/item/35b7ddef6cdc013cacafd59d.html#comment">查看评论</a>]]></description>
        <pubDate>2009-10-10  09:55</pubDate>
        <category><![CDATA[Javascript]]></category>
        <author><![CDATA[mikyliang]]></author>
		<guid>http://hi.baidu.com/mikyliang/blog/item/35b7ddef6cdc013cacafd59d.html</guid>
</item>

<item>
        <title><![CDATA[完全图解scrollLeft,scrollWidth,clientWidth,offsetWidth]]></title>
        <link><![CDATA[http://hi.baidu.com/mikyliang/blog/item/f219658d75b62218b31bba82.html]]></link>
        <description><![CDATA[
		
		<p>scrollHeight: 获取对象的滚动高度。<br>
scrollLeft:设置或获取位于对象左边界和窗口中目前可见内容的最左端之间的距离<br>
scrollTop:设置或获取位于对象最顶端和窗口中可见内容的最顶端之间的距离<br>
scrollWidth:获取对象的滚动宽度<br>
offsetHeight:获取对象相对于版面或由父坐标 offsetParent 属性指定的父坐标的高度<br>
offsetLeft:获取对象相对于版面或由 offsetParent 属性指定的父坐标的计算左侧位置<br>
offsetTop:获取对象相对于版面或由 offsetTop 属性指定的父坐标的计算顶端位置<br>
event.clientX 相对文档的水平座标<br>
event.clientY 相对文档的垂直座标<br>
event.offsetX 相对容器的水平坐标<br>
event.offsetY 相对容器的垂直坐标<br>
document.documentElement.scrollTop 垂直方向滚动的值<br>
event.clientX+document.documentElement.scrollTop 相对文档的水平座标+垂直方向滚动的量<br>
以上主要指IE之中，FireFox差异如下：<br>
IE6.0、FF1.06+：<br>
clientWidth = width + padding<br>
clientHeight = height + padding<br>
offsetWidth = width + padding + border<br>
offsetHeight = height + padding + border<br>
IE5.0/5.5：<br>
clientWidth = width - border<br>
clientHeight = height - border<br>
offsetWidth = width<br>
offsetHeight = height(需要提一下：CSS中的margin属性，与clientWidth、offsetWidth、clientHeight、offsetHeight均无关)</p>
<p> </p>
<p> </p>
<div forimg="1"><img class="blogimg" src="http://hiphotos.baidu.com/327382594/pic/item/8af3403d58254d2bbba1673e.jpg" border="0" small="0"></div>
<p><br>
网页可见区域宽： document.body.clientWidth;<br>
网页可见区域高： document.body.clientHeight;</p>
<p>网页可见区域宽： document.body.offsetWidth (包括边线的宽);<br>
网页可见区域高： document.body.offsetHeight (包括边线的宽);</p>
<p>网页正文全文宽： document.body.scrollWidth;<br>
网页正文全文高： document.body.scrollHeight;</p>
<p>网页被卷去的高： document.body.scrollTop;<br>
网页被卷去的左： document.body.scrollLeft;</p>
<p>网页正文部分上： window.screenTop;<br>
网页正文部分左： window.screenLeft;</p>
<p>屏幕分辨率的高： window.screen.height;<br>
屏幕分辨率的宽： window.screen.width;</p>
<p>屏幕可用工作区高度： window.screen.availHeight;<br>
屏幕可用工作区宽度：window.screen.availWidth;</p> <a href="http://hi.baidu.com/mikyliang/blog/item/f219658d75b62218b31bba82.html">阅读全文</a>
		
		<br/><b>类别：</b><a href="http://hi.baidu.com/mikyliang/blog/category/%C7%B0%B6%CB">前端</a>&nbsp;<a href="http://hi.baidu.com/mikyliang/blog/item/f219658d75b62218b31bba82.html#comment">查看评论</a>]]></description>
        <pubDate>2009-09-21  16:20</pubDate>
        <category><![CDATA[前端]]></category>
        <author><![CDATA[mikyliang]]></author>
		<guid>http://hi.baidu.com/mikyliang/blog/item/f219658d75b62218b31bba82.html</guid>
</item>

<item>
        <title><![CDATA[window.location.hash]]></title>
        <link><![CDATA[http://hi.baidu.com/mikyliang/blog/item/a59191d6d1ac8e2507088b9c.html]]></link>
        <description><![CDATA[
		
		<div>location是javascript里边管理地址栏的内置对象，比如location.href就管理页面的url，用location.href=url就可以直接将页面重定向url。而location.hash则可以用来获取或设置页面的标签值。比如<a href="http://domain/#admin">http://domain/#admin</a>的location.hash=&quot;#admin&quot;。利用这个属性值可以做一个非常有意义的事情。</div>
<div>很多人都喜欢收藏网页，以便于以后的浏览。不过对于Ajax页面来说的话，一般用一个页面来处理所有的事务，也就是说，如果你浏览到一个Ajax页面里边有意思的内容，想将它收藏起来，可是地址只有一个呀，下次你打开这个地址，还是得像以往一样不断地去点击网页，找到你钟情的那个页面。另外的话，浏览器上的&ldquo;前进&rdquo;&ldquo;后退&rdquo;按钮也会失效，这于很多习惯了传统页面的用户来说，是一个很大的使用障碍。</div>
<div>那么，怎么用location.hash来解决这两个问题呢？其实一点也不神秘。</div>
<div>比如，我的作者管理系统，主要功能有三个：普通搜索、高级搜索、后台管理，我分别给它们分配一个hash值：#search、#advsearch、#admin，在页面初始化的时候，通过window.location.hash来判断用户需要访问的页面，然后通过javascript来调整显示页面。比如：</div>
<div> </div>
<div><font face="Georgia">var hash;</font></div>
<div><font face="Georgia">hash=(!window.location.hash)?&quot;#search&quot;:window.location.hash;</font></div>
<div><font face="Georgia">window.location.hash=hash;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  //调整地址栏地址，使前进、后退按钮能使用</font></div>
<div><font face="Georgia">switch(hash){</font></div>
<div><font face="Georgia">&nbsp;&nbsp;  case &quot;#search&quot;:</font></div>
<div><font face="Georgia">&nbsp;&nbsp;&nbsp;&nbsp;  selectPanel(&quot;pnlSearch&quot;);&nbsp;&nbsp;  //显示普通搜索面板</font></div>
<div><font face="Georgia">&nbsp;&nbsp;&nbsp;&nbsp;  break;</font></div>
<div><font face="Georgia">&nbsp;&nbsp;  case &quot;#advsearch&quot;:</font></div>
<div><font face="Georgia">&nbsp;&nbsp;&nbsp;&nbsp;  ...</font></div>
<div><font face="Georgia">&nbsp;&nbsp;  case &quot;#admin&quot;:</font></div>
<div><font face="Georgia">&nbsp;&nbsp;&nbsp;&nbsp;  ...</font></div>
<div><font face="Georgia">}</font></div>
<div> </div>
<div> </div>
<p>通过window.location.hash=hash这个语句来调整地址栏的地址，使得浏览器里边的&ldquo;前进&rdquo;、&ldquo;后退&rdquo;按钮能正常使用（实质上欺骗了浏览器<img src="http://blog.sina.com.cn/images/face/005.gif">）。然后再根据hash值的不同来显示不同的面板（用户可以收藏对应的面板了），这就使得Ajax页面的浏览趋于传统化了。</p> <a href="http://hi.baidu.com/mikyliang/blog/item/a59191d6d1ac8e2507088b9c.html">阅读全文</a>
		
		<br/><b>类别：</b><a href="http://hi.baidu.com/mikyliang/blog/category/%BC%BC%CA%F5">技术</a>&nbsp;<a href="http://hi.baidu.com/mikyliang/blog/item/a59191d6d1ac8e2507088b9c.html#comment">查看评论</a>]]></description>
        <pubDate>2009-09-17  11:55</pubDate>
        <category><![CDATA[技术]]></category>
        <author><![CDATA[mikyliang]]></author>
		<guid>http://hi.baidu.com/mikyliang/blog/item/a59191d6d1ac8e2507088b9c.html</guid>
</item>

<item>
        <title><![CDATA[【转】无限分类的新说]]></title>
        <link><![CDATA[http://hi.baidu.com/mikyliang/blog/item/3d08a51b4b7c07108618bf36.html]]></link>
        <description><![CDATA[
		
		<p><strong style="font-weight: 400">无论你要构建自己的论坛，在你的网站上发布消息还是书写自己的CMS程序，你都会遇到要在数据库中存储层次数据的情况。同时，除非你使用一种像XML的数据库，否则关系数据库中的表都不是层次结构的，他们只是一个平坦的列表。所以你必须找到一种把层次数据库转化的方法。</strong></p>
<p>存储树形结构是一个很常见的问题，他有好几种解决方案。主要有两种方法：邻接列表模型和改进前序遍历树算法</p>
<p>在本文中，我们将探讨这两种保存层次数据的方法。我将举一个在线食品店树形图的例子。这个食品店通过类别、颜色和品种来组织食品。树形图如下：</p>
<p> </p>
<p><img style="display: block; margin: 0px auto 10px; text-align: center" src="http://116.img.pp.sohu.com/images/blog/2007/7/2/13/7/1141e55a7ff.gif" border="0">本文包含了一些代码的例子来演示如何保存和获取数据。我选择PHP来写例子，因为我常用这个语言，而且很多人也都使用或者知道这个语言。你可以很方便地把它们翻译成你自己用的语言。</p>
<h5>邻接列表模型(The Adjacency List Model)</h5>
<p>我们要尝试的第一个&mdash;&mdash;也是最优美的&mdash;&mdash;方法称为&ldquo;邻接列表模型&rdquo;或称为&ldquo;递归方法&rdquo;。它是一个很优雅的方法因为你只需要一个简单的方法来在你的树中进行迭代。在我们的食品店中，邻接列表的表格如下：</p>
<p><a href="http://blog.sina.com.cn/main/html/showpic.html#url=http://s8.album.sina.com.cn/pic/4c008a8102000snv" target="_blank"><img style="display: block; margin: 0px auto 10px; text-align: center" src="http://118.img.pp.sohu.com/images/blog/2007/7/2/13/6/1141e57a57c.jpg" border="0"></a></p>
<p>如你所见，对每个节点保存一个&ldquo;父&rdquo;节点。我们可以看到&ldquo;Pear&rdquo;是&ldquo;Green&rdquo;的一个子节点，而后者又是&ldquo;Fruit&rdquo;的子节点，如此类推。根节点，&ldquo;Food&rdquo;，则他的父节点没有值。为了简单，我只用了&ldquo;title&rdquo;值来标识每个节点。当然，在实际的数据库中，你要使用数字的ID。</p>
<p><strong><em>显示树</em></strong></p>
<p>现在我们已经把树放入数据库中了，得写一个显示函数了。这个函数将从根节点开始&mdash;&mdash;没有父节点的节点&mdash;&mdash;同时要显示这个节点所有的子节点。对于这些子节点，函数也要获取并显示这个子节点的子节点。然后，对于他们的子节点，函数还要再显示所有的子节点，然后依次类推。</p>
<p>也许你已经注意到了，这种函数的描述，有一种普遍的模式。我们可以简单地只写一个函数，用来获得特定节点的子节点。这个函数然后要对每个子节点调用自身来再次显示他们的子节点。这就是&ldquo;递归&rdquo;机制，因此称这种方法叫&ldquo;递归方法&rdquo;。</p>
<p><code><a href="http://blog.sina.com.cn/main/html/showpic.html#url=http://s2.album.sina.com.cn/pic/4c008a8102000sn1" target="_blank"><img style="display: block; margin: 0px auto 10px; text-align: center" src="http://117.img.pp.sohu.com/images/blog/2007/7/2/13/7/1141e561a8d.jpg" border="0"></a></code></p>
<p>要实现整个树，我们只要调用函数时用一个空字符串作为<code><font face="新宋体">$parent</font></code> 和<code><font face="新宋体">$level = 0: display_children('',0);</font></code> 函数返回了我们的食品店的树状图如下：</p>
<p><code><font face="新宋体">Food<br>
Fruit<br>
Red<br>
Cherry<br>
Yellow<br>
Banana<br>
Meat<br>
Beef<br>
Pork</font></code></p>
<p>注意如果你只想看一个子树，你可以告诉函数从另一个节点开始。例如，要显示&ldquo;Fruit&rdquo;子树，你只要<code><font face="新宋体">display_children('Fruit',0);</font></code></p>
<p><strong><em>The Path to a Node节点的路径</em></strong></p>
<p>利用差不多的函数，我们也可以查询某个节点的路径如果你只知道这个节点的名字或者ID。例如，&ldquo;Cherry&rdquo;的路径是&ldquo;Food&rdquo;&gt;&ldquo;Fruit&rdquo;&gt;&ldquo;Red&rdquo;。要获得这个路径，我们的函数要获得这个路径，这个函数必须从最深的层次开始：&ldquo;Cheery&rdquo;。但后查找这个节点的父节点，并添加到路径中。在我们的例子中，这个父节点是&ldquo;Red&rdquo;。如果我们知道&ldquo;Red&rdquo;是&ldquo;Cherry&rdquo;的父节点。</p>
<p><a href="http://blog.sina.com.cn/main/html/showpic.html#url=http://s3.album.sina.com.cn/pic/4c008a8102000sn2" target="_blank"><img style="display: block; margin: 0px auto 10px; text-align: center" src="http://117.img.pp.sohu.com/images/blog/2007/7/2/13/7/1141e565377.jpg" border="0"></a></p>
<p>这个函数现在返回了指定节点的路径。他把路径作为数组返回，这样我们可以使用<code><font face="新宋体">print_r(get_path('Cherry'));</font></code> 来显示，其结果是：</p>
<p><code><font face="新宋体">Array<br>
(<br>
   [0] =&gt; Food<br>
   [1] =&gt; Fruit<br>
   [2] =&gt; Red<br>
)</font></code></p>
<p><strong><em>不足</em></strong></p>
<p>正如我们所见，这确实是一个很好的方法。他很容易理解，同时代码也很简单。但是邻接列表模型的缺点在哪里呢？在大多数编程语言中，他运行很慢，效率很差。这主要是&ldquo;递归&rdquo;造成的。我们每次查询节点都要访问数据库。</p>
<p>每次数据库查询都要花费一些时间，这让函数处理庞大的树时会十分慢。</p>
<p>造成这个函数不是太快的第二个原因可能是你使用的语言。不像Lisp这类语言，大多数语言不是针对递归函数设计的。对于每个节点，函数都要调用他自己，产生新的实例。这样，对于一个4层的树，你可能同时要运行4个函数副本。对于每个函数都要占用一块内存并且需要一定的时间初始化，这样处理大树时递归就很慢了。</p>
<h5>改进前序遍历树</h5>
<p>现在，让我们看另一种存储树的方法。递归可能会很慢，所以我们就尽量不使用递归函数。我们也想尽量减少数据库查询的次数。最好是每次只需要查询一次。</p>
<p>我们先把树按照水平方式摆开。从根节点开始（&ldquo;Food&rdquo;），然后他的左边写上1。然后按照树的顺序（从上到下）给&ldquo;Fruit&rdquo;的左边写上2。这样，你沿着树的边界走啊走（这就是&ldquo;遍历&rdquo;），然后同时在每个节点的左边和右边写上数字。最后，我们回到了根节点&ldquo;Food&rdquo;在右边写上18。下面是标上了数字的树，同时把遍历的顺序用箭头标出来了。</p>
<p><a href="http://blog.sina.com.cn/main/html/showpic.html#url=http://s9.album.sina.com.cn/pic/4c008a8102000snw" target="_blank"><img style="display: block; margin: 0px auto 10px; text-align: center" src="http://117.img.pp.sohu.com/images/blog/2007/7/2/13/7/1141e56817c.jpg" border="0"></a></p>
<p>我们称这些数字为左值和右值（如，&ldquo;Food&rdquo;的左值是1，右值是18）。正如你所见，这些数字按时了每个节点之间的关系。因为&ldquo;Red&rdquo;有3和6两个值，所以，它是有拥有1-18值的&ldquo;Food&rdquo;节点的后续。同样的，我们可以推断所有左值大于2并且右值小于11的节点，都是有2-11的&ldquo;Food&rdquo;节点的后续。这样，树的结构就通过左值和右值储存下来了。这种数遍整棵树算节点的方法叫做&ldquo;改进前序遍历树&rdquo;算法。</p>
<p>在继续前，我们先看看我们的表格里的这些值：</p>
<p><a href="http://blog.sina.com.cn/main/html/showpic.html#url=http://s10.album.sina.com.cn/pic/4c008a8102000snx" target="_blank"><img style="display: block; margin: 0px auto 10px; text-align: center" src="http://118.img.pp.sohu.com/images/blog/2007/7/2/13/7/1141e585fc8.jpg" border="0"></a></p>
<p>注意单词&ldquo;left&rdquo;和&ldquo;right&rdquo;在SQL中有特殊的含义。因此，我们只能用&ldquo;lft&rdquo;和&ldquo;rgt&rdquo;来表示这两个列。（译注&mdash;&mdash;其实Mysql中可以用&ldquo;`&rdquo;来表示，如&ldquo;`left`&rdquo;，MSSQL中可以用&ldquo;[]&rdquo;括出，如&ldquo;[left]&rdquo;，这样就不会和关键词冲突了。）同样注意这里我们已经不需要&ldquo;parent&rdquo;列了。我们只需要使用lft和rgt就可以存储树的结构。</p>
<p><strong><em>获取树</em></strong></p>
<p>如果你要通过左值和右值来显示这个树的话，你要首先标识出你要获取的那些节点。例如，如果你想获得&ldquo;Fruit&rdquo;子树，你要选择那些左值在2到11的节点。用SQL语句表达：</p>
<p><code><font face="新宋体">SELECT * FROM tree WHERE lft BETWEEN 2 AND 11;</font></code></p>
<p>这个会返回：</p>
<p><a href="http://blog.sina.com.cn/main/html/showpic.html#url=http://s11.album.sina.com.cn/pic/4c008a8102000sny" target="_blank"><img style="display: block; margin: 0px auto 10px; text-align: center" src="http://116.img.pp.sohu.com/images/blog/2007/7/2/13/9/1141e56ab3c.gif" border="0"></a></p>
<p>好吧，现在整个树都在一个查询中了。现在就要像前面的递归函数那样显示这个树，我们要加入一个ORDER BY子句在这个查询中。如果你从表中添加和删除行，你的表可能就顺序不对了，我们因此需要按照他们的左值来进行排序。</p>
<p><code><font face="新宋体">SELECT * FROM tree WHERE lft BETWEEN 2 AND 11 ORDER BY lft ASC;</font></code></p>
<p>就只剩下缩进的问题了。</p>
<p>要显示树状结构，子节点应该比他们的父节点稍微缩进一些。我们可以通过保存一个右值的一个栈。每次你从一个节点的子节点开始时，你把这个节点的右值添加到栈中。你也知道子节点的右值都比父节点的右值小，这样通过比较当前节点和栈中的前一个节点的右值，你可以判断你是不是在显示这个父节点的子节点。当你显示完这个节点，你就要把他的右值从栈中删除。要获得当前节点的层数，只要数一下栈中的元素。</p>
<p><code><a href="http://blog.sina.com.cn/main/html/showpic.html#url=http://s4.album.sina.com.cn/pic/4c008a8102000sn3" target="_blank"><img style="display: block; margin: 0px auto 10px; text-align: center" src="http://115.img.pp.sohu.com/images/blog/2007/7/2/13/9/1141e56a222.jpg" border="0"></a></code></p>
<p>如果运行这段代码，你可以获得和上一部分讨论的递归函数一样的结果。而这个函数可能会更快一点：他不采用递归而且只是用了两个查询</p>
<p><strong><em>节点的路径</em></strong></p>
<p>有了新的算法，我们还要另找一种新的方法来获得指定节点的路径。这样，我们就需要这个节点的祖先的一个列表。</p>
<p>由于新的表结构，这不需要花太多功夫。你可以看一下，例如，4-5的&ldquo;Cherry&rdquo;节点，你会发现祖先的左值都小于4，同时右值都大于5。这样，我们就可以使用下面这个查询：</p>
<p><code><font face="新宋体">SELECT title FROM tree WHERE lft &lt; 4 AND rgt &gt; 5 ORDER BY lft ASC;</font></code></p>
<p>注意，就像前面的查询一样，我们必须使用一个ORDER BY子句来对节点排序。这个查询将返回：</p>
<p><code><font face="新宋体">+-------+<br>
| title |<br>
+-------+<br>
| Food  |<br>
| Fruit |<br>
| Red&nbsp;&nbsp;  |<br>
+-------+</font></code></p>
<p>我们现在只要把各行连起来，就可以得到&ldquo;Cherry&rdquo;的路径了。</p>
<p><strong><em>有多少个后续节点？How Many Descendants</em></strong></p>
<p>如果你给我一个节点的左值和右值，我就可以告诉你他有多少个后续节点，只要利用一点点数学知识。</p>
<p>因为每个后续节点依次会对这个节点的右值增加2，所以后续节点的数量可以这样计算：</p>
<p><code><font face="新宋体">descendants = (right &ndash; left - 1) / 2</font></code></p>
<p>利用这个简单的公式，我可以立刻告诉你2-11的&ldquo;Fruit&rdquo;节点有4个后续节点，8-9的&ldquo;Banana&rdquo;节点只是1个子节点，而不是父节点。</p>
<p><strong><em>自动化树遍历</em></strong></p>
<p>现在你对这个表做一些事情，我们应该学习如何自动的建立表了。这是一个不错的练习，首先用一个小的树，我们也需要一个脚本来帮我们完成对节点的计数。</p>
<p>让我们先写一个脚本用来把一个邻接列表转换成前序遍历树表格。</p>
<p><a href="http://blog.sina.com.cn/main/html/showpic.html#url=http://s5.album.sina.com.cn/pic/4c008a8102000sn4" target="_blank"><img style="display: block; margin: 0px auto 10px; text-align: center" src="http://118.img.pp.sohu.com/images/blog/2007/7/2/13/7/1141e590577.jpg" border="0"></a></p>
<p>这是一个递归函数。你要从<code><font face="新宋体">rebuild_tree('Food',1);</font></code> 开始，这个函数就会获取所有的&ldquo;Food&rdquo;节点的子节点。</p>
<p>如果没有子节点，他就直接设置它的左值和右值。左值已经给出了，1，右值则是左值加1。如果有子节点，函数重复并且返回最后一个右值。这个右值用来作为&ldquo;Food&rdquo;的右值。</p>
<p>递归让这个函数有点复杂难于理解。然而，这个函数确实得到了同样的结果。他沿着树走，添加每一个他看见的节点。你运行了这个函数之后，你会发现左值和右值和预期的是一样的（一个快速检验的方法：根节点的右值应该是节点数量的两倍）。</p>
<p><strong><em>添加一个节点</em></strong></p>
<p>我们如何给这棵树添加一个节点？有两种方式：在表中保留&ldquo;parent&rdquo;列并且重新运行<code><font face="新宋体">rebuild_tree()</font></code> 函数&mdash;&mdash;一个很简单但却不是很优雅的函数；或者你可以更新所有新节点右边的节点的左值和右值。</p>
<p>第一个想法比较简单。你使用邻接列表方法来更新，同时使用改进前序遍历树来查询。如果你想添加一个新的节点，你只需要把节点插入表格，并且设置好parent列。然后，你只需要重新运行<code><font face="新宋体">rebuild_tree()</font></code> 函数。这做起来很简单，但是对大的树效率不高。</p>
<p>第二种添加和删除节点的方法是更新新节点右边的所有节点。让我们看一下例子。我们要添加一种新的水果&mdash;&mdash;&ldquo;Strawberry&rdquo;，作为&ldquo;Red&rdquo;的最后一个子节点。首先，我们要腾出一个空间。&ldquo;Red&rdquo;的右值要从6变成8，7-10的&ldquo;Yellow&rdquo;节点要变成9-12，如此类推。更新&ldquo;Red&rdquo;节点意味着我们要把所有左值和右值大于5的节点加上2。</p>
<p>我们用一下查询：</p>
<p><code><font face="新宋体">UPDATE tree SET rgt=rgt+2 WHERE rgt&gt;5;<br>
UPDATE tree SET lft=lft+2 WHERE lft&gt;5;</font></code></p>
<p>现在我们可以添加一个新的节点&ldquo;Strawberry&rdquo;来填补这个新的空间。这个节点左值为6右值为7。</p>
<p><code><font face="新宋体">INSERT INTO tree SET lft=6, rgt=7, title='Strawberry';</font></code></p>
<p>如果我们运行<code><font face="新宋体">display_tree()</font></code> 函数，我们将发现我们新的&ldquo;Strawberry&rdquo;节点已经成功地插入了树中：</p>
<p><code><font face="新宋体">Food<br>
 Fruit<br>
   Red<br>
     Cherry<br>
     Strawberry<br>
   Yellow<br>
     Banana<br>
 Meat<br>
   Beef<br>
   Pork</font></code></p>
<p><strong><em>缺点</em></strong></p>
<p>首先，改进前序遍历树算法看上去很难理解。它当然没有邻接列表方法简单。然而，一旦你习惯了左值和右值这两个属性，他就会变得清晰起来，你可以用这个技术来完成临街列表能完成的所有事情，同时改进前序遍历树算法更快。当然，更新树需要很多查询，要慢一点，但是取得节点却可以只用一个查询。</p>
<h5>总结</h5>
<p>你现在已经对两种在数据库存储树方式熟悉了吧。虽然在我这儿改进前序遍历树算法性能更好，但是也许在你特殊的情况下邻接列表方法可能表现更好一些。这个就留给你自己决定了</p>
<p>最后一点：就像我已经说得我部推荐你使用节点的标题来引用这个节点。你应该遵循数据库标准化的基本规则。我没有使用数字标识是因为用了之后例子就比较难读。</p>
<p><strong><em>进一步阅读</em></strong></p>
<p>数据库指导 Joe Celko写的更多关于SQL数据库中的树的问题：<br>
http://searchdatabase.techtarget.com/tip/1,289483,sid13_gci537290,00.html</p>
<p>另外两种处理层次数据的方法：<br>
http://www.evolt.org/article/Four_ways_to_work_with_hierarchical_data/17/4047/index.html</p>
<p>Xindice, &ldquo;本地XML数据库&rdquo;:<br>
http://xml.apache.org/xindice/</p>
<p>递归的一个解释:<br>
http://www.strath.ac.uk/IT/Docs/Ccourse/subsection3_9_5.html</p>
<p> </p>
<p>mysql存储过程实现无限分类</p>
<p>表结构</p>
<div class="blockcode">
<div >
<ol>
    <li>-- phpMyAdmin <span class="t_tag" href="tag.php?name=SQL">SQL</span> Dump</li>
    <li>-- version 2.10.1</li>
    <li>-- [url]http://www.phpmyadmin.net[/url]</li>
    <li>--</li>
    <li>-- 主机: localhost</li>
    <li>-- 生成日期: 2007 年 08 月 23 日 14:36</li>
    <li>-- 服务器版本: 5.0.41</li>
    <li>-- <span class="t_tag" href="tag.php?name=PHP">PHP</span> 版本: 5.2.3</li>
    <li>SET SQL_MODE=&quot;NO_AUTO_VALUE_ON_ZERO&quot;;</li>
    <li>--</li>
    <li>-- 数据库: `cms`</li>
    <li>--</li>
    <li>-- --------------------------------------------------------</li>
    <li>--</li>
    <li>-- 表的结构 `pcms_channel`</li>
    <li>--</li>
    <li>DROP TABLE IF EXISTS `pcms_channel`;</li>
    <li>CREATE TABLE IF NOT EXISTS `pcms_channel` (</li>
    <li>&nbsp;&nbsp; `cid` tinyint(3) unsigned NOT NULL auto_increment,</li>
    <li>&nbsp;&nbsp; `name` char(10) NOT NULL COMMENT '频道名称',</li>
    <li>&nbsp;&nbsp; `parentid` tinyint(4) NOT NULL COMMENT '父级ID',</li>
    <li>&nbsp;&nbsp; `lft` tinyint(4) NOT NULL COMMENT '左值',</li>
    <li>&nbsp;&nbsp; `rgt` tinyint(4) NOT NULL COMMENT '右值',</li>
    <li>&nbsp;&nbsp; `lv` tinyint(3) unsigned NOT NULL default '0' COMMENT '级层',</li>
    <li>&nbsp;&nbsp; `themeid` tinyint(3) unsigned NOT NULL default '1' COMMENT '使用的主题的ID',</li>
    <li>&nbsp;&nbsp; PRIMARY KEY&nbsp;&nbsp; (`cid`),</li>
    <li>&nbsp;&nbsp; KEY `parentid` (`parentid`,`lft`,`rgt`)</li>
    <li>) ENGINE=InnoDB DEFAULT CHARSET=utf8 AUTO_INCREMENT=7 ;</li>
    <li>--</li>
    <li>-- 导出表中的数据 `pcms_channel`</li>
    <li>--</li>
    <li>INSERT INTO `pcms_channel` (`cid`, `name`, `parentid`, `lft`, `rgt`, `lv`, `themeid`) VALUES</li>
    <li>(1, 'phpoocms', 0, 1, 12, 0, 1),</li>
    <li>(2, 'test', 1, 2, 7, 1, 1),</li>
    <li>(3, 'te', 2, 3, 6, 2, 1),</li>
    <li>(4, 'tes', 1, 8, 9, 1, 1),</li>
    <li>(5, 'dd', 3, 4, 5, 3, 1),</li>
    <li>(6, 'fromphp', 1, 10, 11, 1, 1);</li>
</ol>
</div>
<em >复制<span class="t_tag" href="tag.php?name=%B4%FA%C2%EB">代码</span></em></div>
<p>清空表记录</p>
<div class="blockcode">
<div >
<ol>
    <li>TRUNCATE TABLE `pcms_channel`</li>
</ol>
</div>
<em >复制代码</em></div>
<p>添加节点到指定节点</p>
<div class="blockcode">
<div >
<ol>
    <li>DROP PROCEDURE IF EXISTS addChannel//</li>
    <li>create procedure addChannel (in pid int,in name varchar(20))</li>
    <li>BEGIN</li>
    <li>DECLARE pr INT;/*右值*/</li>
    <li>DECLARE lvv INT;/*层级*/</li>
    <li>DECLARE aff INT;/*计数器*/</li>
    <li>DECLARE af INT DEFAULT 0;</li>
    <li>SET @result = null;</li>
    <li>SELECT `rgt`,`lv` INTO pr,lvv FROM `pcms_channel` WHERE `cid` = pid;</li>
    <li>IF pr THEN</li>
    <li>START TRANSACTION;</li>
    <li>UPDATE `pcms_channel` SET `lft`=`lft`+2 WHERE `lft`&gt;pr;</li>
    <li>SELECT ROW_COUNT() INTO aff;</li>
    <li>SET af = aff+af;</li>
    <li>UPDATE `pcms_channel` SET `rgt`=`rgt`+2 WHERE `rgt`&gt;=pr;</li>
    <li>SELECT ROW_COUNT() INTO aff;</li>
    <li>SET af = aff+af;</li>
    <li>INSERT INTO `pcms_channel` (`name`,`parentid`,`lft`,`rgt`,`lv`) VALUES (name,pid,pr,pr+1,lvv+1);</li>
    <li>SELECT ROW_COUNT() INTO aff;</li>
    <li>SET af = aff+af;</li>
    <li>IF af &gt;= 2 THEN</li>
    <li>COMMIT;</li>
    <li>SET @result = 1000;</li>
    <li>SELECT 1000 AS result;</li>
    <li>ELSE</li>
    <li>ROLLBACK;</li>
    <li>SET @result = 1002;</li>
    <li>SELECT 1002 AS result;</li>
    <li>END IF;</li>
    <li>ELSE</li>
    <li>SET @result = 1001;</li>
    <li>SELECT 1001 AS result;</li>
    <li>END IF;</li>
    <li>END//</li>
    <li>call addChannel (5,&quot;aa&quot;)//</li>
</ol>
</div>
<em >复制代码</em></div>
<p>删除指定节点</p>
<div class="blockcode">
<div >
<ol>
    <li>DROP PROCEDURE IF EXISTS delChannel//</li>
    <li>create procedure delChannel (in pid int)</li>
    <li>BEGIN</li>
    <li>DECLARE pl INT;</li>
    <li>DECLARE pn INT;</li>
    <li>DECLARE aff INT;</li>
    <li>DECLARE af INT DEFAULT 0;</li>
    <li>SET @result = null;</li>
    <li>SET @parentid = null;</li>
    <li>SET @name = null;</li>
    <li>SELECT a.`lft`,IFNULL(COUNT(b.`cid`),0),a.`parentid`,a.`name` INTO pl,pn,@parentid,@name FROM `pcms_channel` AS a LEFT JOIN `pcms_channel` AS b ON a.`cid`=b.`parentid` WHERE a.`cid`=pid GROUP BY b.`parentid`;</li>
    <li>IF pl&amp;&amp;!pn THEN</li>
    <li>IF pl!=1 THEN</li>
    <li>&nbsp;&nbsp; START TRANSACTION;</li>
    <li>&nbsp;&nbsp; UPDATE `pcms_channel` SET `lft`=`lft`-2 WHERE `lft`&gt;pl;</li>
    <li>&nbsp;&nbsp; SELECT ROW_COUNT() INTO aff;</li>
    <li>&nbsp;&nbsp; SET af = aff+af;</li>
    <li>&nbsp;&nbsp; UPDATE `pcms_channel` SET `rgt`=`rgt`-2 WHERE `rgt`&gt;pl;</li>
    <li>&nbsp;&nbsp; SELECT ROW_COUNT() INTO aff;</li>
    <li>&nbsp;&nbsp; SET af = aff+af;</li>
    <li>&nbsp;&nbsp; DELETE FROM `pcms_channel` WHERE `cid` = pid;</li>
    <li>&nbsp;&nbsp; SELECT ROW_COUNT() INTO aff;</li>
    <li>&nbsp;&nbsp; SET af = aff+af;</li>
    <li>&nbsp;&nbsp; IF af &gt;= 2 THEN</li>
    <li>   COMMIT;</li>
    <li>   SET @result = 1000;</li>
    <li>   SELECT 1000 AS result;</li>
    <li>&nbsp;&nbsp; ELSE</li>
    <li>   ROLLBACK;</li>
    <li>   SET @result = 1002;</li>
    <li>   SELECT 1002 AS result;</li>
    <li>&nbsp;&nbsp; END IF;</li>
    <li>ELSE</li>
    <li>&nbsp;&nbsp; SET @result = 1004;</li>
    <li>&nbsp;&nbsp; SELECT 1004 AS result;</li>
    <li>END IF;</li>
    <li>ELSEIF pn&amp;&amp;pl THEN</li>
    <li>SET @result = 1003;</li>
    <li>SELECT 1003 AS result;</li>
    <li>ELSE</li>
    <li>SET @result = 1001;</li>
    <li>SELECT 1001 AS result;</li>
    <li>END IF;</li>
    <li>END//</li>
    <li>call delChannel (1)//</li>
</ol>
</div>
<em >复制代码</em></div>
<p>移动节点</p>
<div class="blockcode">
<div >
<ol>
    <li>DROP PROCEDURE IF EXISTS moveChannel//</li>
    <li>create procedure moveChannel (pid int,tid int)</li>
    <li>BEGIN</li>
    <li>IF pid=1 THEN</li>
    <li>SELECT 1004 AS result;</li>
    <li>ELSE</li>
    <li>IF pid!=tid THEN</li>
    <li>&nbsp;&nbsp; call delChannel (pid);</li>
    <li>&nbsp;&nbsp; IF @result=1000 THEN</li>
    <li>   call addChannel (tid,@name);</li>
    <li>   IF @result THEN</li>
    <li>    SELECT 1000 AS result;</li>
    <li>   ELSE</li>
    <li>    call addChannel (@parentid,@name);</li>
    <li>    SELECT @result AS result;</li>
    <li>   END IF;</li>
    <li>&nbsp;&nbsp; ELSE</li>
    <li>   SELECT @result AS result;</li>
    <li>&nbsp;&nbsp; END IF;</li>
    <li>ELSE</li>
    <li>&nbsp;&nbsp; SELECT 1005 AS result;</li>
    <li>END IF;</li>
    <li>END IF;</li>
    <li>SET @result=null;</li>
    <li>SET @parentid=null;</li>
    <li>SET @name=null;</li>
    <li>END//</li>
    <li>call moveChannel (1,1)//</li>
</ol>
</div>
<em >复制代码</em></div>
<p>查询出树状结构</p>
<div class="blockcode">
<div >
<ol>
    <li>select cid,concat(repeat(&quot;　&quot;,lv)) from pcms_channel;</li>
</ol>
</div>
</div> <a href="http://hi.baidu.com/mikyliang/blog/item/3d08a51b4b7c07108618bf36.html">阅读全文</a>
		
		<br/><b>类别：</b><a href="http://hi.baidu.com/mikyliang/blog/category/%D7%AA%D4%D8">转载</a>&nbsp;<a href="http://hi.baidu.com/mikyliang/blog/item/3d08a51b4b7c07108618bf36.html#comment">查看评论</a>]]></description>
        <pubDate>2009-09-10  14:51</pubDate>
        <category><![CDATA[转载]]></category>
        <author><![CDATA[mikyliang]]></author>
		<guid>http://hi.baidu.com/mikyliang/blog/item/3d08a51b4b7c07108618bf36.html</guid>
</item>

<item>
        <title><![CDATA[给PHP加速，eAccelerator配置和使用指南]]></title>
        <link><![CDATA[http://hi.baidu.com/mikyliang/blog/item/228d4fee15b0a9f2b3fb9565.html]]></link>
        <description><![CDATA[
		
		<p>前一段时间完成了服务器从FreeBSD4.10到6.1的升级，同时把PHP也升级到了最新的PHP5.1.4，Apache也升级到了最新的Apache2.2，为了更好的提高系统的性能，考虑对PHP再进行一些优化，前两年接触过MMCache和eAccelerator，尤其对eAccelerator非常喜欢，这次优化也选择了它，下面整理一些文档和大家分享。</p>
<p></p>
<p>目录：<br>
一、eAccelerator介绍<br>
1、背景<br>
2、原理<br>
二、安装和配置<br>
1、支持平台<br>
2、系统要求<br>
3、安装<br>
4、php.ini文件配置<br>
5、验证安装<br>
三、使用eAccelerator开发PHP代码<br>
1、API文档和接口说明<br>
2、开发范例<br>
四、附录和参考资料</p>
<p>一、eAccelerator介绍</p>
<p>1、背景<br>
eAccelerator 是一个免费开源的PHP加速、优化、编译和动态缓存的项目，它可以通过缓存PHP代码编译后的结果来提高PHP脚本的性能，使得一向很复杂和离我们很远的PHP脚本编译问题完全得到解决。通过使用eAccelerator，可以优化你的PHP代码执行速度，降低服务器负载，可以提高PHP应用执行速度最高达10倍。</p>
<p>eAccelerator 项目诞生于2004年，当时它是作为 <a href="http://sourceforge.net/projects/turck-mmcache" target="_blank">Turck MMCache </a>项目的一个分支提出并投入开发的。 Turck MMCache 由 Dmitry Stogov 开发，是个非常优秀的PHP内存缓存加速系统，如今仍然有很大部分 eAccelerator 的代码应用到该项目中，目前该项目有很长时间没有更新了，对于最新的PHP5.x的支持还未推出。</p>
<p>2、原理<br>
eAccelerator 通过把经过编译后的PHP代码缓存到共享内存中，并在用户访问的时候直接调用从而起到高效的加速作用。它的效率非常高，从创建共享内存到查找编译后的代码都在非常短的时间内完成，对于不能缓存到共享内存中的文件和代码，eAccelerator还可以把他们缓存到系统磁盘上。</p>
<p>eAccelerator 同样还支持PHP代码的编译和解释执行，你可以通过encoder.php脚本来对php代码进行编译达到保护代码的目的，经过编译后的代码必须运行在安装了eAccelerator的环境下。eAccelerator编译后的代码不能被反编译，它不象其他一些编译工具那样可以进行反编译，这将使得代码更加安全和高效。</p>
<p>二、eAccelerator安装配置</p>
<p>1、支持平台<br>
由于aAccelerator提供了大部分基于共享内存的API，所以在*nix的平台上将得到更好的支持，虽然也发布了基于windows平台的binary版本，但我在这里就只提供基于*nix平台的配置和说明，目前可以支持的平台包括Linux, FreeBSD, OpenBSD, Mac OS X, Solaris, AIX en HP-UX。</p>
<p>2、系统要求<br>
php4 or php5<br>
autoconf<br>
automake<br>
libtool<br>
m4<br>
eAccelerator 只支持使用 mod_php 或者 fastcgi mode 安装的PHP</p>
<p>3、安装<br>
先去eAccelerator官方下载最新版的源码包：<a href="https://sourceforge.net/project/showfiles.php?group_id=122249&amp;package_id=133446&amp;release_id=408973" target="_blank">eaccelerator-0.9.5-beta.tar.bz2</a></p>
<div class="hl-surround">
<div class="hl-main">
<p>#tar -zxvf ./eaccelerator-0.9.5-beta2.tar.bz2<br>
#cd eaccelerator-0.9.5-beta2<br>
#export PHP_PREFIX=&quot;/usr/local&quot; （把PHP安装目录导入到环境变量，FreeBSD默认是/usr/local）<br>
#$PHP_PREFIX/bin/phpize<br>
#./configure --enable-eaccelerator=shared --with-php-config=$PHP_PREFIX/bin/php-config<br>
#make<br>
#make install</p>
<p>4、ini文件配置<br>
安装完成，下面开始配置php.ini文件,eAccelerator提供了两种配置和调用方式，分别如下。</p>
<p>安装为 Zend extension 模式：</p>
<div class="hl-surround">
<div class="hl-main">zend_extension=&quot;/usr/local/lib/php/20050922/eaccelerator.so&quot;<br>
eaccelerator.shm_size=&quot;16&quot;<br>
eaccelerator.cache_dir=&quot;/tmp/eaccelerator&quot;<br>
eaccelerator.enable=&quot;1&quot;<br>
eaccelerator.optimizer=&quot;1&quot;<br>
eaccelerator.check_mtime=&quot;1&quot;<br>
eaccelerator.debug=&quot;0&quot;<br>
eaccelerator.log_file = &quot;/var/log/httpd/eaccelerator_log&quot;<br>
eaccelerator.filter=&quot;&quot;<br>
eaccelerator.shm_max=&quot;0&quot;<br>
eaccelerator.shm_ttl=&quot;0&quot;<br>
eaccelerator.shm_prune_period=&quot;0&quot;<br>
eaccelerator.shm_only=&quot;0&quot;<br>
eaccelerator.compress=&quot;1&quot;<br>
eaccelerator.compress_level=&quot;9&quot;</div>
</div>
<p>如果你使用了thread safe模式安装的PHP，你必须使用 &ldquo;zend_extension_ts&rdquo; 替换第一行的 &ldquo;zend_extension&rdquo;.</p>
<p>安装为 PHP extension 模式：（这是大部分采用的方式）</p>
<div class="hl-surround">
<div class="hl-main">extension=&quot;eaccelerator.so&quot;<br>
eaccelerator.shm_size=&quot;16&quot;<br>
eaccelerator.cache_dir=&quot;/tmp/eaccelerator&quot;<br>
eaccelerator.enable=&quot;1&quot;<br>
eaccelerator.optimizer=&quot;1&quot;<br>
eaccelerator.check_mtime=&quot;1&quot;<br>
eaccelerator.debug=&quot;0&quot;<br>
eaccelerator.log_file = &quot;/var/log/httpd/eaccelerator_log&quot;<br>
eaccelerator.filter=&quot;&quot;<br>
eaccelerator.shm_max=&quot;0&quot;<br>
eaccelerator.shm_ttl=&quot;0&quot;<br>
eaccelerator.shm_prune_period=&quot;0&quot;<br>
eaccelerator.shm_only=&quot;0&quot;<br>
eaccelerator.compress=&quot;1&quot;<br>
eaccelerator.compress_level=&quot;9&quot;</div>
</div>
<p>有关php.ini文件的详细配置说明，请参照源码目录的README文档或者访问官方文档：<a href="http://eaccelerator.net/wiki/Settings" target="_blank"><font color="#416e90">ini setting</font></a></p>
<p>完成安装配置后，我们最后要创建缓存目录</p>
<div class="hl-surround">
<div class="hl-main">#mkdir /tmp/eaccelerator<br>
#chmod 777 /tmp/eaccelerator</div>
</div>
<p>5、验证安装结果<br>
通过浏览器访问您的phpinfo()页面或者运行 php -i 得到php配置信息，里面如果看到类似下面的信息就表示安装成功了。</p>
<div class="hl-surround">
<div class="hl-main">This program makes use of the Zend Scripting Language Engine:<br>
Zend Engine v2.1.0, Copyright (c) 1998-2006 Zend Technologies<br>
&nbsp;&nbsp;   with eAccelerator v0.9.5-beta2, Copyright (c) 2004-2006 eAccelerator, by eAccelerator</div>
</div>
<p>我的机器上同时还安装了Zend Optimizer3.0.1，所以看到的信息如下：</p>
<div class="hl-surround">
<div class="hl-main">This program makes use of the Zend Scripting Language Engine:<br>
Zend Engine v2.1.0, Copyright (c) 1998-2006 Zend Technologies<br>
&nbsp;&nbsp;   with eAccelerator v0.9.5-beta2, Copyright (c) 2004-2006 eAccelerator, by eAccelerator<br>
&nbsp;&nbsp;   with Zend Extension Manager v1.0.10, Copyright (c) 2003-2006, by Zend Technologies<br>
&nbsp;&nbsp;   with Zend Optimizer v3.0.1, Copyright (c) 1998-2006, by Zend Technologies</div>
</div>
<p>如果你打开了eAccelerator的debug选项，可以从日志中看到类似下面的信息</p>
<div class="hl-surround">
<div class="hl-main">#tail /var/log/httpd/eAccelerator_log<br>
EACCELERATOR hit: &quot;/var/www/toplee.com/blog/index.php&quot;<br>
EACCELERATOR hit: &quot;/var/www/toplee.com/blog/wp-blog-header.php&quot;<br>
EACCELERATOR hit: &quot;/var/www/toplee.com/blog/wp-config.php&quot;<br>
EACCELERATOR hit: &quot;/var/www/toplee.com/blog/wp-settings.php&quot;<br>
EACCELERATOR hit: &quot;/var/www/toplee.com/blog/wp-content/plugins/wp-cache/wp-cache-phase1.php&quot;<br>
...</div>
</div>
<p>以上信息表示文件都得到了缓存和命中。</p>
<p>至此，我们就完成了全部的安装和配置，好好享受eAccelerator带给你的惊喜吧，根据Michael的测试，效果的确相当的好。</p>
<p> </p>
<p>三、在PHP中可以使用eAccelerator的API开发</p>
<p>1、API和文档说明：</p>
<p>eAccelerator提供了便捷便捷而又稳定的本机缓存实现方式，由于大部分代码实现基于共享内存，所以只能在*nix平台中使用，Windows平台Michael就暂时不知道何时有这方面的支持了。<br>
eAccelerator提供如下的API接口和文件：（下述文件均在源码包的doc/php/目录下）</p>
<p>文件列表：</p>
<div class="hl-surround">
<div class="hl-main">cache.php<br>
dasm.php<br>
encoder.php<br>
info.php<br>
loader.php<br>
session.php<br>
shared_memory.php</div>
</div>
<p>接口列表：</p>
<div class="hl-surround">
<div class="hl-main">array eaccelerator_cached_scripts () <br>
void eaccelerator_cache_output (string $key, string $eval_code, [int $ttl = 0]) <br>
void eaccelerator_cache_page (string $key, [int $ttl = 0]) <br>
void eaccelerator_cache_result (string $key, string $code, [int $ttl = 0])<br>
void eaccelerator_caching (boolean $flag) <br>
void eaccelerator_clean () <br>
void eaccelerator_clear ()<br>
array eaccelerator_dasm_file (mixed $filename) <br>
mixed eaccelerator_encode (mixed $src, [mixed $prefix = ''], [string $pre_content = ''], [string $post_content = ''])  <br>
void eaccelerator_gc ()<br>
mixed eaccelerator_get (string $key)  <br>
array eaccelerator_info () <br>
array eaccelerator_list_keys ()<br>
void eaccelerator_load () <br>
boolean eaccelerator_lock (string $key)<br>
void eaccelerator_optimizer (boolean $flag)  <br>
void eaccelerator_purge () <br>
boolean eaccelerator_put (string $key, mixed $value, [int $ttl = 0]) <br>
array eaccelerator_removed_scripts () <br>
boolean eaccelerator_rm (string $key) <br>
void eaccelerator_rm_page (string $key)  <br>
boolean eaccelerator_set_session_handlers () <br>
boolean eaccelerator_unlock (string $key)</div>
</div>
<p>有关上述文档详细说明请参考官方文档：<a href="http://bart.eaccelerator.net/doc/phpdoc/" target="_blank"><font color="#416e90">API Documents</font></a></p>
<p>下面有部分网友翻译后的接口说明：</p>
<div class="hl-surround">
<div class="hl-main">
<p><span style="color: gray">eaccelerator_put($key, $value, $ttl=0)<br>
  将 $value 以 $key 为键名存进缓存(php4下支持对像类型，看源码好像zend2里不支持了)，$ttl 是这个缓存的生命周期，单位是秒，省略该参数或指定为 0 表示不限时，直到服务器重启清空为止。<br>
 <br>
eaccelerator_get($key)<br>
  根据 $key 从缓存中返回相应的 eaccelerator_put() 存进去的数据，如果这项缓存已经过期或不存在那么返回值是 NULL<br>
 <br>
eaccelerator_rm($key)<br>
  根据 $key 移除缓存<br>
 <br>
eaccelerator_gc()<br>
  移除清理所有已过期的 key <br>
 <br>
eaccelerator_lock($key)<br>
  为 $key 加上锁定操作，以保证多进程多线程操作时数据的同步。需要调用 eaccelerator_unlock($key) 来释放这个锁或等待程序请求结束时自动释放这个锁。<br>
  例如:<br>
  </span><span style="color: blue">&lt;?php</span><span style="color: gray"><br>
&nbsp;&nbsp;   </span><span style="color: blue">eaccelerator_lock</span><span style="color: olive">(</span><span style="color: #8b0000">&quot;</span><span style="color: red">count</span><span style="color: #8b0000">&quot;</span><span style="color: olive">)</span><span style="color: gray">;<br>
&nbsp;&nbsp;   </span><span style="color: blue">eaccelerator_put</span><span style="color: olive">(</span><span style="color: #8b0000">&quot;</span><span style="color: red">count</span><span style="color: #8b0000">&quot;</span><span style="color: gray">,</span><span style="color: blue">eaccelerator_get</span><span style="color: olive">(</span><span style="color: #8b0000">&quot;</span><span style="color: red">count</span><span style="color: #8b0000">&quot;</span><span style="color: olive">)</span><span style="color: gray">+</span><span style="color: maroon">1</span><span style="color: olive">)</span><span style="color: gray">);<br>
  </span><span style="color: blue">?&gt;</span><span style="color: gray"><br>
 <br>
eaccelerator_unlock($key)<br>
  根据 $key 释放锁<br>
 <br>
eaccelerator_cache_output($key, $eval_code, $ttl=0)<br>
  将 $eval_code 代码的输出缓存 $ttl 秒，（$ttl参数同 eacclerator_put）<br>
  例如：<br>
  </span><span style="color: blue">&lt;?php</span><span style="color: gray"> </span><span style="color: blue">eaccelerator_cache_output</span><span style="color: olive">(</span><span style="color: #8b0000">'</span><span style="color: red">test</span><span style="color: #8b0000">'</span><span style="color: gray">, </span><span style="color: #8b0000">'</span><span style="color: red">echo time(); phpinfo();</span><span style="color: #8b0000">'</span><span style="color: gray">, </span><span style="color: maroon">30</span><span style="color: olive">)</span><span style="color: gray">; </span><span style="color: blue">?&gt;</span><span style="color: gray"><br>
 <br>
eaccelerator_cache_result($key, $eval_code, $ttl=0)<br>
  将 $eval_code 代码的执行结果缓存 $ttl 秒，（$ttl参数同 eacclerator_put），类似 cache_output<br>
  例如：<br>
  </span><span style="color: blue">&lt;?php</span><span style="color: gray"> </span><span style="color: blue">eaccelerator_cache_result</span><span style="color: olive">(</span><span style="color: #8b0000">'</span><span style="color: red">test</span><span style="color: #8b0000">'</span><span style="color: gray">, </span><span style="color: #8b0000">'</span><span style="color: red"> time() . &quot;Hello&quot;;</span><span style="color: #8b0000">'</span><span style="color: gray">, </span><span style="color: maroon">30</span><span style="color: olive">)</span><span style="color: gray">; </span><span style="color: blue">?&gt;</span><span style="color: gray"><br>
 <br>
eaccelerator_cache_page($key, $ttl=0)<br>
  将当前整页缓存 $ttl 秒。<br>
  例如：<br>
  </span><span style="color: blue">&lt;?php</span><span style="color: gray"><br>
&nbsp;&nbsp;   </span><span style="color: blue">eaccelerator_cache_page</span><span style="color: olive">(</span><span style="color: #00008b">$_SERVER</span><span style="color: olive">[</span><span style="color: #8b0000">'</span><span style="color: red">PHP_SELF</span><span style="color: #8b0000">'</span><span style="color: olive">]</span><span style="color: gray">.</span><span style="color: #8b0000">'</span><span style="color: red">?GET=</span><span style="color: #8b0000">'</span><span style="color: gray">.</span><span style="color: blue">serialize</span><span style="color: olive">(</span><span style="color: #00008b">$_GET</span><span style="color: olive">)</span><span style="color: gray">,</span><span style="color: maroon">30</span><span style="color: olive">)</span><span style="color: gray">;<br>
&nbsp;&nbsp;   </span><span style="color: green">echo</span><span style="color: gray"> </span><span style="color: blue">time</span><span style="color: olive">()</span><span style="color: gray">;<br>
&nbsp;&nbsp;   </span><span style="color: blue">phpinfo</span><span style="color: olive">()</span><span style="color: gray">;<br>
  </span><span style="color: blue">?&gt;</span><span style="color: gray"><br>
 <br>
eaccelerator_rm_page($key)<br>
  删除由  eaccelerator_cache_page() 执行的缓存，参数也是 $key</span></p>
<span style="color: gray">
<p>2、PHP代码中使用eAccelerator加速</p>
<p>下面有一个测试的代码，你可以测试一下eAccelerator强大的威力：（该代码在 cli 模式下可能无效）</p>
<div class="hl-surround">
<div class="hl-main">
<p><span style="color: blue">&lt;?php</span><span style="color: gray"><br>
</span><span style="color: green">class</span><span style="color: gray"> </span><span style="color: blue">test_cache</span><span style="color: gray"> </span><span style="color: olive">{</span><span style="color: gray"><br>
  </span><span style="color: green">var</span><span style="color: gray"> </span><span style="color: #00008b">$pro</span><span style="color: gray"> = </span><span style="color: #8b0000">'</span><span style="color: red">hello</span><span style="color: #8b0000">'</span><span style="color: gray">;<br>
 <br>
  </span><span style="color: green">function</span><span style="color: gray"> </span><span style="color: blue">test_cache</span><span style="color: olive">()</span><span style="color: gray"> </span><span style="color: olive">{</span><span style="color: gray"><br>
&nbsp;&nbsp;   </span><span style="color: green">echo</span><span style="color: gray"> </span><span style="color: #8b0000">&quot;</span><span style="color: red">Object Created!&lt;br&gt;</span><span style="color: navy">\n</span><span style="color: #8b0000">&quot;</span><span style="color: gray">;<br>
  </span><span style="color: olive">}</span><span style="color: gray"><br>
  </span><span style="color: green">function</span><span style="color: gray"> </span><span style="color: blue">func</span><span style="color: olive">()</span><span style="color: gray"> </span><span style="color: olive">{</span><span style="color: gray"><br>
&nbsp;&nbsp;   </span><span style="color: green">echo</span><span style="color: gray"> </span><span style="color: #8b0000">'</span><span style="color: red">, the world!</span><span style="color: #8b0000">'</span><span style="color: gray">;<br>
  </span><span style="color: olive">}</span><span style="color: gray"><br>
  </span><span style="color: green">function</span><span style="color: gray"> </span><span style="color: blue">now</span><span style="color: olive">(</span><span style="color: #00008b">$t</span><span style="color: olive">)</span><span style="color: gray"> </span><span style="color: olive">{</span><span style="color: gray"><br>
&nbsp;&nbsp;   </span><span style="color: green">echo</span><span style="color: gray"> </span><span style="color: blue">date</span><span style="color: olive">(</span><span style="color: #8b0000">'</span><span style="color: red">Y-m-d H:i:s</span><span style="color: #8b0000">'</span><span style="color: gray">, </span><span style="color: #00008b">$t</span><span style="color: olive">)</span><span style="color: gray">;<br>
  </span><span style="color: olive">}</span><span style="color: gray"><br>
</span><span style="color: olive">}</span><span style="color: gray"><br>
 <br>
</span><span style="color: #00008b">$tt</span><span style="color: gray"> = </span><span style="color: blue">eaccelerator_get</span><span style="color: olive">(</span><span style="color: #8b0000">&quot;</span><span style="color: red">test_tt</span><span style="color: #8b0000">&quot;</span><span style="color: olive">)</span><span style="color: gray">;<br>
</span><span style="color: green">if</span><span style="color: gray"> </span><span style="color: olive">(</span><span style="color: gray">!</span><span style="color: #00008b">$tt</span><span style="color: olive">)</span><span style="color: gray"><br>
</span><span style="color: olive">{</span><span style="color: gray"><br>
  </span><span style="color: #00008b">$tt</span><span style="color: gray"> = </span><span style="color: green">new</span><span style="color: gray"> </span><span style="color: blue">test_cache</span><span style="color: gray">;<br>
  </span><span style="color: blue">eaccelerator_put</span><span style="color: olive">(</span><span style="color: #8b0000">&quot;</span><span style="color: red">test_tt</span><span style="color: #8b0000">&quot;</span><span style="color: gray">, </span><span style="color: #00008b">$tt</span><span style="color: olive">)</span><span style="color: gray">;<br>
  </span><span style="color: green">echo</span><span style="color: gray"> </span><span style="color: #8b0000">&quot;</span><span style="color: red">no cached!&lt;br&gt;</span><span style="color: navy">\n</span><span style="color: #8b0000">&quot;</span><span style="color: gray">;<br>
</span><span style="color: olive">}</span><span style="color: gray"><br>
</span><span style="color: green">else</span><span style="color: gray"> </span><span style="color: olive">{</span><span style="color: gray"><br>
  </span><span style="color: green">echo</span><span style="color: gray"> </span><span style="color: #8b0000">&quot;</span><span style="color: red">cached&lt;br&gt;</span><span style="color: navy">\n</span><span style="color: #8b0000">&quot;</span><span style="color: gray">;<br>
</span><span style="color: olive">}</span><span style="color: gray"><br>
 <br>
</span><span style="color: green">echo</span><span style="color: gray"> </span><span style="color: #00008b">$tt</span><span style="color: gray">-&gt;</span><span style="color: blue">pro</span><span style="color: gray">; <br>
</span><span style="color: #00008b">$tt</span><span style="color: gray">-&gt;</span><span style="color: blue">func</span><span style="color: olive">()</span><span style="color: gray">;<br>
</span><span style="color: #00008b">$tt</span><span style="color: gray">-&gt;</span><span style="color: blue">now</span><span style="color: olive">(</span><span style="color: blue">time</span><span style="color: olive">()</span><span style="color: gray"> + </span><span style="color: maroon">86400</span><span style="color: olive">)</span><span style="color: gray">;<br>
</span><span style="color: blue">?&gt;</span></p>
<p><span style="color: blue">转:<a href="http://www.toplee.com/blog/?p=100"><font color="#416e90">http://www.toplee.com/blog/?p=100</font></a></span></p>
</div>
</div>
</span></div>
</div>
</div>
</div> <a href="http://hi.baidu.com/mikyliang/blog/item/228d4fee15b0a9f2b3fb9565.html">阅读全文</a>
		
		<br/><b>类别：</b><a href="http://hi.baidu.com/mikyliang/blog/category/%D7%AA%D4%D8">转载</a>&nbsp;<a href="http://hi.baidu.com/mikyliang/blog/item/228d4fee15b0a9f2b3fb9565.html#comment">查看评论</a>]]></description>
        <pubDate>2009-09-09  16:16</pubDate>
        <category><![CDATA[转载]]></category>
        <author><![CDATA[mikyliang]]></author>
		<guid>http://hi.baidu.com/mikyliang/blog/item/228d4fee15b0a9f2b3fb9565.html</guid>
</item>

<item>
        <title><![CDATA[JavaScript面向对象编程[三] 自定义事件]]></title>
        <link><![CDATA[http://hi.baidu.com/mikyliang/blog/item/14224543a70b45189213c679.html]]></link>
        <description><![CDATA[
		
		<p>上一篇给foo类增加了<br>
addEvent和removeEvent方便事件的注册与注销</p>
<p>这次总结下自定义事件的几种方法</p>
<div class="UBBPanel codePanel">
<div class="UBBTitle">程序代码</div>
<div class="UBBContent">
<p>&lt;script type=&rdquo;text/javascript&rdquo;&gt;<br>
&lt;!&ndash;</p>
<p>var foo = function(){ this.init.apply(this,arguments);};</p>
<p>foo.prototype = {<br>
init:function(_name){<br>
this.name = _name;<br>
this.addEvent(&rsquo;click&rsquo;,document,this.say,this,&rsquo;hello world!&rsquo;);<br>
},<br>
say:function(_ev,_word){<br>
alert(this.name +&rsquo;:&rsquo; +_word);<br>
this.stop();<br>
this.onSay(_word);<br>
},<br>
stop:function(){<br>
this.removeEvent(&rsquo;click&rsquo;,document,this.say);<br>
},<br>
addEvent:function(_event,_element,_fn,_scope,_args){<br>
var args = Array.prototype.slice.call(arguments, 0);<br>
ev = args.shift(),<br>
element = args.shift(),<br>
fn = args.shift(),<br>
scope = args.length&gt;0?args.shift():window;<br>
element['e'+ev+fn] =&nbsp;&nbsp; function(_ev){<br>
_ev == _ev || window.event;<br>
args.unshift(_ev);<br>
fn.apply(scope,args);<br>
};<br>
if (element.addEventListener) {<br>
element.addEventListener(ev, element['e'+ev+fn], false);<br>
} else if (element.attachEvent) {<br>
element.attachEvent(&rdquo;on&rdquo; +ev, element['e'+ev+fn]);<br>
}<br>
},<br>
removeEvent:function(_event,_element,_fn){<br>
if (_element.removeEventListener) {<br>
_element.removeEventListener(_event, _element['e'+_event+_fn], false);<br>
} else if (_element.detachEvent) {<br>
_element.detachEvent(&rdquo;on&rdquo; +_event, _element['e'+_event+_fn]);<br>
}<br>
try {<br>
delete _element['e'+_event+_fn];<br>
}catch(_ex){<br>
_element['e'+_event+_fn] = null;<br>
}<br>
},<br>
onSay:function(){}</p>
<p>}</p>
<p>var a = new foo(&rsquo;llinzzi&rsquo;);<br>
a.onSay = function(_word){<br>
alert(&rsquo;事件:&rsquo;+this.name +&rsquo;刚说了&rsquo;+ _word);<br>
}</p>
</div>
</div>
<div class="UBBPanel">
<div class="UBBTitle">HTML代码</div>
<div class="UBBContent"> &lt;br /&gt; &lt;html&gt;&lt;br /&gt; &lt;head&gt;&lt;/p&gt; &lt;p&gt;&lt;meta http-equiv=&rdquo;Content-Type&rdquo; content=&rdquo;text/html; charset=utf-8″ &gt;&lt;br /&gt; &lt;meta name=&rdquo;keywords&rdquo; content=&rdquo;&quot; &gt;&lt;br /&gt; &lt;meta name=&rdquo;description&rdquo; content=&rdquo;&quot; &gt;&lt;br /&gt; &lt;/head&gt;&lt;br /&gt; &lt;body&gt;&lt;br /&gt; &lt;mce:script type=mce-&rdquo;text/javascript&rdquo;&gt;&lt;!&ndash; var foo = function(){ this.init.apply(this,arguments);}; foo.prototype = { init:function(_name){ this.name = _name; this.addEvent(&rsquo;click&rsquo;,document,this.say,this,&rsquo;hello world!&rsquo;); }, say:function(_ev,_word){ alert(this.name +&rsquo;:&rsquo; +_word); this.stop(); this.onSay(_word); }, stop:function(){ this.removeEvent(&rsquo;click&rsquo;,document,this.say); }, addEvent:function(_event,_element,_fn,_scope,_args){ var args = Array.prototype.slice.call(arguments, 0); ev = args.shift(), element = args.shift(), fn = args.shift(), scope = args.length&gt;0?args.shift():window; element['e'+ev+fn] =  function(_ev){ _ev == _ev || window.event; args.unshift(_ev); fn.apply(scope,args); }; if (element.addEventListener) { element.addEventListener(ev, element['e'+ev+fn], false); } else if (element.attachEvent) { element.attachEvent(&amp;#34;on&amp;#34; +ev, element['e'+ev+fn]); } }, removeEvent:function(_event,_element,_fn){ if (_element.removeEventListener) { _element.removeEventListener(_event, _element['e'+_event+_fn], false); } else if (_element.detachEvent) { _element.detachEvent(&amp;#34;on&amp;#34; +_event, _element['e'+_event+_fn]); } try { del&amp;#101;te _element['e'+_event+_fn]; }catch(_ex){ _element['e'+_event+_fn] = null; } }, onSay:function(){} } var a = new foo(&rsquo;llinzzi&rsquo;); a.onSay = function(_word){ alert(&rsquo;事件:&rsquo;+this.name +&rsquo;刚说了&rsquo;+ _word); } // &ndash;&gt;&lt;/mce:script&gt;&lt;br /&gt; &lt;/body&gt;&lt;br /&gt; &lt;/html&gt;&lt;br /&gt;  </div>
</div>
<p>增加了个onSay的事件，在类定义的时候只定义成空函数，然后在需要的时候调用，定义具体的方法是在类实例化后，给实例中的onSay</p>
<p>缺点是只能定义一次的onSay的回调，如果多次定义后面的会把前面的覆盖掉，修改一下。</p>
<div class="UBBPanel codePanel">
<div class="UBBTitle">程序代码</div>
<div class="UBBContent">
<p>var foo = function(){ this.init.apply(this,arguments);};</p>
<p>foo.prototype = {<br>
init:function(_name){<br>
this.name = _name;<br>
this.addEvent(&rsquo;click&rsquo;,document,this.say,this,&rsquo;hello world!&rsquo;);<br>
},<br>
say:function(_ev,_word){<br>
alert(this.name +&rsquo;:&rsquo; +_word);<br>
this.stop();<br>
this._onSay(_word);<br>
},<br>
stop:function(){<br>
this.removeEvent(&rsquo;click&rsquo;,document,this.say);<br>
},<br>
addEvent:function(_event,_element,_fn,_scope,_args){<br>
var args = Array.prototype.slice.call(arguments, 0);<br>
ev = args.shift(),<br>
element = args.shift(),<br>
fn = args.shift(),<br>
scope = args.length&gt;0?args.shift():window;<br>
element['e'+ev+fn] =&nbsp;&nbsp; function(_ev){<br>
_ev == _ev || window.event;<br>
args.unshift(_ev);<br>
fn.apply(scope,args);<br>
};<br>
if (element.addEventListener) {<br>
element.addEventListener(ev, element['e'+ev+fn], false);<br>
} else if (element.attachEvent) {<br>
element.attachEvent(&rdquo;on&rdquo; +ev, element['e'+ev+fn]);<br>
}<br>
},<br>
removeEvent:function(_event,_element,_fn){<br>
if (_element.removeEventListener) {<br>
_element.removeEventListener(_event, _element['e'+_event+_fn], false);<br>
} else if (_element.detachEvent) {<br>
_element.detachEvent(&rdquo;on&rdquo; +_event, _element['e'+_event+_fn]);<br>
}<br>
try {<br>
delete _element['e'+_event+_fn];<br>
}catch(_ex){<br>
_element['e'+_event+_fn] = null;<br>
}<br>
},<br>
_onSay:function(){<br>
if(!this._onSayArray) return;<br>
for(var i=0; i&lt;this._onSayArray.length; i++){<br>
this._onSayArray[i].apply(this,arguments);<br>
}<br>
},<br>
addOnSay:function(_fn){<br>
if(!this._onSayArray) this._onSayArray = new Array();<br>
this._onSayArray.push(_fn);<br>
}<br>
}</p>
<p>var a = new foo(&rsquo;llinzzi&rsquo;);<br>
a.addOnSay(function(_word){<br>
alert(&rsquo;事件1:&rsquo;+this.name +&rsquo;刚说了&rsquo;+ _word);<br>
});<br>
a.addOnSay(function(_word){<br>
alert(&rsquo;事件2:&rsquo;+this.name +&rsquo;刚说了&rsquo;+ _word);<br>
});</p>
</div>
</div>
<div class="UBBPanel">
<div class="UBBTitle">HTML代码</div>
<div class="UBBContent"> &lt;br /&gt; &lt;html&gt;&lt;br /&gt; &lt;head&gt;&lt;/p&gt; &lt;p&gt;&lt;meta http-equiv=&rdquo;Content-Type&rdquo; content=&rdquo;text/html; charset=utf-8″ &gt;&lt;br /&gt; &lt;meta name=&rdquo;keywords&rdquo; content=&rdquo;&quot; &gt;&lt;br /&gt; &lt;meta name=&rdquo;description&rdquo; content=&rdquo;&quot; &gt;&lt;br /&gt; &lt;/head&gt;&lt;br /&gt; &lt;body&gt;&lt;br /&gt; &lt;mce:script type=mce-&rdquo;text/javascript&rdquo;&gt;&lt;!&ndash; var foo = function(){ this.init.apply(this,arguments);}; foo.prototype = { init:function(_name){ this.name = _name; this.addEvent(&rsquo;click&rsquo;,document,this.say,this,&rsquo;hello world!&rsquo;); }, say:function(_ev,_word){ alert(this.name +&rsquo;:&rsquo; +_word); this.stop(); this._onSay(_word); }, stop:function(){ this.removeEvent(&rsquo;click&rsquo;,document,this.say); }, addEvent:function(_event,_element,_fn,_scope,_args){ var args = Array.prototype.slice.call(arguments, 0); ev = args.shift(), element = args.shift(), fn = args.shift(), scope = args.length&gt;0?args.shift():window; element['e'+ev+fn] =  function(_ev){ _ev == _ev || window.event; args.unshift(_ev); fn.apply(scope,args); }; if (element.addEventListener) { element.addEventListener(ev, element['e'+ev+fn], false); } else if (element.attachEvent) { element.attachEvent(&amp;#34;on&amp;#34; +ev, element['e'+ev+fn]); } }, removeEvent:function(_event,_element,_fn){ if (_element.removeEventListener) { _element.removeEventListener(_event, _element['e'+_event+_fn], false); } else if (_element.detachEvent) { _element.detachEvent(&amp;#34;on&amp;#34; +_event, _element['e'+_event+_fn]); } try { del&amp;#101;te _element['e'+_event+_fn]; }catch(_ex){ _element['e'+_event+_fn] = null; } }, _onSay:function(){ if(!this._onSayArray) return; for(var i=0; i &lt;this._onSayArray.length; i++){ this._onSayArray[i].apply(this,arguments); } }, addOnSay:function(_fn){ if(!this._onSayArray) this._onSayArray = new Array(); this._onSayArray.push(_fn); } } var a = new foo(&rsquo;llinzzi&rsquo;); a.addOnSay(function(_word){ alert(&rsquo;事件1:&rsquo;+this.name +&rsquo;刚说了&rsquo;+ _word); }); a.addOnSay(function(_word){ alert(&rsquo;事件2:&rsquo;+this.name +&rsquo;刚说了&rsquo;+ _word); }); // &ndash;&gt;&lt;/mce:script&gt;&lt;br /&gt; &lt;/body&gt;&lt;br /&gt; &lt;/html&gt;&lt;br /&gt;  </div>
</div>
<p>实例通过addOnSay方法来增加事件响应，可以增加多个。</p>
<p>缺点，代码繁琐，如果要增加addOnSayAfter addOnSayBefore 就要增加很多代码。</p>
<p>再修改一下</p>
<div class="UBBPanel codePanel">
<div class="UBBTitle">程序代码</div>
<div class="UBBContent">
<p>var foo = function(){ this.init.apply(this,arguments);};</p>
<p>foo.prototype = {<br>
init:function(_name){<br>
this.name = _name;<br>
this.addEvent(&rsquo;click&rsquo;,document,this.say,this,&rsquo;hello world!&rsquo;);<br>
},<br>
say:function(_ev,_word){<br>
this.fireEvent(&rsquo;saybefore&rsquo;,_word);<br>
alert(this.name +&rsquo;:&rsquo; +_word);<br>
this.stop();<br>
this.fireEvent(&rsquo;sayafter&rsquo;,_word);<br>
},<br>
stop:function(){<br>
this.removeEvent(&rsquo;click&rsquo;,document,this.say);<br>
},<br>
addEvent:function(_event,_element,_fn,_scope,_args){<br>
var args = Array.prototype.slice.call(arguments, 0);<br>
ev = args.shift(),<br>
element = args.shift(),<br>
fn = args.shift(),<br>
scope = args.length&gt;0?args.shift():window;<br>
element['e'+ev+fn] =&nbsp;&nbsp; function(_ev){<br>
_ev == _ev || window.event;<br>
args.unshift(_ev);<br>
fn.apply(scope,args);<br>
};<br>
if (element.addEventListener) {<br>
element.addEventListener(ev, element['e'+ev+fn], false);<br>
} else if (element.attachEvent) {<br>
element.attachEvent(&rdquo;on&rdquo; +ev, element['e'+ev+fn]);<br>
}<br>
},<br>
removeEvent:function(_event,_element,_fn){<br>
if (_element.removeEventListener) {<br>
_element.removeEventListener(_event, _element['e'+_event+_fn], false);<br>
} else if (_element.detachEvent) {<br>
_element.detachEvent(&rdquo;on&rdquo; +_event, _element['e'+_event+_fn]);<br>
}<br>
try {<br>
delete _element['e'+_event+_fn];<br>
}catch(_ex){<br>
_element['e'+_event+_fn] = null;<br>
}<br>
},<br>
fireEvent:function(){<br>
var args = Array.prototype.slice.call(arguments, 0);<br>
var _event = args.shift();<br>
if(!this.cusEvents) return;<br>
if(!this.cusEvents[_event]) return;<br>
for(var i=0; i&lt;this.cusEvents[_event].length; i++){<br>
this.cusEvents[_event][i].apply(this,args);<br>
}<br>
},<br>
catchEvent:function(_event,_fn){<br>
if(!this.cusEvents) this.cusEvents = {}<br>
if(!this.cusEvents[_event]) this.cusEvents[_event] = new Array();<br>
this.cusEvents[_event].push(_fn);<br>
}<br>
}</p>
<p>var a = new foo(&rsquo;llinzzi&rsquo;);</p>
<p>a.catchEvent(&rsquo;saybefore&rsquo;,function(_word){<br>
alert(&rsquo;事件1:&rsquo;+this.name +&rsquo;想说&rsquo;+ _word);<br>
});</p>
<p>a.catchEvent(&rsquo;sayafter&rsquo;,function(_word){<br>
alert(&rsquo;事件2:&rsquo;+this.name +&rsquo;刚说了&rsquo;+ _word);<br>
});</p>
</div>
</div>
<div class="UBBPanel">
<div class="UBBTitle">HTML代码</div>
<div class="UBBContent"> &lt;br /&gt; &lt;html&gt;&lt;br /&gt; &lt;head&gt;&lt;/p&gt; &lt;p&gt;&lt;meta http-equiv=&rdquo;Content-Type&rdquo; content=&rdquo;text/html; charset=utf-8″ &gt;&lt;br /&gt; &lt;meta name=&rdquo;keywords&rdquo; content=&rdquo;&quot; &gt;&lt;br /&gt; &lt;meta name=&rdquo;description&rdquo; content=&rdquo;&quot; &gt;&lt;br /&gt; &lt;/head&gt;&lt;br /&gt; &lt;body&gt;&lt;br /&gt; &lt;mce:script type=mce-&rdquo;text/javascript&rdquo;&gt;&lt;!&ndash; var foo = function(){ this.init.apply(this,arguments);}; foo.prototype = { init:function(_name){ this.name = _name; this.addEvent(&rsquo;click&rsquo;,document,this.say,this,&rsquo;hello world!&rsquo;); }, say:function(_ev,_word){ this.fireEvent(&rsquo;saybefore&rsquo;,_word); alert(this.name +&rsquo;:&rsquo; +_word); this.stop(); this.fireEvent(&rsquo;sayafter&rsquo;,_word); }, stop:function(){ this.removeEvent(&rsquo;click&rsquo;,document,this.say); }, addEvent:function(_event,_element,_fn,_scope,_args){ var args = Array.prototype.slice.call(arguments, 0); ev = args.shift(), element = args.shift(), fn = args.shift(), scope = args.length&gt;0?args.shift():window; element['e'+ev+fn] =  function(_ev){ _ev == _ev || window.event; args.unshift(_ev); fn.apply(scope,args); }; if (element.addEventListener) { element.addEventListener(ev, element['e'+ev+fn], false); } else if (element.attachEvent) { element.attachEvent(&amp;#34;on&amp;#34; +ev, element['e'+ev+fn]); } }, removeEvent:function(_event,_element,_fn){ if (_element.removeEventListener) { _element.removeEventListener(_event, _element['e'+_event+_fn], false); } else if (_element.detachEvent) { _element.detachEvent(&amp;#34;on&amp;#34; +_event, _element['e'+_event+_fn]); } try { del&amp;#101;te _element['e'+_event+_fn]; }catch(_ex){ _element['e'+_event+_fn] = null; } }, fireEvent:function(){ var args = Array.prototype.slice.call(arguments, 0); var _event = args.shift(); if(!this.cusEvents) return; if(!this.cusEvents[_event]) return; for(var i=0; i &lt;this.cusEvents[_event].length; i++){ this.cusEvents[_event][i].apply(this,args); } }, catchEvent:function(_event,_fn){ if(!this.cusEvents) this.cusEvents = {} if(!this.cusEvents[_event]) this.cusEvents[_event] = new Array(); this.cusEvents[_event].push(_fn); } } var a = new foo(&rsquo;llinzzi&rsquo;); a.catchEvent(&rsquo;saybefore&rsquo;,function(_word){ alert(&rsquo;事件1:&rsquo;+this.name +&rsquo;想说&rsquo;+ _word); }); a.catchEvent(&rsquo;sayafter&rsquo;,function(_word){ alert(&rsquo;事件2:&rsquo;+this.name +&rsquo;刚说了&rsquo;+ _word); }); // &ndash;&gt;&lt;/mce:script&gt;&lt;br /&gt; &lt;/body&gt;&lt;br /&gt; &lt;/html&gt;&lt;br /&gt;  </div>
</div>
<p>最后如果将catchEvent fireEvent addEvent removeEvent 单独放在一个类.EventHeloper<br>
将addEvent和catchEvent整合<br>
EventHeloper.addEvent(element/object,dom event/custom event,callback) 这样还是很方便的。</p>
<div class="UBBPanel codePanel">
<div class="UBBTitle">程序代码</div>
<div class="UBBContent">
<p>EventHelper = {<br>
Events:{Dom:{},Custom:{}},<br>
addEvent:function(_object,_event,_fn,_scope,_args){<br>
var args = Array.prototype.slice.call(arguments, 0),<br>
obj = args.shift(),<br>
ev = args.shift(),<br>
fn = args.shift(),<br>
scope = args.length&gt;0?args.shift():window;<br>
var eType = obj.nodeType?&rsquo;Dom&rsquo;:'Custom&rsquo;;<br>
var fun;<br>
if(eType==&rsquo;Dom&rsquo;){<br>
sfn = function(_ev){<br>
_ev == _ev || window.event;<br>
args.unshift(_ev);<br>
fn.apply(scope,args);<br>
}<br>
if (obj.addEventListener) {<br>
obj.addEventListener(ev,sfn, false);<br>
} else if (obj.attachEvent) {<br>
obj.attachEvent(&rdquo;on&rdquo; +ev,sfn);<br>
}<br>
}else {<br>
sfn = function(){<br>
var __sargs = Array.prototype.slice.call(arguments, 0);<br>
var _sargs = __sargs.concat(args);<br>
fn.apply(scope,_sargs);<br>
}<br>
}<br>
fun = { fn:fn,sfn:sfn };<br>
this.Events[eType][obj] = this.Events[eType][obj] || {};<br>
this.Events[eType][obj][ev] = this.Events[eType][obj][ev] || new Array();<br>
this.Events[eType][obj][ev].push(fun);<br>
},<br>
removeEvent:function(_object,_event,_fn){<br>
var obj = _object,<br>
ev = _event,<br>
fn = _fn;<br>
var eType = obj.nodeType?&rsquo;Dom&rsquo;:'Custom&rsquo;;<br>
if(!this.Events[eType][obj]) return;</p>
<p>var fun;<br>
for( var i=0; i&lt;this.Events[eType][obj][ev].length;i++){<br>
if(fn == this.Events[eType][obj][ev][i].fn){<br>
fun = this.Events[eType][obj][ev][i].sfn;<br>
this.Events[eType][obj][ev].splice(i,1);<br>
break;<br>
}<br>
}<br>
if(eType==&rsquo;Dom&rsquo;){<br>
if (obj.removeEventListener) {<br>
obj.removeEventListener(ev, fun, false);<br>
} else if (obj.detachEvent) {<br>
obj.detachEvent(&rdquo;on&rdquo; + ev, fun);<br>
}<br>
}</p>
<p>},<br>
fireEvent:function(_object,_event){<br>
var args = Array.prototype.slice.call(arguments, 0),<br>
obj = args.shift(),<br>
ev = args.shift();<br>
var eType = &lsquo;Custom&rsquo;;<br>
if((!this.Events[eType][obj]) || (!this.Events[eType][obj][ev])) return;</p>
<p>for(var i=0; i&lt;this.Events[eType][obj][ev].length; i++){<br>
this.Events[eType][obj][ev][i].sfn.apply(window,args);<br>
}<br>
}<br>
}</p>
</div>
</div>
<p>修改一下演示的例子</p>
<div class="UBBPanel">
<div class="UBBTitle">HTML代码</div>
<div class="UBBContent"> &lt;br /&gt; &lt;html&gt;&lt;br /&gt; &lt;head&gt;&lt;/p&gt; &lt;p&gt;&lt;meta http-equiv=&rdquo;Content-Type&rdquo; content=&rdquo;text/html; charset=utf-8″ &gt;&lt;br /&gt; &lt;meta name=&rdquo;keywords&rdquo; content=&rdquo;&quot; &gt;&lt;br /&gt; &lt;meta name=&rdquo;description&rdquo; content=&rdquo;&quot; &gt;&lt;br /&gt; &lt;/head&gt;&lt;br /&gt; &lt;body&gt;&lt;br /&gt; &lt;mce:script type=mce-&rdquo;text/javascript&rdquo;&gt;&lt;!&ndash; EventHelper = { Events:{Dom:{},Custom:{}}, addEvent:function(_object,_event,_fn,_scope,_args){ var args = Array.prototype.slice.call(arguments, 0), obj = args.shift(), ev = args.shift(), fn = args.shift(), scope = args.length&gt;0?args.shift():window; var eType = obj.nodeType?&rsquo;Dom&rsquo;:'Custom&rsquo;; var fun; if(eType==&rsquo;Dom&rsquo;){ sfn = function(_ev){ _ev == _ev || window.event; args.unshift(_ev); fn.apply(scope,args); } if (obj.addEventListener) { obj.addEventListener(ev,sfn, false); } else if (obj.attachEvent) { obj.attachEvent(&amp;#34;on&amp;#34; +ev,sfn); } }else { sfn = function(){ var __sargs = Array.prototype.slice.call(arguments, 0); var _sargs = __sargs.concat(args); fn.apply(scope,_sargs); } } fun = { fn:fn,sfn:sfn }; this.Events[eType][obj] = this.Events[eType][obj] || {}; this.Events[eType][obj][ev] = this.Events[eType][obj][ev] || new Array(); this.Events[eType][obj][ev].push(fun); }, removeEvent:function(_object,_event,_fn){ var obj = _object, ev = _event, fn = _fn; var eType = obj.nodeType?&rsquo;Dom&rsquo;:'Custom&rsquo;; if(!this.Events[eType][obj]) return; var fun; for( var i=0; i &lt;this.Events[eType][obj][ev].length;i++){ if(fn == this.Events[eType][obj][ev][i].fn){ fun = this.Events[eType][obj][ev][i].sfn; this.Events[eType][obj][ev].splice(i,1); break; } } if(eType==&rsquo;Dom&rsquo;){ if (obj.removeEventListener) { obj.removeEventListener(ev, fun, false); } else if (obj.detachEvent) { obj.detachEvent(&amp;#34;on&amp;#34; + ev, fun); } } }, fireEvent:function(_object,_event){ var args = Array.prototype.slice.call(arguments, 0), obj = args.shift(), ev = args.shift(); var eType = &lsquo;Custom&rsquo;; if((!this.Events[eType][obj]) || (!this.Events[eType][obj][ev])) return; for(var i=0; i&lt;this.Events[eType][obj][ev].length; i++){ this.Events[eType][obj][ev][i].sfn.apply(window,args); } } } var foo = function(){ this.init.apply(this,arguments);}; foo.prototype = { init:function(_name){ this.name = _name; EventHelper.addEvent(document,&rsquo;click&rsquo;,this.say,this,&rsquo;hello world!&rsquo;); }, say:function(_ev,_word){ EventHelper.fireEvent(this,&rsquo;saybefore&rsquo;,_word); alert(this.name +&rsquo;:&rsquo; +_word); this.stop(); EventHelper.fireEvent(this,&rsquo;sayafter&rsquo;,_word); }, stop:function(){ EventHelper.removeEvent(document,&rsquo;click&rsquo;,this.say); } } var a = new foo(&rsquo;llinzzi&rsquo;); function sayBefore(_word,_word2){ alert(&rsquo;事件1:&rsquo;+this.name +&rsquo;想说&rsquo;+ _word+_word2); } function sayAfter(_word){ alert(&rsquo;事件2:&rsquo;+this.name +&rsquo;刚说了&rsquo;+ _word); } EventHelper.addEvent(a,&rsquo;saybefore&rsquo;,sayBefore,a,&rsquo;外部的数据&rsquo;); //EventHelper.removeEvent(a,&rsquo;saybefore&rsquo;,sayBefore); EventHelper.addEvent(a,&rsquo;sayafter&rsquo;,sayBefore,a); // &ndash;&gt;&lt;/mce:script&gt;&lt;br /&gt; &lt;/body&gt;&lt;br /&gt; &lt;/html&gt;&lt;br /&gt;  </div>
</div>
<p>上面例子的 EventHelper.addEvent方法可以增加自定义事件或者原生的事件<br>
EventHelper.addEvent(document,&rsquo;click&rsquo;,function(){alert(&rsquo;hello&rsquo;);}); // 原生事件<br>
EventHelper.addEvent(foo,&rsquo;say&rsquo;,function(){alert(&rsquo;hello&rsquo;);}); // 自定义时间</p>
<p>对应的EventHelper.removeEvent也可以移除自定义事件。</p> <a href="http://hi.baidu.com/mikyliang/blog/item/14224543a70b45189213c679.html">阅读全文</a>
		
		<br/><b>类别：</b><a href="http://hi.baidu.com/mikyliang/blog/category/Javascript">Javascript</a>&nbsp;<a href="http://hi.baidu.com/mikyliang/blog/item/14224543a70b45189213c679.html#comment">查看评论</a>]]></description>
        <pubDate>2009-09-07  17:13</pubDate>
        <category><![CDATA[Javascript]]></category>
        <author><![CDATA[mikyliang]]></author>
		<guid>http://hi.baidu.com/mikyliang/blog/item/14224543a70b45189213c679.html</guid>
</item>


</channel>
</rss>