<?xml version="1.0" encoding="utf-8"?><feed xmlns="http://www.w3.org/2005/Atom"><title type="text">博客园_BearRui(AK-47)</title><subtitle type="text">   花开有时，错过了一日便错过了一季，就象人生错过了相遇，就不再找寻到美丽的相聚</subtitle><id>http://feed.cnblogs.com/blog/u/17803/rss</id><updated>2010-10-19T01:37:46Z</updated><author><name>BearRui(AK-47)</name><uri>http://www.cnblogs.com/BearsTaR/</uri></author><generator>CNBlogs BlogServer</generator><link rel="alternate" type="text/html" href="http://www.cnblogs.com/BearsTaR/"/><link rel="self" type="application/atom+xml" href="http://feed.cnblogs.com/blog/u/17803/rss"/><entry><id>http://www.cnblogs.com/BearsTaR/archive/2010/10/19/unique_random_code.html</id><title type="text">产生唯一随机码的方法分析。</title><summary type="text">现在的WEB中经常会需要产生一些邀请码、激活码。需要是唯一并且随机的。下面总结下一些常用的产生随机码的方法，并分享自己的1个方法:</summary><published>2010-10-19T01:38:00Z</published><updated>2010-10-19T01:38:00Z</updated><author><name>BearRui(AK-47)</name><uri>http://www.cnblogs.com/BearsTaR/</uri></author><link rel="alternate" href="http://www.cnblogs.com/BearsTaR/archive/2010/10/19/unique_random_code.html"/><link rel="alternate" type="text/html" href="http://www.cnblogs.com/BearsTaR/archive/2010/10/19/unique_random_code.html"/><content type="html">&lt;p&gt;现在的WEB中经常会需要产生一些邀请码、激活码。需要是唯一并且随机的。下面总结下一些常用的产生随机码的方法，并分享自己的1个方法:&lt;/p&gt;&#xD;
&lt;p&gt;&lt;/p&gt;&#xD;
&lt;p&gt;1. 自己写代码产生随机的数字和字母组合，每产生1个去数据库查询该随机码是否已存在，如果已存在，则重新产生，直到不重复为止。&lt;/p&gt;&#xD;
&lt;p&gt;优点：没发现有啥优点。&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&lt;/p&gt;&#xD;
&lt;p&gt;缺点：产生速度慢，还要查询数据库，当数据量大的时候，可能重复的机率会比较高，要查询多次数据库.&lt;/p&gt;&#xD;
&lt;p&gt;&lt;/p&gt;&#xD;
&lt;p&gt;2. guid,该方法应该是用的比较多的。&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&lt;/p&gt;&#xD;
&lt;p&gt;优点：使用简单方便，不用自己编写额外的代码&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&lt;/p&gt;&#xD;
&lt;p&gt;缺点：占用数据库空间相对较大，特别是根据guid查询速度比较慢(毕竟是字符串)。&lt;/p&gt;&#xD;
&lt;p&gt;&lt;/p&gt;&#xD;
&lt;p&gt;3. 主键+随机码的方式，我们产生的随机码保存到数据库肯定会有个主键，用该主键+随机字符来组合。产生步骤： &amp;nbsp; &amp;nbsp;&amp;nbsp;&lt;/p&gt;&#xD;
&lt;p&gt;1) 先从id生成器中获取id，比如是155. &amp;nbsp; &amp;nbsp;&amp;nbsp;&lt;/p&gt;&#xD;
&lt;p&gt;2）填充成固定位数(比如8位)的字符串(不够位数的左边填0，超过位数直接使用该数字)，得到：00000155 &amp;nbsp; &amp;nbsp;&amp;nbsp;&lt;/p&gt;&#xD;
&lt;p&gt;3）在每个数字后面随机插入1个字母或其它非数字符号，得到：0A0F0R0Y0H1K5L5M&lt;/p&gt;&#xD;
&lt;p&gt;这样就可以得到1个随机的唯一的邀请码了。 &amp;nbsp; &amp;nbsp;&lt;/p&gt;&#xD;
&lt;p&gt;优点：使用也比较简单，不用查询数据库。最大的优点是查询的时候，可以根据邀请码直接得到主键id， &amp;nbsp; &amp;nbsp;&amp;nbsp;&lt;/p&gt;&#xD;
&lt;p&gt;然后根据id去数据库查询(速度很快)，再比较查询出来的邀请码和用户提交的邀请码是否一致。 &amp;nbsp; &amp;nbsp;&lt;/p&gt;&#xD;
&lt;p&gt;缺点：需要使用id产生器，如果主键是数据库自增长的就不太好用(需要先插入数据库获取id，再更新邀请码)。&lt;/p&gt;&#xD;
&lt;p&gt;&lt;/p&gt;&#xD;
&lt;p&gt;4. 有时候产品经理说，我要求邀请码都是数字的。why？no why? 我喜欢。*(&amp;amp;^(^%&amp;amp;^$&amp;amp;^$ 把方法3变通下就可以实现唯一的纯数字随机码了。 &amp;nbsp; &amp;nbsp;&lt;/p&gt;&#xD;
&lt;p&gt;1) 获取id: 155 &amp;nbsp; &amp;nbsp;&lt;/p&gt;&#xD;
&lt;p&gt;2) 转换成8进制：233 &amp;nbsp; &amp;nbsp;&lt;/p&gt;&#xD;
&lt;p&gt;3) 转为字符串，并在后面加'9'字符：2339 &amp;nbsp; &amp;nbsp;&lt;/p&gt;&#xD;
&lt;p&gt;4）在后面随机产生若干个随机数字字符：2003967524987&amp;nbsp;&lt;/p&gt;&#xD;
&lt;p&gt;转为8进制后就不会出现9这个字符，然后在后面加个'9'，这样就能确定唯一性。最后在后面产生一些随机数字就可以。&lt;/p&gt;&#xD;
&lt;p&gt;优缺点同方法3&lt;/p&gt;&#xD;
&lt;p&gt;&lt;/p&gt;&#xD;
&lt;p&gt;目前方法3，4方法在我们产品中都使用了，感觉还可以。&amp;nbsp;&lt;/p&gt;&#xD;
&lt;p&gt;&lt;br /&gt;&lt;span style="color: #ff0000;"&gt;PS：以上是个人浅见，有更好方法的同学请分享下。^_^&amp;nbsp;&lt;/span&gt;&lt;/p&gt;&lt;img src="http://www.cnblogs.com/BearsTaR/aggbug/1855319.html?type=1" width="1" height="1" alt=""/&gt;&lt;p&gt;&lt;a href="http://www.cnblogs.com/BearsTaR/archive/2010/10/19/unique_random_code.html" target="_blank"&gt;本文链接&lt;/a&gt;&lt;/p&gt;</content></entry><entry><id>http://www.cnblogs.com/BearsTaR/archive/2010/08/24/URL_SESSION_ID_LEEK.html</id><title type="text">URL中允许携带sessionid带来的安全隐患。</title><summary type="text">很多WEB开发语言为了防止浏览器禁止了cookie而无法识别用户，允许在URL中携带sessionid，这样虽然方便，但却有可能引起钓鱼的安全漏洞。</summary><published>2010-08-24T00:44:00Z</published><updated>2010-08-24T00:44:00Z</updated><author><name>BearRui(AK-47)</name><uri>http://www.cnblogs.com/BearsTaR/</uri></author><link rel="alternate" href="http://www.cnblogs.com/BearsTaR/archive/2010/08/24/URL_SESSION_ID_LEEK.html"/><link rel="alternate" type="text/html" href="http://www.cnblogs.com/BearsTaR/archive/2010/08/24/URL_SESSION_ID_LEEK.html"/><content type="html">&lt;p&gt;很多WEB开发语言为了防止浏览器禁止了cookie而无法识别用户，允许在URL中携带sessionid，这样虽然方便，但却有可能引起钓鱼的安全漏洞。&lt;/p&gt;&#xD;
&lt;p&gt;&lt;/p&gt;&#xD;
&lt;p&gt;&lt;strong&gt;图示：&lt;/strong&gt;&lt;/p&gt;&#xD;
&lt;p&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;　　下图是从测试组发来的安全报告中剪出来的，图有些小问题，本来想重画1个，在visio中没找到合适的图。所以只能用别人的图了。&lt;/p&gt;&#xD;
&lt;p&gt;&lt;img height="345" width="554" src="http://pic002.cnblogs.com/img/bearstar/201008/2010082317154179.jpg" /&gt;&lt;/p&gt;&#xD;
&lt;p&gt;&lt;/p&gt;&#xD;
&lt;p&gt;&lt;strong&gt;说明：&lt;/strong&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/p&gt;&#xD;
&lt;p&gt;让我们对上图的步骤进行详细说明：&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/p&gt;&#xD;
&lt;p&gt;1. 黑客用自己的帐号登录,假设登录页面是:http://www.abc.com/login.jsp&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/p&gt;&#xD;
&lt;p&gt;2. 服务器返回登录成功。&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/p&gt;&#xD;
&lt;p&gt;3. 黑客从cookie中查看自己的sessionid，比如是1234&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/p&gt;&#xD;
&lt;p&gt;4. 黑客把带自己sessionid的地址发送给一般用户。http://www.abc.com/login.jsp;jsessionid=1234(不同的语言带sessionid的方式不一样，着是jsp的方式)&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/p&gt;&#xD;
&lt;p&gt;5. 用户在黑客给的地址中用自己的帐号进行登录，登录成功。(这个时候用户登录的信息就会覆盖黑客之前的登录信息，而且2个人用的是同1个sessionid)&amp;nbsp;&amp;nbsp; 6. 黑客刷新页面，看到的账户信息就是用户的信息了，而不是之前黑客自己帐号的信息。&lt;/p&gt;&#xD;
&lt;p&gt;&lt;/p&gt;&#xD;
&lt;p&gt;&lt;strong&gt;防治：&lt;/strong&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&amp;nbsp;&lt;/p&gt;&#xD;
&lt;p&gt;要防止这种问题，其实也很简单，只要在用户登录时重置session(session.invalidate()方法)，然后把登录信息保存到新的session中。&lt;/p&gt;&#xD;
&lt;p&gt;&lt;/p&gt;&#xD;
&lt;p&gt;&lt;strong&gt;后语：&lt;/strong&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&amp;nbsp;&lt;/p&gt;&#xD;
&lt;p&gt;可能你跟我一样，刚开始看到这个时候，就自己去测试到底能不能钓鱼成功，经过我的测试是可以成功的，但测试过程中需要注意下面几个问题：&lt;span&gt;&amp;nbsp;&lt;/span&gt;&amp;nbsp;&lt;/p&gt;&#xD;
&lt;p&gt;1. 要注意你使用的语言是如何在URL中带sessionid。(我测试的时候开始在URL中使用大写的jsessionid，导致一直不起效)&lt;span&gt;&amp;nbsp;&lt;/span&gt;&amp;nbsp;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&amp;nbsp;&lt;/p&gt;&#xD;
&lt;p&gt;2. 要http://www.abc.com/login.jsp;jsessionid=1234页面登录表单的action也带上了jsessionid,不然也没用。对于这个问题你可能觉得如果login.jsp表单的action是写死，而不是读取当前URL的，&lt;span&gt;&amp;nbsp;&lt;/span&gt; &lt;span&gt;&amp;nbsp;&lt;/span&gt; &amp;nbsp;可能就不会出现这个钓鱼问题。这只能防住1个方向。黑客可以做1个和login.jsp一模一样的页面(比如http://www.abc1.com/login.jsp)，然后把这个地址发个客户，而这个地址中的表单这样写就可以：&lt;span&gt;&amp;nbsp;&lt;/span&gt; &lt;span&gt;&lt;/span&gt; &amp;nbsp;&amp;lt;form action="http://www.abc.com/login.jsp;jsessionid=1234" ....&lt;/p&gt;&lt;img src="http://www.cnblogs.com/BearsTaR/aggbug/1806664.html?type=1" width="1" height="1" alt=""/&gt;&lt;p&gt;&lt;a href="http://www.cnblogs.com/BearsTaR/archive/2010/08/24/URL_SESSION_ID_LEEK.html" target="_blank"&gt;本文链接&lt;/a&gt;&lt;/p&gt;</content></entry><entry><id>http://www.cnblogs.com/BearsTaR/archive/2010/08/05/js_include.html</id><title type="text">JS 实现完美include</title><summary type="text">     js为什么需要include？让我们想想这样1个场景，a.js 需要用到1个公用的common.js，当然你可以在用到a.js的页面使用，但假设有5个页面用到了a.js，你是不是要写5遍&lt;script。而且要是以后a.js 又需要引用common2.js，你是不是又的修改5个页面了？	</summary><published>2010-08-05T00:51:00Z</published><updated>2010-08-05T00:51:00Z</updated><author><name>BearRui(AK-47)</name><uri>http://www.cnblogs.com/BearsTaR/</uri></author><link rel="alternate" href="http://www.cnblogs.com/BearsTaR/archive/2010/08/05/js_include.html"/><link rel="alternate" type="text/html" href="http://www.cnblogs.com/BearsTaR/archive/2010/08/05/js_include.html"/><content type="html">&lt;p&gt;js为什么需要include？让我们想想这样1个场景，a.js 需要用到1个公用的common.js，当然你可以在用到a.js的页面使用&amp;lt;script src="common.js"&amp;gt;，但假设有5个页面用到了a.js，你是不是要写5遍&amp;lt;script。而且要是以后a.js 又需要引用common2.js，你是不是又的修改5个页面了？&lt;/p&gt;&#xD;
&lt;p&gt;&lt;/p&gt;&#xD;
&lt;p&gt;&lt;strong&gt;已有js include的一些问题&lt;/strong&gt;&lt;/p&gt;&#xD;
&lt;p&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;　　在写这个之前在网上搜索了些资料，发现以前写的include都存在2个问题，这也是include需要解决的比较重要的2个问题。&lt;/p&gt;&#xD;
&lt;p&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;　　1、相对路径的问题：&lt;span&gt;&amp;nbsp;&lt;/span&gt; 在a.js中使用include("../js/common.js"); &amp;nbsp;include 函数中肯定是使用相对路径，是相对a.js的路径。而a.js在html中使用&amp;lt;script&amp;gt;嵌入有可能是相对路径，有可能是绝对路径。&lt;span&gt;&amp;nbsp;&lt;/span&gt; include函数如何才能真正确定common.js的绝对路径，或者是相对html的相对路径。网上一些为了解决这个问题，还需要加一些js变量，不方便。&lt;span&gt;&amp;nbsp;&lt;/span&gt;&amp;nbsp;&lt;/p&gt;&#xD;
&lt;p&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;　　2、引用的问题。&lt;span&gt;&amp;nbsp;&lt;/span&gt; 网上include函数的实现几乎都是使用下面2种方式插入common.js&lt;span&gt;&amp;nbsp;&lt;/span&gt; &lt;span&gt;&amp;nbsp;&lt;/span&gt; &amp;nbsp;&lt;/p&gt;&#xD;
&lt;p&gt;document.write("&amp;lt;script src='" + .. + "&amp;gt;&amp;lt;/script&amp;gt;")&lt;span&gt;&amp;nbsp;&lt;/span&gt;&amp;nbsp;&lt;/p&gt;&#xD;
&lt;p&gt;或者&lt;span&gt;&amp;nbsp;&lt;/span&gt; &amp;nbsp;&amp;nbsp;&lt;/p&gt;&#xD;
&lt;p&gt;var s = document.createElement("script");&lt;span&gt;&amp;nbsp;&lt;/span&gt; &amp;nbsp;&amp;nbsp;&lt;/p&gt;&#xD;
&lt;p&gt;s.src = ...;&lt;span&gt;&amp;nbsp;&lt;/span&gt; &amp;nbsp;&amp;nbsp;&lt;/p&gt;&#xD;
&lt;p&gt;head.insertAfter(s,...);&lt;span&gt;&amp;nbsp;&lt;/span&gt;&amp;nbsp;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&amp;nbsp;&lt;/p&gt;&#xD;
&lt;p&gt;document.write 输出的脚本会在a.js后面加载，而createElement("script")创建的脚本是非阻塞加载。&lt;span&gt;&amp;nbsp;&lt;/span&gt; 所以如果在common.js加载完毕之前，a.js中调用了common.js的函数就会报错。&lt;/p&gt;&#xD;
&lt;p&gt;&lt;/p&gt;&#xD;
&lt;p&gt;&lt;strong&gt;实现&lt;/strong&gt;&lt;/p&gt;&#xD;
&lt;p&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt; &lt;span&gt;&amp;nbsp;&lt;/span&gt;　　解决上面2个问题，就可以实现js include。&lt;span&gt;&amp;nbsp;&lt;/span&gt;&amp;nbsp;&lt;/p&gt;&#xD;
&lt;p&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;　　第1个问题，我的方法是先获取到a.js在html中的绝对路径(如果是相对路径，就转为绝对路径)，然后再把common.js的路径转为绝对路径。&lt;span&gt;&amp;nbsp;&lt;/span&gt;&amp;nbsp;&lt;/p&gt;&#xD;
&lt;p&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;　　第2个问题，采用同步的ajax来请求common.js，这样就不会出现引用问题。&lt;/p&gt;&#xD;
&lt;p&gt;&lt;/p&gt;&#xD;
&lt;p&gt;实现代码如下：&lt;/p&gt;&#xD;
&lt;p&gt;&lt;/p&gt;&#xD;
&lt;div &gt;&#xD;
&lt;pre &gt;// 根据相对路径获取绝对路径&#xD;
	function getPath(relativePath,absolutePath){&#xD;
		var reg = new RegExp("\\.\\./","g");&#xD;
		var uplayCount = 0;		// 相对路径中返回上层的次数。&#xD;
		var m = relativePath.match(reg);&#xD;
		if(m) uplayCount = m.length;&#xD;
		&#xD;
		var lastIndex = absolutePath.length-1; &#xD;
		for(var i=0;i&amp;lt;=uplayCount;i++){&#xD;
			lastIndex = absolutePath.lastIndexOf("/",lastIndex);&#xD;
		}&#xD;
		return absolutePath.substr(0,lastIndex+1) + relativePath.replace(reg,"");&#xD;
	}	 	&#xD;
	&#xD;
	function include(jssrc){&#xD;
		// 先获取当前a.js的src。a.js中调用include,直接获取最后1个script标签就是a.js的引用。&#xD;
		var scripts = document.getElementsByTagName("script");&#xD;
		var lastScript = scripts[scripts.length-1];&#xD;
		var src = lastScript.src;&#xD;
		if(src.indexOf("http://")!=0 &amp;amp;&amp;amp; src.indexOf("/") !=0){		&#xD;
			// a.js使用相对路径,先替换成绝对路径&#xD;
			var url = location.href;&#xD;
			var index = url.indexOf("?");&#xD;
			if(index != -1){&#xD;
				url = url.substring(0, index-1);&#xD;
			}&#xD;
			&#xD;
			src = getPath(src,url);&#xD;
		}&#xD;
		var jssrcs = jssrc.split("|");	// 可以include多个js，用|隔开&#xD;
		for(var i=0;i&amp;lt;jssrcs.length;i++){&#xD;
			// 使用juqery的同步ajax加载js.&#xD;
			// 使用document.write 动态添加的js会在当前js的后面，可能会有js引用问题&#xD;
			// 动态创建script脚本，是非阻塞下载，也会出现引用问题&#xD;
			$.ajax({type:'GET',url:getPath(jssrc,src),async:false,dataType:'script'});&#xD;
		}&#xD;
	}&#xD;
&#xD;
&lt;/pre&gt;&#xD;
&lt;/div&gt;&#xD;
&lt;p&gt;&lt;/p&gt;&#xD;
&lt;p&gt;在a.js中直接使用 include("../js/common.js");&lt;/p&gt;&#xD;
&lt;p&gt;&lt;/p&gt;&#xD;
&lt;p&gt;&lt;strong&gt;多请求的问题&lt;/strong&gt;&lt;/p&gt;&#xD;
&lt;p&gt;使用上面的include看上去挺爽的，不过却带来另外1个严重的问题，就是多发送了1个ajax的请求。&lt;/p&gt;&#xD;
&lt;p&gt;我们常常为了WEB性能，而合并js，减少请求。但使用include后却偏偏多了请求。如果这个问题不解决，相信很多人都不会在正式产品中使用include的了，除非是局域网产品。&lt;/p&gt;&#xD;
&lt;p&gt;&lt;/p&gt;&#xD;
&lt;p&gt;如何解决这个多请求的问题，我也思考很久，最后觉的单单使用客户端js是没办法解决了。所以就想到了使用服务端代码来解决&lt;/p&gt;&#xD;
&lt;p&gt;还记的我之前有文章介绍 "&lt;a target="_blank" href="http://www.cnblogs.com/BearsTaR/archive/2010/05/12/web_performance.html"&gt;js、css的合并、压缩、缓存管理&lt;/a&gt;"的时候，就通过服务器端代码在程序启动时候去合并js。&lt;/p&gt;&#xD;
&lt;p&gt;&lt;/p&gt;&#xD;
&lt;p&gt;所以我把include多请求的解决方案也加到里面去。就是在程序启动的时候去查找所有的js，发现有使用include的就把include中common.js的源代码替换该include函数。这样a.js中在运行的时候就没有include函数，而是真真包含了common.js的内容的js文件&lt;/p&gt;&#xD;
&lt;p&gt;&lt;/p&gt;&#xD;
&lt;p&gt;&lt;strong&gt;后语&lt;/strong&gt;&lt;/p&gt;&#xD;
&lt;p&gt;丫的。说到最后，怎么又把所有的include都替换掉了，哪之前说的那么多不白说了。&lt;/p&gt;&#xD;
&lt;p&gt;&lt;/p&gt;&#xD;
&lt;p&gt;个人觉得，每个产品都应该要区分开发环境和产品环境(一般通过配置文件进行区分)，在开发环境应该以开发效率为首要，而产品环境则以性能为首。所以这里的inlcude就应该要区分对待，在开发环境中使用js include来提高开发和维护效率，而在产品环境中则自动把所有include替换成真真的js文件的内容。&lt;/p&gt;&#xD;
&lt;p&gt;&lt;/p&gt;&#xD;
&lt;p&gt;&lt;span style="color: #0000ff;"&gt;都说完了，欢迎大家拍砖讨论。&lt;/span&gt;&lt;/p&gt;&lt;img src="http://www.cnblogs.com/BearsTaR/aggbug/1792626.html?type=1" width="1" height="1" alt=""/&gt;&lt;p&gt;&lt;a href="http://www.cnblogs.com/BearsTaR/archive/2010/08/05/js_include.html" target="_blank"&gt;本文链接&lt;/a&gt;&lt;/p&gt;</content></entry><entry><id>http://www.cnblogs.com/BearsTaR/archive/2010/08/04/freemarker_excel_export.html</id><title type="text">基于模板的excel导出</title><summary type="text">产品中有很多模块需要导出excel功能，导出excel几乎都是把页面已经显示出来的数据列表导出为excel。但后台使用poi生成excel却要1个单元格1个单元格的去编写。每个模块都需要单独写导出excel的代码，导致代码里充斥了createRow,createCell,setCellValue的代码。但这不是要命的，要命的是当前台数据列表格式变了的时候，后台生成excel代码的修改非常麻烦，特别是当产品经理要求在excel中也要保留WEB样式的时候(背景色，字体色，宽度)，就只能oh shit！</summary><published>2010-08-04T00:45:00Z</published><updated>2010-08-04T00:45:00Z</updated><author><name>BearRui(AK-47)</name><uri>http://www.cnblogs.com/BearsTaR/</uri></author><link rel="alternate" href="http://www.cnblogs.com/BearsTaR/archive/2010/08/04/freemarker_excel_export.html"/><link rel="alternate" type="text/html" href="http://www.cnblogs.com/BearsTaR/archive/2010/08/04/freemarker_excel_export.html"/><content type="html">&lt;p&gt;产品中有很多模块需要导出excel功能，导出excel几乎都是把页面已经显示出来的数据列表导出为excel。但后台使用poi生成excel却要1个单元格1个单元格的去编写。每个模块都需要单独写导出excel的代码，导致代码里充斥了createRow,createCell,setCellValue的代码。但这不是要命的，要命的是当前台数据列表格式变了的时候，后台生成excel代码的修改非常麻烦，特别是当产品经理要求在excel中也要保留WEB样式的时候(背景色，字体色，宽度)，就只能oh shit！&lt;/p&gt;&#xD;
&lt;p&gt;&lt;/p&gt;&#xD;
&lt;p&gt;&lt;strong&gt;HTML直接另存为excel&lt;/strong&gt;&lt;/p&gt;&#xD;
&lt;p&gt;最开始想的解决办法是直接把数据列表的html代码另存为xls后缀的excel文件，这样是最方便，也最容易维护的方式。&amp;nbsp;&amp;nbsp;&amp;nbsp;可惜因为只是改了文件的后缀，所以当用excel打开的时候就会弹出"您尝试打开的文件格式与文件扩展名指定格式不一致。"的提示。最终放弃了该方法。　　&lt;/p&gt;&#xD;
&lt;p&gt;&lt;/p&gt;&#xD;
&lt;p&gt;&lt;strong&gt;基于模板引擎的excel数据导出&lt;/strong&gt;&lt;br /&gt;　　在一次跟朋友szyicol(&lt;a href="http://www.cnblogs.com/szyicol/" target="_blank"&gt;http://www.cnblogs.com/szyicol/&lt;/a&gt;)聊天中，聊起该问题，他也碰见了类似的问题，目前也是每个模块都写单独的导出excel代码。但他说想使用xls模板+xml映射文件(类似与hibernate的映射文件)来做通用导出excel。经他提醒，我最终选择使用模板引擎生成html代码，然后把html代码通过poi生成为excel。这样开发人员以后导出excel只需要编写html模板就行。&lt;/p&gt;&#xD;
&lt;p&gt;&lt;/p&gt;&#xD;
&lt;p&gt;&lt;strong&gt;选择html的原因&lt;/strong&gt;&lt;/p&gt;&#xD;
&lt;p&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;　　选择通过html代码(而不是xml或者其他)生成excel的原因有下：&lt;/p&gt;&#xD;
&lt;p&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;　 &amp;nbsp;1、html对于开发人员来可读性最强，可以说看到这段html代码就知道生成的excel会是什么样子。&lt;br /&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;　　2、因导出的就是前台的数据列表，所以html代码几乎可以直接从前台页面中copy到模板中就可以了，维护也比较方便，不需要额外比较多的工作量。&lt;/p&gt;&#xD;
&lt;p&gt;&lt;/p&gt;&#xD;
&lt;p&gt;&lt;strong&gt;HTML格式&amp;nbsp;&lt;/strong&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&lt;/p&gt;&#xD;
&lt;p&gt;为了易解析和增加可读性，要求生成的html代码只有table tr td标签,而且只能有1个table，类似下面的代码：&lt;/p&gt;&#xD;
&lt;p&gt;&lt;/p&gt;&#xD;
&lt;div &gt;&#xD;
&lt;pre &gt;&amp;lt;table&amp;gt;&#xD;
	&amp;lt;tr&amp;gt;&#xD;
		&amp;lt;td colspan="7" align="center"&amp;gt;项目名称&amp;lt;/td&amp;gt;&#xD;
	&amp;lt;/tr&amp;gt;&#xD;
	&amp;lt;tr&amp;gt;&#xD;
		&amp;lt;td colspan="7" align="center"&amp;gt;(导出时间：2010-08-01)&amp;lt;/td&amp;gt;&#xD;
	&amp;lt;/tr&amp;gt;&#xD;
	&amp;lt;tr align="center" bgcolor="#9AB0AD"&amp;gt;&#xD;
		&amp;lt;td width="150"&amp;gt;记账人&amp;lt;/td&amp;gt;&#xD;
		&amp;lt;td width="100"&amp;gt;日期&amp;lt;/td&amp;gt;&#xD;
		&amp;lt;td width="80"&amp;gt;金额&amp;lt;/td&amp;gt;&#xD;
	&amp;lt;/tr&amp;gt;&#xD;
	&amp;lt;tr bgcolor="#ABCDC1" color="#14645E"&amp;gt;&#xD;
		&amp;lt;td color="#00000"&amp;gt;x1&amp;lt;/td&amp;gt;&#xD;
		&amp;lt;td&amp;gt;2010-08-01&amp;lt;/td&amp;gt;&#xD;
		&amp;lt;td&amp;gt;100&amp;lt;/td&amp;gt;&#xD;
	&amp;lt;/tr&amp;gt;&#xD;
  &amp;lt;tr bgcolor="#ABCDC1" color="#14645E"&amp;gt;&#xD;
		&amp;lt;td color="#00000"&amp;gt;x1&amp;lt;/td&amp;gt;&#xD;
		&amp;lt;td&amp;gt;2010-08-01&amp;lt;/td&amp;gt;&#xD;
		&amp;lt;td&amp;gt;100&amp;lt;/td&amp;gt;&#xD;
	&amp;lt;/tr&amp;gt;&#xD;
 &amp;lt;/table&amp;gt;&#xD;
&lt;/pre&gt;&#xD;
&lt;/div&gt;&#xD;
&lt;p&gt;&lt;/p&gt;&#xD;
&lt;p&gt;&lt;/p&gt;&#xD;
&lt;p&gt;&lt;strong&gt;模板引擎&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/strong&gt;&lt;/p&gt;&#xD;
&lt;p&gt;要根据一些数据生成上面的html代码，当然需要使用模板引擎，当然选择什么模板引擎就看自己了，我们选择了freemarker&lt;/p&gt;&#xD;
&lt;p&gt;&lt;/p&gt;&#xD;
&lt;p&gt;&lt;strong&gt;html代码转excel&lt;/strong&gt;&lt;br /&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;　　对于html代码的解析，因为我们要求html代码只能有1个table,可以看出我们的html代码也是符合xml格式的，所以我们就使用xml库解析html代码。&lt;br /&gt;通过xml解析循环所有tr,td标签，并调用对应的createRow,createCell就能生成excel了，这里不贴出所有代码，有兴趣的自己研究下，只说说poi的几个问题。&lt;/p&gt;&#xD;
&lt;p&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;　　1、合并单元格&lt;span&gt;&amp;nbsp;&lt;/span&gt; &amp;nbsp;&amp;nbsp;&lt;/p&gt;&#xD;
&lt;p&gt;当html中出现colspan的时候，就需要用到合并单元格，HSSFSheet.addMergedRegion 支持合并单元格&lt;span&gt;&amp;nbsp;&lt;/span&gt; &amp;nbsp;&amp;nbsp;&lt;/p&gt;&#xD;
&lt;p&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;　　&lt;/p&gt;&#xD;
&lt;p&gt;2、设置颜色&lt;span&gt;&amp;nbsp;&lt;/span&gt; &amp;nbsp;&amp;nbsp;&lt;/p&gt;&#xD;
&lt;p&gt;poi设置颜色比较麻烦，不能直接设置自定义的颜色值，默认只能使用内置的一些颜色。如果要使用自定义的颜色，需要先把内置的一些颜色替换成自定义颜色。建议先选出一些不常用的poi内置颜色(我们选了15个,应该够用了)，当发现有自定义颜色的时候，就循环进行替换这些不常用的颜色。&lt;span&gt;&amp;nbsp;&lt;/span&gt; &amp;nbsp;&amp;nbsp;&lt;/p&gt;&#xD;
&lt;p&gt;具体可看：&lt;a href="http://poi.apache.org/spreadsheet/quick-guide.html#CustomColors" target="_blank"&gt;http://poi.apache.org/spreadsheet/quick-guide.html#CustomColors&lt;/a&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt; &amp;nbsp;&amp;nbsp;&lt;/p&gt;&#xD;
&lt;p&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;　　&lt;/p&gt;&#xD;
&lt;p&gt;3、设置宽度&lt;span&gt;&amp;nbsp;&lt;/span&gt; &amp;nbsp;&amp;nbsp;&lt;/p&gt;&#xD;
&lt;p&gt;这个在poi文档中没看到很详细的介绍，因为 HSSFSheet.setColumnWidth 方法,使用的并不是像素单位，也不知道是什么单位。经过尝试发现把像素宽度*40，导出的excel列宽刚好是像素宽度。　　&lt;/p&gt;&lt;img src="http://www.cnblogs.com/BearsTaR/aggbug/1791399.html?type=1" width="1" height="1" alt=""/&gt;&lt;p&gt;&lt;a href="http://www.cnblogs.com/BearsTaR/archive/2010/08/04/freemarker_excel_export.html" target="_blank"&gt;本文链接&lt;/a&gt;&lt;/p&gt;</content></entry><entry><id>http://www.cnblogs.com/BearsTaR/archive/2010/07/29/jsp_if_elseif_else_tag.html</id><title type="text">实现if elseif else的jsp标签。</title><summary type="text">相信很多使用jstl的朋友都抱怨过，为什么jstl只有c:if 而没有elseif、else。当需要判断多个条件的时候，只能写多个c:if 或者使用c:choose。</summary><published>2010-07-29T00:46:00Z</published><updated>2010-07-29T00:46:00Z</updated><author><name>BearRui(AK-47)</name><uri>http://www.cnblogs.com/BearsTaR/</uri></author><link rel="alternate" href="http://www.cnblogs.com/BearsTaR/archive/2010/07/29/jsp_if_elseif_else_tag.html"/><link rel="alternate" type="text/html" href="http://www.cnblogs.com/BearsTaR/archive/2010/07/29/jsp_if_elseif_else_tag.html"/><content type="html">&lt;p&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt; &amp;nbsp;　　相信很多使用jstl的朋友都抱怨过，为什么jstl只有c:if 而没有elseif、else。当需要判断多个条件的时候，只能写多个c:if 或者使用c:choose。&lt;br /&gt;虽然struts有elseif 和&lt;span&gt;&amp;nbsp;&lt;/span&gt;else标签，不过看着就跟多个c:if 没什么2样，使用如下：&lt;/p&gt;&#xD;
&lt;p&gt;&amp;lt;s:if test=""&amp;gt;&amp;nbsp;&amp;nbsp;&lt;/p&gt;&#xD;
&lt;p&gt;1&lt;/p&gt;&#xD;
&lt;p&gt;&amp;lt;/s:if&amp;gt;&lt;/p&gt;&#xD;
&lt;p&gt;&amp;lt;s:elseif test=""&amp;gt;&lt;/p&gt;&#xD;
&lt;p&gt;2&lt;/p&gt;&#xD;
&lt;p&gt;&amp;lt;/s:elseif&amp;gt;&lt;/p&gt;&#xD;
&lt;p&gt;&amp;lt;s:else&amp;gt;&lt;/p&gt;&#xD;
&lt;p&gt;3&lt;/p&gt;&#xD;
&lt;p&gt;&amp;lt;/s:else&amp;gt;&lt;/p&gt;&#xD;
&lt;p&gt;&lt;/p&gt;&#xD;
&lt;p&gt;下面是本人实现的if elseif else。先看看使用代码:&lt;/p&gt;&#xD;
&lt;p&gt;&amp;lt;g:if test=""&amp;gt;&lt;/p&gt;&#xD;
&lt;p&gt;1&lt;/p&gt;&#xD;
&lt;p&gt;&amp;lt;g:elseif test="" /&amp;gt;&amp;nbsp;&lt;/p&gt;&#xD;
&lt;p&gt;2&lt;/p&gt;&#xD;
&lt;p&gt;&amp;lt;g:else /&amp;gt;&amp;nbsp;&lt;/p&gt;&#xD;
&lt;p&gt;3&lt;/p&gt;&#xD;
&lt;p&gt;&amp;lt;/g:if&amp;gt;&lt;/p&gt;&#xD;
&lt;p&gt;这样代码结构个人觉得更加清晰简单，类似freemarker的if elseif。&lt;/p&gt;&#xD;
&lt;p&gt;&lt;/p&gt;&#xD;
&lt;p&gt;&lt;strong&gt;实现：&lt;/strong&gt;&lt;/p&gt;&#xD;
&lt;p&gt;&lt;/p&gt;&#xD;
&lt;p&gt;要实现上面说的if elseif，需要继承BodyTagSupport，利用BodyTagSupport的bodyContent的来实现该功能，这里不具体介绍如何实现jsp tag。直接贴出所有代码，有兴趣的自己看看。 &amp;nbsp;&lt;/p&gt;&#xD;
&lt;p&gt;&lt;/p&gt;&#xD;
&lt;p&gt;&lt;/p&gt;&#xD;
&lt;div &gt;&#xD;
&lt;pre &gt;public class IfTag extends BodyTagSupport{&#xD;
&#xD;
	public IfTag() {&#xD;
        super();&#xD;
        init();&#xD;
    }&#xD;
&#xD;
	@Override&#xD;
    public void release() {&#xD;
        super.release();&#xD;
        init();&#xD;
    }&#xD;
    &#xD;
    @Override&#xD;
    public int doStartTag() throws JspException {&#xD;
    	if(test){&#xD;
    		this.succeeded();&#xD;
    	}&#xD;
		return EVAL_BODY_BUFFERED;&#xD;
    }&#xD;
&#xD;
    @Override&#xD;
    public int doEndTag() throws JspException {&#xD;
    	try {&#xD;
    		if(subtagSucceeded)&#xD;
    			pageContext.getOut().write(getBody());&#xD;
		} catch (IOException e) {&#xD;
			throw new JspException("IOError while writing the body: " + e.getMessage(), e);&#xD;
		}&#xD;
    	&#xD;
		init();&#xD;
    	return super.doEndTag();&#xD;
    }&#xD;
	&#xD;
    private String body = null;		//	用于存放成功条件后的内容&#xD;
    public void setBody(){&#xD;
    	if(body == null){&#xD;
    		body = bodyContent.getString().trim();&#xD;
    	}&#xD;
    }&#xD;
    &#xD;
    private String getBody(){&#xD;
    	if(body == null)&#xD;
    		return bodyContent.getString().trim();&#xD;
    	else&#xD;
    		return body;&#xD;
    }&#xD;
    &#xD;
    /**&#xD;
     * 判断if 或者 子 else if是否提交成功&#xD;
     */&#xD;
    private boolean subtagSucceeded;&#xD;
    &#xD;
    /**&#xD;
     * 子条件判断成功&#xD;
     */&#xD;
    public void succeeded(){&#xD;
    	subtagSucceeded = true;&#xD;
    }&#xD;
    /**&#xD;
     * 是否已经执行完毕&#xD;
     * @return&#xD;
     */&#xD;
    public boolean isSucceeded(){&#xD;
    	return subtagSucceeded;&#xD;
    }&#xD;
    &#xD;
    private void init() {&#xD;
        test = false;&#xD;
        subtagSucceeded = false;&#xD;
        body = null;&#xD;
    }&#xD;
    &#xD;
    private boolean test;  &#xD;
    &#xD;
    public void setTest(boolean test) {&#xD;
        this.test = test;&#xD;
    }&#xD;
}&#xD;
&lt;/pre&gt;&#xD;
&lt;/div&gt;&#xD;
&lt;p&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;/p&gt;&#xD;
&lt;div &gt;&#xD;
&lt;pre &gt;public class ElseIfTag extends BodyTagSupport{&#xD;
&#xD;
	public ElseIfTag() {&#xD;
        super();&#xD;
        init();&#xD;
    }&#xD;
&#xD;
	@Override&#xD;
	public int doStartTag() throws JspException {&#xD;
	    Tag parent = getParent();&#xD;
&#xD;
    	if(parent==null || !(parent instanceof IfTag)){&#xD;
            throw new JspTagException("else tag must inside if tag");&#xD;
    	}&#xD;
    	&#xD;
    	IfTag ifTag = (IfTag)parent;&#xD;
    	if(ifTag.isSucceeded()){&#xD;
    		// 已经有执行成功的条件，保存之前的html&#xD;
    		ifTag.setBody();&#xD;
    	}else if(test){		// 当前条件为true,之前无条件为true&#xD;
    		ifTag.succeeded();&#xD;
    		// 则清除之前的输出&#xD;
    		ifTag.getBodyContent().clearBody();&#xD;
    	}&#xD;
    		&#xD;
		return EVAL_BODY_BUFFERED;&#xD;
    }&#xD;
	 &#xD;
	@Override&#xD;
    public void release() {&#xD;
        super.release();&#xD;
        init();&#xD;
    }&#xD;
	&#xD;
	private void init() {&#xD;
        test = false;&#xD;
    }&#xD;
    &#xD;
    private boolean test;  &#xD;
    &#xD;
    public void setTest(boolean test) {&#xD;
        this.test = test;&#xD;
    }&#xD;
}&#xD;
&lt;/pre&gt;&#xD;
&lt;/div&gt;&#xD;
&lt;p&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;/p&gt;&#xD;
&lt;div &gt;&#xD;
&lt;pre &gt;public class ElseTag extends BodyTagSupport{&#xD;
&#xD;
	public void release() {&#xD;
        super.release();&#xD;
    }&#xD;
    &#xD;
    public int doStartTag() throws JspException {&#xD;
    	Tag parent = getParent();&#xD;
&#xD;
    	if(parent==null || !(parent instanceof IfTag)){&#xD;
            throw new JspTagException("else tag must inside if tag");&#xD;
    	}&#xD;
    	&#xD;
    	IfTag ifTag = (IfTag)parent;&#xD;
    	if(ifTag.isSucceeded()){&#xD;
    		// 已经有执行成功的条件，保存之前的html&#xD;
    		ifTag.setBody();&#xD;
    	}else{&#xD;
    		// 之前没有的判断没有成功条件,则清除之前的输出&#xD;
    		ifTag.getBodyContent().clearBody();&#xD;
    		ifTag.succeeded();&#xD;
    	}&#xD;
    		&#xD;
		return EVAL_BODY_BUFFERED;&#xD;
    }&#xD;
    &#xD;
}&#xD;
&lt;/pre&gt;&#xD;
&lt;/div&gt;&#xD;
&lt;p&gt;&lt;/p&gt;&#xD;
&lt;p&gt;tld配置就不贴出来了，因为这个太简单了，大家都知道的。&lt;/p&gt;&lt;img src="http://www.cnblogs.com/BearsTaR/aggbug/1787035.html?type=1" width="1" height="1" alt=""/&gt;&lt;p&gt;&lt;a href="http://www.cnblogs.com/BearsTaR/archive/2010/07/29/jsp_if_elseif_else_tag.html" target="_blank"&gt;本文链接&lt;/a&gt;&lt;/p&gt;</content></entry><entry><id>http://www.cnblogs.com/BearsTaR/archive/2010/07/16/Tally_Optimization2.html</id><title type="text">记一复杂页面的前端优化(2) - 其他优化</title><summary type="text">上一篇 "记一复杂页面的前端优化(1) - 不一样的延迟加载，"	说了下对弹出窗口的优化，接下来说说其他的优化.</summary><published>2010-07-16T00:13:00Z</published><updated>2010-07-16T00:13:00Z</updated><author><name>BearRui(AK-47)</name><uri>http://www.cnblogs.com/BearsTaR/</uri></author><link rel="alternate" href="http://www.cnblogs.com/BearsTaR/archive/2010/07/16/Tally_Optimization2.html"/><link rel="alternate" type="text/html" href="http://www.cnblogs.com/BearsTaR/archive/2010/07/16/Tally_Optimization2.html"/><content type="html">&lt;p&gt;上一篇 "&lt;a target="_blank" href="http://www.cnblogs.com/BearsTaR/archive/2010/07/14/Tally_Optimization.html"&gt;记一复杂页面的前端优化(1) - 不一样的延迟加载&lt;/a&gt;",&lt;span style="white-space: pre;"&gt;&amp;nbsp;&lt;/span&gt;说了下对弹出窗口的优化，接下来说说其他的优化，先把界面图贴出来，方便对照：&lt;/p&gt;&#xD;
&lt;p&gt;&lt;/p&gt;&#xD;
&lt;p&gt;&lt;img height="544" width="1010" src="http://pic002.cnblogs.com/img/bearstar/201007/2010071317292919.jpg" /&gt;&lt;/p&gt;&#xD;
&lt;p&gt;&lt;/p&gt;&#xD;
&lt;p&gt;&lt;strong&gt;下拉列表优化&lt;/strong&gt;&lt;/p&gt;&#xD;
&lt;p&gt;然后创建自己的输入框和弹出框。当页面只有1，2个select的时候，没发现有什么问题，但当页面出现7，8个select的时候，熏染速度明显慢了很多，可以看着1个个select变成input，主要原因还是js执行的太多了(动态生成html，绑定事件)等等。这个是影响页面渲染速度的1个大问题，所以第一个要解决的就是这个select。因原始的select外观是在是不行，而且又不能修改样式，所以我们选择了1个jquery的&lt;a target="_blank" href="http://dervish.wsisiz.edu.pl/~suszynsk/jQuery/demos/jquery-selectbox/"&gt;selectbox插件&lt;/a&gt;，该插件的实现原理：在页面加载完毕后，隐藏原始的select,然后创建自己的输入框和弹出框。当页面只有1，2个select的时候，没发现有什么问题，但当页面出现7，8个select的时候，熏染速度明显慢了很多，可以看着1个个select变成input.主要原因还是js执行的太多了(动态生成html，绑定事件)等等。这个是影响页面渲染速度的1个大问题，所以第一个要解决的就是这个select。&lt;/p&gt;&#xD;
&lt;p&gt;&lt;/p&gt;&#xD;
&lt;p&gt;目前的解决方案是服务器端和js结合使用，通过jsp的标签(net应该叫自定义控件)生成html代码,并不生成任何js来绑定事件，而且当用户第一次点击input的时候，才绑定所有事件，弹出下拉窗口。这样就完全解决了渲染的问题，因为不需要js来生成html，也不需要页面加载的时候去绑定所有事件。&lt;/p&gt;&#xD;
&lt;p&gt;&lt;/p&gt;&#xD;
&lt;p&gt;&lt;strong&gt;右下的数据列表延迟加载&lt;/strong&gt;&lt;span style="white-space: pre;"&gt;&lt;strong&gt;	&lt;/strong&gt;	&lt;/span&gt;&lt;/p&gt;&#xD;
&lt;p&gt;右下方的数据列表，默认只显示基本信息，当用户点击的时候才展开详细信息，一般用户只有在编辑和删除的时候才会用到详细信息，大部分情况可能不会用编辑和删除，也就不需要展开详细信息。之前的做法就是在加载列表的时候就把详细信息的html都生成好，只是隐藏一下，所以加载列表就比较慢。把详细信息改成延迟加载，当用户单击某行数据，才去生成对应的详细信息html代码，并展开显示。&lt;/p&gt;&#xD;
&lt;p&gt;&lt;/p&gt;&#xD;
&lt;p&gt;&lt;strong&gt;png图片转gif&lt;/strong&gt;&lt;/p&gt;&#xD;
&lt;p&gt;这个页面用了很多PNG图片，比如收入、支出的图标，左边分类的图片，选择框的图标。而png图片在ie6下要做单独处理，为了提高性能，跟设计师商量后，把一些图片转成gif的。虽然gif的转了后效果没PNG的好看，但还可以接受，而且也是透明的，于是就通过CSS HACK,让在IE6下使用gif图片，在其他浏览器下使用png图片。这样就可以提高IE6下的速度，而又不用降低其他浏览器的界面效果。&lt;/p&gt;&#xD;
&lt;p&gt;&lt;/p&gt;&#xD;
&lt;p&gt;&lt;strong&gt;延迟执行ajax&lt;/strong&gt;&lt;/p&gt;&#xD;
&lt;p&gt;&lt;span style="white-space: pre;"&gt;	&lt;/span&gt; 左边每个分类前面有个选择框，当用户选择(或去掉选择)某个分类的时候，都会引发ajax刷新右边的数据列表。这里就可能出现这种情况，比如用户想选择3个分类查看，需要点击3次选择，之前的做法，每次点击都会触发一次ajax，这样就触发了3个ajax了，其实对于用户来说，只有最后一次ajax是有用的，前面2次不但浪费资源，而且影响性能。当然你可能会想到我们可以abort前面的ajax请求，但要注意abort只是abort客户端的执行，服务器端还是会接收到请求并执行完毕。于是对这个ajax做了个延迟，每次点击后延迟0.5秒执行，如果用户在0.5秒内再一次点击，则取消之前的ajax。这样就可以避免一些不必要的ajax请求了。&lt;/p&gt;&#xD;
&lt;p&gt;&lt;/p&gt;&#xD;
&lt;p&gt;&lt;strong&gt;后语&lt;/strong&gt;&lt;/p&gt;&#xD;
&lt;p&gt;&lt;span style="white-space: pre;"&gt;	&lt;/span&gt; 今天这篇文章只是介绍优化的方法，并没写任何代码，个人觉的这种方法不需要写代码，大家一看应该就知道。&lt;/p&gt;&#xD;
&lt;p&gt;&lt;/p&gt;&#xD;
&lt;p&gt;&lt;span style="white-space: pre;"&gt;	&lt;/span&gt; 该页面中经过这些优化后，页面总的加载速度(包括资源下载、解析、执行、页面呈现)提高了3倍左右。&lt;/p&gt;&#xD;
&lt;p&gt;&lt;/p&gt;&#xD;
&lt;div id="_mcePaste" style="position: absolute; left: -10000px; top: 357px; width: 1px; height: 1px; overflow-x: hidden; overflow-y: hidden;"&gt;目前的解决方案是服务器端和js结合使用，通过jsp的标签(net应该叫自定义控件)生成html代码,并不生成任何js来绑定事件，而且当用户第一次点击input的时候，才绑定所有事件，弹出下拉窗口。&lt;/div&gt;&#xD;
&lt;div id="_mcePaste" style="position: absolute; left: -10000px; top: 357px; width: 1px; height: 1px; overflow-x: hidden; overflow-y: hidden;"&gt;这样就完全解决了渲染的问题，因为不需要js来生成html，也不需要页面加载的时候去绑定所有事件。目前的解决方案是服务器端和js结合使用，通过jsp的标签(net应该叫自定义控件)生成html代码,并不生成任何js来绑定事件，而且当用户第一次点击input的时候，才绑定所有事件，弹出下拉窗口。这样就完全解决了渲染的问题，因为不需要js来生成html，也不需要页面加载的时候去绑定所有事件。&lt;/div&gt;&lt;img src="http://www.cnblogs.com/BearsTaR/aggbug/1778120.html?type=1" width="1" height="1" alt=""/&gt;&lt;p&gt;&lt;a href="http://www.cnblogs.com/BearsTaR/archive/2010/07/16/Tally_Optimization2.html" target="_blank"&gt;本文链接&lt;/a&gt;&lt;/p&gt;</content></entry><entry><id>http://www.cnblogs.com/BearsTaR/archive/2010/07/14/Tally_Optimization.html</id><title type="text">记一复杂页面的前端优化(1) - 不一样的延迟加载</title><summary type="text">刚刚做完1个复杂页面的前端性能优化，这里的优化是针对这个页面具体的需求单独做的优化，所以这里不会谈哪些减少http请求，合并压缩js,css，图片合并等等。因为这些是所有页面都需要做的，如果需要了解这些，可以参考我这篇文章：</summary><published>2010-07-14T00:32:00Z</published><updated>2010-07-14T00:32:00Z</updated><author><name>BearRui(AK-47)</name><uri>http://www.cnblogs.com/BearsTaR/</uri></author><link rel="alternate" href="http://www.cnblogs.com/BearsTaR/archive/2010/07/14/Tally_Optimization.html"/><link rel="alternate" type="text/html" href="http://www.cnblogs.com/BearsTaR/archive/2010/07/14/Tally_Optimization.html"/><content type="html">&lt;p&gt;刚刚做完1个复杂页面的前端性能优化，这里的优化是针对这个页面具体的需求单独做的优化，所以这里不会谈那些减少http请求，合并压缩js,css，图片合并等等。因为这些是所有页面都需要做的，如果需要了解这些，可以参考我这篇文章：&lt;a target="_blank" href="http://www.cnblogs.com/BearsTaR/archive/2010/05/12/web_performance.html"&gt;web高性能开发系列随笔&lt;/a&gt;&lt;/p&gt;&#xD;
&lt;p&gt;&lt;/p&gt;&#xD;
&lt;p&gt;&lt;strong&gt;页面介绍：&lt;/strong&gt;&lt;/p&gt;&#xD;
&lt;p&gt;该页面是1个记账类的页面，页面如下：&lt;/p&gt;&#xD;
&lt;p&gt;&lt;img src="http://pic002.cnblogs.com/img/bearstar/201007/2010071317292919.jpg" /&gt;&lt;/p&gt;&#xD;
&lt;p&gt;&lt;/p&gt;&#xD;
&lt;p&gt;页面主要有4部分组成：&lt;/p&gt;&#xD;
&lt;p&gt;&lt;span style="white-space: pre;"&gt;		&lt;/span&gt;1. 上部的输入部分(有5大不同的类型，每个类型都是1个单独的tab，对应内容也不一样)&lt;span style="white-space: pre;"&gt;	&lt;/span&gt; &amp;nbsp;&lt;/p&gt;&#xD;
&lt;p&gt;&lt;span style="white-space: pre;"&gt;		&lt;/span&gt;2. 左边的分类列表(默认显示一级分类，点击展开子类)&lt;span style="white-space: pre;"&gt;	&lt;/span&gt;&lt;/p&gt;&#xD;
&lt;p&gt;&lt;span style="white-space: pre;"&gt;		&lt;/span&gt;3. 右边时间选择区(按月，年，季，自定义时间过滤等等)&lt;/p&gt;&#xD;
&lt;p&gt;&lt;span style="white-space: pre;"&gt;		&lt;/span&gt;4. 右边下半部分的数据列表(默认只显示每条数据基本信息，点击展开详细信息)&amp;nbsp;&lt;/p&gt;&#xD;
&lt;p&gt;&lt;/p&gt;&#xD;
&lt;p&gt;可能看到这里大家不觉的这个页面会很大，那就再细说下，该页面包含记账的所有的功能(添加、删除，修改，分拆，上传图片，显示数据，数据排序)，而且每种下拉列表前面都有个"加号"(见输入部分的下列列表)，点击"加号"都会弹出类似如下的窗口进行添加(总共有8个左右的弹出窗口)，所有的这些都是通过js来实现(js代码总共写了大概2000行，不含注释)：&lt;/p&gt;&#xD;
&lt;p&gt;&lt;img src="http://pic002.cnblogs.com/img/bearstar/201007/2010071317361234.jpg" /&gt;&lt;/p&gt;&#xD;
&lt;p&gt;&lt;/p&gt;&#xD;
&lt;p&gt;&lt;/p&gt;&#xD;
&lt;p&gt;&lt;strong&gt;问题&lt;/strong&gt;&lt;/p&gt;&#xD;
&lt;p&gt;该页面有一些用户反映比较慢，经过测试也发现，因为页面比较复杂，js也比较多，所以在IE下速度会比较慢(特别是IE6)，而chrome和firefox速度还是可以的，所以这次的优化主要针对IE，当然优化后的其他浏览器肯定也会受益。&lt;/p&gt;&#xD;
&lt;p&gt;&lt;/p&gt;&#xD;
&lt;p&gt;&lt;strong&gt;优化1：弹出窗口的延迟加载&lt;/strong&gt;&lt;/p&gt;&#xD;
&lt;p&gt;本来第1个优化不应该写这个，因为这个优化效果并不是最明显的。把它放在第一位，是因为个人觉得这种延迟加载的想法还不错，比较有新意(目前还没见过网上有人介绍过这种延迟加载)。&lt;/p&gt;&#xD;
&lt;p&gt;&lt;/p&gt;&#xD;
&lt;p&gt;入正题，上面说到，该页面总共有8个弹出窗口，而且每个弹出窗口的都使用了不同的图片(不少是png)，监控发现这些弹出窗口用的png图片虽然设置了缓存头(也使用了document.execCommand("BackgroundImageCache", false, true);)，但是在IE6下每次都不直接使用缓存，而是发生1个请求，并得到304状态回应(原因我估计跟使用DD_belatedPNG来处理png图片有关，因为时间关系还没深入研究)，监控图如下：&lt;/p&gt;&#xD;
&lt;p&gt;&lt;img src="http://pic002.cnblogs.com/img/bearstar/201007/2010071317382689.jpg" /&gt;&lt;/p&gt;&#xD;
&lt;p&gt;从图中可以看出这几个图片很影响加载速度，其实一开始我们根本用不上这些弹出窗口的图片，因为默认都是隐藏的，而且这些弹出窗口，一般用户都用的比较少。理所当然，我们想到了延迟加载。&lt;/p&gt;&#xD;
&lt;p&gt;&lt;/p&gt;&#xD;
&lt;p&gt;想到延迟加载，第一想到就是先不加载弹出窗口的html代码，这样就不会加载对应的图片了，当用户点击弹出按钮的时候，再去后台加载对应的html代码。但这样就有个问题，当用户点击"加号"按钮，用ajax去加载html代码，用户明显就会感觉到半天窗口还没弹出来，就会连续的点击，这种用户体验肯定是失败的。&lt;/p&gt;&#xD;
&lt;p&gt;&lt;/p&gt;&#xD;
&lt;p&gt;我们想要的延迟加载是先加载html代码，但不加载html代码使用的图片。但用户点击"加号"的时候，直接弹出窗口并加载图片，这样用户一点击就可以看到窗口。那如何实现这种功能了，于是我想到了html的注释。我们先把所有弹出窗口的html代码放进注释中(这样就不会加载图片)，当用户点击"加号"时，用js读取注释中的html插入到body中(不需要ajax)，然后弹出窗口。&lt;/p&gt;&#xD;
&lt;p&gt;&lt;/p&gt;&#xD;
&lt;p&gt;比如有2个弹出窗口，代码大概如下(并不是完整代码，不能直接运行)：&lt;/p&gt;&#xD;
&lt;p&gt;&lt;/p&gt;&#xD;
&lt;pre &gt;&amp;lt;script&amp;gt;&#xD;
	 	 var loaded = new Object();  // 记录哪些html已经append到body中&#xD;
	 	/**&#xD;
		 * 加载html，该html已经以注释的方式嵌入的html中，eg:&#xD;
		 * &amp;lt;div id="fast_model_lazy"&amp;gt;&#xD;
		 *	&amp;lt;!--[lazy]&amp;gt;&#xD;
		 *	sass&#xD;
		 *  &amp;lt;![endlazy]--&amp;gt;&#xD;
		 * &amp;lt;/div&amp;gt;&#xD;
		 */	&#xD;
		function loadHtml(id){&#xD;
			// 已经加载过，不再加载&#xD;
			if(loaded[id])&#xD;
				return false;&#xD;
			&#xD;
			var html = $.trim(document.getElementById(id).innerHTML);&#xD;
			// 去掉注释开头(11位)和结尾(14位)&#xD;
			html = html.substring(11,html.length-14);&#xD;
			$(document.body).append($(html));&#xD;
			&#xD;
			loaded[id]=1;&#xD;
			return true;&#xD;
		}&#xD;
		function click1(){&#xD;
			loadHtml("fast_model_lazy");&#xD;
			// 弹出窗口&#xD;
			$("#fast_model_lazy").showDialog();&#xD;
		}&#xD;
		function click2(){&#xD;
			loadHtml("fast_model2_lazy");&#xD;
			// 弹出窗口&#xD;
			$("#fast_model2_lazy").showDialog();&#xD;
		}&#xD;
	 &amp;lt;/script&amp;gt;&#xD;
	 &amp;lt;button click="click1()"&amp;gt;弹出第一窗口&amp;lt;/button&amp;gt;&#xD;
	 &amp;lt;button click="click2()"&amp;gt;弹出第二窗口&amp;lt;/button&amp;gt;&#xD;
	 &#xD;
	 &amp;lt;div id="fast_model_lazy"&amp;gt;&#xD;
	   &amp;lt;!--[lazy]&amp;gt;&#xD;
	   &amp;lt;div id="fast_model" &amp;gt;&#xD;
	   		....这里省略html&#xD;
	   &amp;lt;/div&amp;gt;&#xD;
	  &amp;lt;![endlazy]--&amp;gt;&#xD;
	 &amp;lt;/div&amp;gt;&#xD;
	&#xD;
	 &amp;lt;div id="fast_model2_lazy"&amp;gt;&#xD;
	   &amp;lt;!--[lazy]&amp;gt;&#xD;
	   &amp;lt;div id="fast_model2" &amp;gt;&#xD;
	   		....这里省略html&#xD;
	   &amp;lt;/div&amp;gt;&#xD;
	  &amp;lt;![endlazy]--&amp;gt;&#xD;
	 &amp;lt;/div&amp;gt;&#xD;
&lt;/pre&gt;&#xD;
&lt;p&gt;&lt;/p&gt;&#xD;
&lt;p&gt;&lt;strong&gt;总结：&lt;/strong&gt;&lt;/p&gt;&#xD;
&lt;p&gt;&lt;span style="white-space: pre;"&gt;	&lt;/span&gt; 这种延迟加载的方式，主要用于延迟图片的加载，css的应用，js的解析和执行等等，并不是为了延迟加载html。如果是大量的html代码，比如分页的数据，&lt;/p&gt;&#xD;
&lt;p&gt;使用这种方式就不太合适。个人觉的这种加载方式还可以在很多地方用的到的。&lt;/p&gt;&#xD;
&lt;p&gt;&lt;/p&gt;&#xD;
&lt;p&gt;&lt;strong&gt;后语：&lt;/strong&gt;&lt;/p&gt;&#xD;
&lt;p&gt;&lt;span style="white-space: pre;"&gt;	&lt;/span&gt; 今天就写这些，下次再写写对该页面的其他的一些优化。&lt;/p&gt;&lt;img src="http://www.cnblogs.com/BearsTaR/aggbug/1776642.html?type=1" width="1" height="1" alt=""/&gt;&lt;p&gt;&lt;a href="http://www.cnblogs.com/BearsTaR/archive/2010/07/14/Tally_Optimization.html" target="_blank"&gt;本文链接&lt;/a&gt;&lt;/p&gt;</content></entry><entry><id>http://www.cnblogs.com/BearsTaR/archive/2010/07/02/tudou_easeOutBounce.html</id><title type="text">名站技术分析 — tudou网首页下列菜单的弹出效果</title><summary type="text">土豆(tudou.com)首页的导航条,当鼠标移到到“社区”菜单时，对应的菜单的弹出效果比较有意思，类似于一个弹球落地的效果，对于有意思的东西，当然要研究研究。有兴趣的朋友可以自己先去看看效果，然后再来看文章。</summary><published>2010-07-02T00:40:00Z</published><updated>2010-07-02T00:40:00Z</updated><author><name>BearRui(AK-47)</name><uri>http://www.cnblogs.com/BearsTaR/</uri></author><link rel="alternate" href="http://www.cnblogs.com/BearsTaR/archive/2010/07/02/tudou_easeOutBounce.html"/><link rel="alternate" type="text/html" href="http://www.cnblogs.com/BearsTaR/archive/2010/07/02/tudou_easeOutBounce.html"/><content type="html">&#xD;
&lt;style type="text/css"&gt;&lt;!--&#xD;
		#b_menu{border:1px solid #F56E0B;width:100px;list-style:none;padding:0;height:0;overflow:hidden;display:none;}&#xD;
		#b_menu li{line-height:25px;width:100px;text-align:center;}&#xD;
--&gt;&lt;/style&gt;&#xD;
&lt;p&gt;土豆(tudou.com)首页的导航条,当鼠标移到到&amp;ldquo;社区&amp;rdquo;菜单时，对应的菜单的弹出效果比较有意思，类似于一个弹球落地的效果，对于有意思的东西，当然要研究研究。有兴趣的朋友可以自己先去看看效果，然后再来看文章。&lt;/p&gt;&#xD;
&lt;p&gt;&lt;/p&gt;&#xD;
&lt;p&gt;&lt;strong&gt;tudou代码&lt;/strong&gt;&lt;/p&gt;&#xD;
&lt;p&gt;看了tudou的js代码，发现他们也是使用jquery来实现动画效果的，代码如下：&lt;/p&gt;&#xD;
&lt;p&gt;f.style.height=0;&lt;/p&gt;&#xD;
&lt;p&gt;this.style.visibility="visible";&lt;/p&gt;&#xD;
&lt;p&gt;&lt;span style="color: #0000ff;"&gt;$(f).animate({height:g},500,"easeOutBounce");&lt;/span&gt;&lt;/p&gt;&#xD;
&lt;p&gt;$(i).addClass("hover")&lt;/p&gt;&#xD;
&lt;p&gt;&lt;/p&gt;&#xD;
&lt;p&gt;最重要的是上面第三行代码，使用jquery的animate的函数，其中重点就是tudou自定义了animate的easing函数，即easeOutBounce函数，easeOutBounce函数如下。&lt;/p&gt;&#xD;
&lt;p&gt;&lt;/p&gt;&#xD;
&lt;pre &gt;easeOutBounce:function(o,p,n,r,q){&#xD;
	if((p/=q)&amp;lt;(1/2.75)){&#xD;
		return r*(7.5625*p*p)+n&#xD;
	}else{&#xD;
		if(p&amp;lt;(2/2.75)){&#xD;
			return r*(7.5625*(p-=(1.5/2.75))*p+0.75)+n&#xD;
		}else{&#xD;
			if(p&amp;lt;(2.5/2.75)){&#xD;
				return r*(7.5625*(p-=(2.25/2.75))*p+0.9375)+n&#xD;
			}else{&#xD;
				return r*(7.5625*(p-=(2.625/2.75))*p+0.984375)+n&#xD;
			}&#xD;
		}&#xD;
	}&#xD;
   }&#xD;
&lt;/pre&gt;&#xD;
&lt;p&gt;&lt;/p&gt;&#xD;
&lt;div&gt;&#xD;
&lt;div&gt;&lt;strong&gt;DEMO&lt;/strong&gt;&lt;/div&gt;&#xD;
&lt;div&gt;　　先不分析代码，先用tudou的easeOutBounce函数做个demo看看效果。&lt;/div&gt;&#xD;
&lt;div&gt;　　demo(该demo在IE下点击没有效果，可能是跟博客园的其他代码有冲突，不想花时间去解决。要在IE下看效果，请copy后面的代码在本地进行测试)：&lt;/div&gt;&#xD;
&lt;div style="height: 150px; padding-left: 20px;"&gt;&#xD;
&amp;nbsp;&amp;nbsp;&lt;a href="javascript:void(0)" onclick="b_showMenu();"&gt;我的菜单(点击我)&lt;/a&gt;&lt;br /&gt; &#xD;
&lt;ul id="b_menu"&gt;&#xD;
&lt;li&gt;菜单一&lt;/li&gt;&#xD;
&lt;li&gt;菜单二&lt;/li&gt;&#xD;
&lt;li&gt;菜单三&lt;/li&gt;&#xD;
&lt;li&gt;菜单四&lt;/li&gt;&#xD;
&lt;/ul&gt;&#xD;
&lt;/div&gt;&#xD;
&lt;/div&gt;&#xD;
&lt;p&gt;&lt;/p&gt;&#xD;
&lt;p&gt;代码：&lt;/p&gt;&#xD;
&lt;p&gt;&lt;/p&gt;&#xD;
&lt;pre &gt;&amp;lt;!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"&amp;gt;&#xD;
&amp;lt;html xmlns="http://www.w3.org/1999/xhtml"&amp;gt;&#xD;
	&amp;lt;head&amp;gt;&#xD;
	&amp;lt;meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /&amp;gt;&#xD;
	&amp;lt;script type="text/javascript" src="http://common.cnblogs.com/script/jquery.js"&amp;gt;&amp;lt;/script&amp;gt;&#xD;
	&amp;lt;script type="text/javascript"&amp;gt;&#xD;
	jQuery.extend(jQuery.easing,{&#xD;
		def : "easeOutQuad",&#xD;
		swing : function(o, p, n, r, q) {&#xD;
			return jQuery.easing[jQuery.easing.def](o, p, n, r,q)&#xD;
		},&#xD;
		easeOutBounce : function(o, p, n, r, q) {&#xD;
			if ((p /= q) &amp;lt; (1 / 2.75)) {&#xD;
				return r * (7.5625 * p * p) + n&#xD;
			} else {&#xD;
				if (p &amp;lt; (2 / 2.75)) {&#xD;
					return r * (7.5625 * (p -= (1.5 / 2.75)) * p + 0.75) + n&#xD;
				} else {&#xD;
					if (p &amp;lt; (2.5 / 2.75)) {&#xD;
						return r * (7.5625 * (p -= (2.25 / 2.75))	* p + 0.9375) + n&#xD;
					} else {&#xD;
						return r * (7.5625 * (p -= (2.625 / 2.75)) * p + 0.984375) + n&#xD;
					}&#xD;
				}&#xD;
			}&#xD;
		}&#xD;
	});&#xD;
	function showMenu(){&#xD;
		resetMenu();&#xD;
		$("#b_menu").animate({height:100},500,"easeOutBounce");&#xD;
	}&#xD;
	function resetMenu(){&#xD;
		$("#b_menu").show();&#xD;
		$("#b_menu").height(0);&#xD;
	}&#xD;
	&amp;lt;/script&amp;gt;&#xD;
	&#xD;
	&amp;lt;style type="text/css"&amp;gt;&#xD;
		#b_menu{border:1px solid #F56E0B;width:100px;list-style:none;padding:0;height:0;overflow:hidden;display:none;}&#xD;
		#b_menu li{line-height:25px;width:100px;text-align:center;}&#xD;
	&amp;lt;/style&amp;gt;		&#xD;
	&amp;lt;/head&amp;gt;&#xD;
	&amp;lt;body&amp;gt;&#xD;
	  &amp;lt;a href="javascript:showMenu();void(0)"&amp;gt;我的菜单&amp;lt;/a&amp;gt;&amp;lt;br /&amp;gt;&#xD;
	  &amp;lt;ul id="b_menu"&amp;gt;&#xD;
	  	&amp;lt;li&amp;gt;菜单一&amp;lt;/li&amp;gt;	&#xD;
	  	&amp;lt;li&amp;gt;菜单二&amp;lt;/li&amp;gt;	&#xD;
	  	&amp;lt;li&amp;gt;菜单三&amp;lt;/li&amp;gt;	&#xD;
	  	&amp;lt;li&amp;gt;菜单四&amp;lt;/li&amp;gt;	&#xD;
	  &amp;lt;/ul&amp;gt;		&#xD;
  &amp;lt;/body&amp;gt;		&#xD;
&amp;lt;/html&amp;gt;  &#xD;
&lt;/pre&gt;&#xD;
&lt;p&gt;&lt;/p&gt;&#xD;
&lt;p&gt;&lt;/p&gt;&#xD;
&lt;div&gt;&#xD;
&lt;div&gt;&lt;strong&gt;easing函数&lt;/strong&gt;&lt;/div&gt;&#xD;
&lt;div&gt;　　jquery默认定义了2个easing函数，分别是swing和linear,easing函数格式如下：function(o, p, n, r, q)&lt;/div&gt;&#xD;
&lt;div&gt;但对于该几个参数的具体说明，jquery官方也没有文档说明(不知道是否是我没有找到)，经过我看源代码和自己的理解，对几个参数理解如下：&lt;/div&gt;&#xD;
&lt;div&gt;o = p/q&lt;/div&gt;&#xD;
&lt;div&gt;p: 当前时间 - animate开始时间的毫秒值&lt;/div&gt;&#xD;
&lt;div&gt;n: 起始值，一直为0&lt;/div&gt;&#xD;
&lt;div&gt;r: 这个个人认为是递增值，一直为1&lt;/div&gt;&#xD;
&lt;div&gt;q: animate中的duration参数，即设置的动画效果运行完毕需要的时间&lt;/div&gt;&#xD;
&lt;div&gt;返回值：返回1个大于0，小于等于1的百分比值，animate方法通过这个百分比去计算各个参数的值&lt;/div&gt;&#xD;
&lt;div&gt;&lt;/div&gt;&#xD;
&lt;div&gt;　　知道这几个参数的含义后，再看看tudou的easeOutBounce，就发现其第一行代码写的有问题，if ((p /= q) &amp;lt; (1 / 2.75)) 其实可以直接写成&amp;nbsp;if ((o) &amp;lt; (1 / 2.75)) 。&lt;/div&gt;&#xD;
&lt;div&gt;可以看出tudou的开发人员对easing函数的几个参数也不太理解，不然就不会这样写了(也有可能easeOutBounce函数，tudou也是直接从其他地方copy过来的，呵呵)&lt;/div&gt;&#xD;
&lt;/div&gt;&#xD;
&lt;div&gt;&lt;/div&gt;&#xD;
&lt;div&gt;&#xD;
&lt;div&gt;&lt;strong&gt;&lt;br /&gt;&lt;/strong&gt;&lt;/div&gt;&#xD;
&lt;div&gt;&lt;strong&gt;胡言乱语&lt;/strong&gt;&lt;/div&gt;&#xD;
&lt;div&gt;　　在查询jquery的easing参数的时候，无意间发现1个专门做easing效果的网站(&lt;a target="_blank" href="http://gsgd.co.uk/sandbox/jquery/easing/"&gt;http://gsgd.co.uk/sandbox/jquery/easing/&lt;/a&gt;)，而土豆的几个easing效果代码跟该网站的easing效果代码是惊人的相似，除了参数名不同外(这也出现我前面copy 代码的猜测),其实是不是copy都无所谓的，偶也是胡言乱语下，大家也别想太多，贴出2段代码，大家自己看看吧。&lt;/div&gt;&#xD;
&lt;/div&gt;&#xD;
&lt;div&gt;&lt;/div&gt;&#xD;
&lt;div&gt;下面tudou的代码：&lt;/div&gt;&#xD;
&lt;div&gt;&#xD;
&lt;pre &gt;jQuery.extend(jQuery.easing,{&#xD;
	def : "easeOutQuad",&#xD;
	swing : function(o, p, n, r, q) {&#xD;
		return jQuery.easing[jQuery.easing.def](o, p, n, r,q)&#xD;
	},&#xD;
	easeInQuad : function(o, p, n, r, q) {&#xD;
		return r * (p /= q) * p + n&#xD;
	},&#xD;
	easeOutQuad : function(o, p, n, r, q) {&#xD;
		return -r * (p /= q) * (p - 2) + n&#xD;
	},&#xD;
	easeInOutQuad : function(o, p, n, r, q) {&#xD;
		if ((p /= q / 2) &amp;lt; 1) {&#xD;
			return r / 2 * p * p * p + n&#xD;
		}&#xD;
		return r / 2 * ((p -= 2) * p * p + 2) + n&#xD;
	},&#xD;
	easeInBack : function(o, p, n, u, r, q) {&#xD;
		if (q == undefined) {&#xD;
			q = 1.70158&#xD;
		}&#xD;
		return u * (p /= r) * p * ((q + 1) * p - q) + n&#xD;
	},&#xD;
	easeOutBack : function(o, p, n, u, r, q) {&#xD;
		if (q == undefined) {&#xD;
			q = 1.70158&#xD;
		}&#xD;
		return u * ((p = p / r - 1) * p * ((q + 1) * p + q) + 1) + n&#xD;
	},&#xD;
	easeOutBounce : function(o, p, n, r, q) {&#xD;
		if ((p /= q) &amp;lt; (1 / 2.75)) {&#xD;
			return r * (7.5625 * p * p) + n&#xD;
		} else {&#xD;
			if (p &amp;lt; (2 / 2.75)) {&#xD;
				return r * (7.5625 * (p -= (1.5 / 2.75)) * p + 0.75) + n&#xD;
			} else {&#xD;
				if (p &amp;lt; (2.5 / 2.75)) {&#xD;
					return r * (7.5625 * (p -= (2.25 / 2.75))	* p + 0.9375) + n&#xD;
				} else {&#xD;
					return r * (7.5625 * (p -= (2.625 / 2.75)) * p + 0.984375) + n&#xD;
				}&#xD;
			}&#xD;
		}&#xD;
	}&#xD;
});&#xD;
&lt;/pre&gt;&#xD;
&lt;/div&gt;&#xD;
&lt;div&gt;&lt;a target="_blank" href="http://gsgd.co.uk/sandbox/jquery/easing/jquery.easing.1.3.js"&gt;http://gsgd.co.uk/sandbox/jquery/easing/jquery.easing.1.3.js&lt;/a&gt; 代码&lt;/div&gt;&#xD;
&lt;div&gt;&#xD;
&lt;pre &gt;jQuery.extend( jQuery.easing,{&#xD;
	def: 'easeOutQuad',&#xD;
	swing: function (x, t, b, c, d) {&#xD;
		//alert(jQuery.easing.default);&#xD;
		return jQuery.easing[jQuery.easing.def](x, t, b, c, d);&#xD;
	},&#xD;
	easeInQuad: function (x, t, b, c, d) {&#xD;
		return c*(t/=d)*t + b;&#xD;
	},&#xD;
	easeOutQuad: function (x, t, b, c, d) {&#xD;
		return -c *(t/=d)*(t-2) + b;&#xD;
	},&#xD;
	easeInOutQuad: function (x, t, b, c, d) {&#xD;
		if ((t/=d/2) &amp;lt; 1) return c/2*t*t + b;&#xD;
		return -c/2 * ((--t)*(t-2) - 1) + b;&#xD;
	},&#xD;
	easeInCubic: function (x, t, b, c, d) {&#xD;
		return c*(t/=d)*t*t + b;&#xD;
	},&#xD;
	easeOutCubic: function (x, t, b, c, d) {&#xD;
		return c*((t=t/d-1)*t*t + 1) + b;&#xD;
	},&#xD;
	easeInOutCubic: function (x, t, b, c, d) {&#xD;
		if ((t/=d/2) &amp;lt; 1) return c/2*t*t*t + b;&#xD;
		return c/2*((t-=2)*t*t + 2) + b;&#xD;
	},&#xD;
	easeInQuart: function (x, t, b, c, d) {&#xD;
		return c*(t/=d)*t*t*t + b;&#xD;
	},&#xD;
	easeOutQuart: function (x, t, b, c, d) {&#xD;
		return -c * ((t=t/d-1)*t*t*t - 1) + b;&#xD;
	},&#xD;
	easeInOutQuart: function (x, t, b, c, d) {&#xD;
		if ((t/=d/2) &amp;lt; 1) return c/2*t*t*t*t + b;&#xD;
		return -c/2 * ((t-=2)*t*t*t - 2) + b;&#xD;
	},&#xD;
	easeInQuint: function (x, t, b, c, d) {&#xD;
		return c*(t/=d)*t*t*t*t + b;&#xD;
	},&#xD;
	easeOutQuint: function (x, t, b, c, d) {&#xD;
		return c*((t=t/d-1)*t*t*t*t + 1) + b;&#xD;
	},&#xD;
	easeInOutQuint: function (x, t, b, c, d) {&#xD;
		if ((t/=d/2) &amp;lt; 1) return c/2*t*t*t*t*t + b;&#xD;
		return c/2*((t-=2)*t*t*t*t + 2) + b;&#xD;
	},&#xD;
	easeInSine: function (x, t, b, c, d) {&#xD;
		return -c * Math.cos(t/d * (Math.PI/2)) + c + b;&#xD;
	},&#xD;
	easeOutSine: function (x, t, b, c, d) {&#xD;
		return c * Math.sin(t/d * (Math.PI/2)) + b;&#xD;
	},&#xD;
	easeInOutSine: function (x, t, b, c, d) {&#xD;
		return -c/2 * (Math.cos(Math.PI*t/d) - 1) + b;&#xD;
	},&#xD;
	easeInExpo: function (x, t, b, c, d) {&#xD;
		return (t==0) ? b : c * Math.pow(2, 10 * (t/d - 1)) + b;&#xD;
	},&#xD;
	easeOutExpo: function (x, t, b, c, d) {&#xD;
		return (t==d) ? b+c : c * (-Math.pow(2, -10 * t/d) + 1) + b;&#xD;
	},&#xD;
	easeInOutExpo: function (x, t, b, c, d) {&#xD;
		if (t==0) return b;&#xD;
		if (t==d) return b+c;&#xD;
		if ((t/=d/2) &amp;lt; 1) return c/2 * Math.pow(2, 10 * (t - 1)) + b;&#xD;
		return c/2 * (-Math.pow(2, -10 * --t) + 2) + b;&#xD;
	},&#xD;
	easeInCirc: function (x, t, b, c, d) {&#xD;
		return -c * (Math.sqrt(1 - (t/=d)*t) - 1) + b;&#xD;
	},&#xD;
	easeOutCirc: function (x, t, b, c, d) {&#xD;
		return c * Math.sqrt(1 - (t=t/d-1)*t) + b;&#xD;
	},&#xD;
	easeInOutCirc: function (x, t, b, c, d) {&#xD;
		if ((t/=d/2) &amp;lt; 1) return -c/2 * (Math.sqrt(1 - t*t) - 1) + b;&#xD;
		return c/2 * (Math.sqrt(1 - (t-=2)*t) + 1) + b;&#xD;
	},&#xD;
	easeInElastic: function (x, t, b, c, d) {&#xD;
		var s=1.70158;var p=0;var a=c;&#xD;
		if (t==0) return b;  if ((t/=d)==1) return b+c;  if (!p) p=d*.3;&#xD;
		if (a &amp;lt; Math.abs(c)) { a=c; var s=p/4; }&#xD;
		else var s = p/(2*Math.PI) * Math.asin (c/a);&#xD;
		return -(a*Math.pow(2,10*(t-=1)) * Math.sin( (t*d-s)*(2*Math.PI)/p )) + b;&#xD;
	},&#xD;
	easeOutElastic: function (x, t, b, c, d) {&#xD;
		var s=1.70158;var p=0;var a=c;&#xD;
		if (t==0) return b;  if ((t/=d)==1) return b+c;  if (!p) p=d*.3;&#xD;
		if (a &amp;lt; Math.abs(c)) { a=c; var s=p/4; }&#xD;
		else var s = p/(2*Math.PI) * Math.asin (c/a);&#xD;
		return a*Math.pow(2,-10*t) * Math.sin( (t*d-s)*(2*Math.PI)/p ) + c + b;&#xD;
	},&#xD;
	easeInOutElastic: function (x, t, b, c, d) {&#xD;
		var s=1.70158;var p=0;var a=c;&#xD;
		if (t==0) return b;  if ((t/=d/2)==2) return b+c;  if (!p) p=d*(.3*1.5);&#xD;
		if (a &amp;lt; Math.abs(c)) { a=c; var s=p/4; }&#xD;
		else var s = p/(2*Math.PI) * Math.asin (c/a);&#xD;
		if (t &amp;lt; 1) return -.5*(a*Math.pow(2,10*(t-=1)) * Math.sin( (t*d-s)*(2*Math.PI)/p )) + b;&#xD;
		return a*Math.pow(2,-10*(t-=1)) * Math.sin( (t*d-s)*(2*Math.PI)/p )*.5 + c + b;&#xD;
	},&#xD;
	easeInBack: function (x, t, b, c, d, s) {&#xD;
		if (s == undefined) s = 1.70158;&#xD;
		return c*(t/=d)*t*((s+1)*t - s) + b;&#xD;
	},&#xD;
	easeOutBack: function (x, t, b, c, d, s) {&#xD;
		if (s == undefined) s = 1.70158;&#xD;
		return c*((t=t/d-1)*t*((s+1)*t + s) + 1) + b;&#xD;
	},&#xD;
	easeInOutBack: function (x, t, b, c, d, s) {&#xD;
		if (s == undefined) s = 1.70158; &#xD;
		if ((t/=d/2) &amp;lt; 1) return c/2*(t*t*(((s*=(1.525))+1)*t - s)) + b;&#xD;
		return c/2*((t-=2)*t*(((s*=(1.525))+1)*t + s) + 2) + b;&#xD;
	},&#xD;
	easeInBounce: function (x, t, b, c, d) {&#xD;
		return c - jQuery.easing.easeOutBounce (x, d-t, 0, c, d) + b;&#xD;
	},&#xD;
	easeOutBounce: function (x, t, b, c, d) {&#xD;
		if ((t/=d) &amp;lt; (1/2.75)) {&#xD;
			return c*(7.5625*t*t) + b;&#xD;
		} else if (t &amp;lt; (2/2.75)) {&#xD;
			return c*(7.5625*(t-=(1.5/2.75))*t + .75) + b;&#xD;
		} else if (t &amp;lt; (2.5/2.75)) {&#xD;
			return c*(7.5625*(t-=(2.25/2.75))*t + .9375) + b;&#xD;
		} else {&#xD;
			return c*(7.5625*(t-=(2.625/2.75))*t + .984375) + b;&#xD;
		}&#xD;
	},&#xD;
	easeInOutBounce: function (x, t, b, c, d) {&#xD;
		if (t &amp;lt; d/2) return jQuery.easing.easeInBounce (x, t*2, 0, c, d) * .5 + b;&#xD;
		return jQuery.easing.easeOutBounce (x, t*2-d, 0, c, d) * .5 + c*.5 + b;&#xD;
	}&#xD;
});&#xD;
&lt;/pre&gt;&#xD;
&lt;/div&gt;&#xD;
&lt;div&gt;&lt;/div&gt;&#xD;
&lt;div&gt;相关链接&lt;/div&gt;&#xD;
&lt;div&gt;　　&lt;a target="_blank" href="http://www.cnblogs.com/BearsTaR/archive/2010/06/18/facebook_html_chunk.html" &gt;名站技术分析 &amp;mdash; facebook奇特的页面加载技术&lt;/a&gt;&lt;/div&gt;&#xD;
&lt;div&gt;　　&lt;a target="_blank" href="http://www.cnblogs.com/BearsTaR/archive/2010/05/25/tudou_lazy_image.html"&gt;名站技术分析 - 浅谈tudou.com首页图片延迟加载的效果&lt;/a&gt;&lt;/div&gt;&lt;img src="http://www.cnblogs.com/BearsTaR/aggbug/1769591.html?type=1" width="1" height="1" alt=""/&gt;&lt;p&gt;&lt;a href="http://www.cnblogs.com/BearsTaR/archive/2010/07/02/tudou_easeOutBounce.html" target="_blank"&gt;本文链接&lt;/a&gt;&lt;/p&gt;</content></entry><entry><id>http://www.cnblogs.com/BearsTaR/archive/2010/07/01/less.html</id><title type="text">LESS 让css也支持变量，运算符，include,嵌套规则等等</title><summary type="text">最近在网上看到1个很有意思的CSS扩展，这里介绍给大家。LESS 最早是1个ruby的gem，用于扩展css的语法，用了LESS后，可以在css中使用变量，运算符，include,嵌套规则等等。现在LESS出了js版本，让我们一起来看看LESS能为我们带来什么吧?</summary><published>2010-07-01T00:49:00Z</published><updated>2010-07-01T00:49:00Z</updated><author><name>BearRui(AK-47)</name><uri>http://www.cnblogs.com/BearsTaR/</uri></author><link rel="alternate" href="http://www.cnblogs.com/BearsTaR/archive/2010/07/01/less.html"/><link rel="alternate" type="text/html" href="http://www.cnblogs.com/BearsTaR/archive/2010/07/01/less.html"/><content type="html">&lt;p&gt;最近在网上看到1个很有意思的CSS扩展，这里介绍给大家。LESS 最早是1个ruby的gem，用于扩展css的语法，用了LESS后，可以在css中使用变量，运算符，include,嵌套规则等等。现在LESS出了js版本，让我们一起来看看LESS能为我们带来什么吧?&lt;/p&gt;&#xD;
&lt;p&gt;&lt;/p&gt;&#xD;
&lt;p&gt;&lt;strong&gt;使用&lt;/strong&gt;&lt;/p&gt;&#xD;
&lt;p&gt;1. 下载js: &lt;a href="http://lesscss.googlecode.com/" target="_blank"&gt;http://lesscss.googlecode.com/&lt;/a&gt; 最新版本好像是 1.0.22&lt;/p&gt;&#xD;
&lt;p&gt;2. 使用less，css文件的后缀名需要改为.less。&lt;/p&gt;&#xD;
&lt;p&gt;3. 在html页面中加入下面代码&lt;/p&gt;&#xD;
&lt;p&gt;&amp;lt;!-- style.less文件就是样式表文件，并且style.less必须放在less-1.0.22.min.js文件前加载，原理后面介绍 --&amp;gt;&lt;/p&gt;&#xD;
&lt;p&gt;&amp;lt;link rel="stylesheet/less" href="style.less" /&amp;gt; &amp;nbsp;&lt;/p&gt;&#xD;
&lt;p&gt;&amp;lt;script src="less-1.0.22.min.js"&amp;gt;&amp;lt;/script&amp;gt;&lt;/p&gt;&#xD;
&lt;p&gt;&lt;/p&gt;&#xD;
&lt;p&gt;&lt;strong&gt;变量&lt;/strong&gt;&lt;/p&gt;&#xD;
&lt;p&gt;变量可以让我们声明1个常量值，并在以后多处地方进行重复使用。&lt;/p&gt;&#xD;
&lt;p&gt;&lt;/p&gt;&#xD;
&lt;p&gt;一般css写法：&lt;/p&gt;&#xD;
&lt;pre &gt;.class1{&#xD;
      color:#ccc;&#xD;
      width:100px;&#xD;
   }&#xD;
   &#xD;
   .class2{&#xD;
      color:#ccc;&#xD;
      width:120px;&#xD;
   }&#xD;
&lt;/pre&gt;&#xD;
&lt;p&gt;&lt;/p&gt;&#xD;
&lt;div&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;LESS写法:&lt;/div&gt;&#xD;
&lt;div&gt;&#xD;
&lt;pre &gt;@color1: #ccc;&#xD;
   &#xD;
   .class1{&#xD;
      color:@color1;&#xD;
      width:100px;&#xD;
   }&#xD;
   &#xD;
   .class2{&#xD;
      color:@color1;&#xD;
      width:120px;&#xD;
   }&#xD;
&lt;/pre&gt;&#xD;
&lt;/div&gt;&#xD;
&lt;div&gt;&lt;strong&gt;&lt;br /&gt;&lt;/strong&gt;&lt;/div&gt;&#xD;
&lt;div&gt;&lt;strong&gt;inlucde&lt;/strong&gt;&lt;/div&gt;&#xD;
&lt;div&gt;&#xD;
&lt;div&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp;大家一定碰见过再某个规则中需要用的部分样式跟另外1个规则样式一样，但没办法，我们只能copy过来，或者为元素指定多个class。但用了LESS后，我们不再需要这么痛苦了。&lt;/div&gt;&#xD;
&lt;/div&gt;&#xD;
&lt;div&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp;&lt;/div&gt;&#xD;
&lt;div&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp;一般css写法：&lt;/div&gt;&#xD;
&lt;div&gt;&#xD;
&lt;pre &gt;.red{&#xD;
     color:red;border:1px solid red;&#xD;
   }&#xD;
   &#xD;
   .class2{&#xD;
      width:100px;font-size:12px;&#xD;
      /*下面的样式跟red的一样,copy过来的，修改就要修改2处*/&#xD;
      color:red;border:1px solid red;&#xD;
   }&#xD;
&lt;/pre&gt;&#xD;
&amp;nbsp;&lt;/div&gt;&#xD;
&lt;div&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp;LESS写法:&lt;/div&gt;&#xD;
&lt;div&gt;&#xD;
&lt;pre &gt;.red{&#xD;
     color:red;border:1px solid red;&#xD;
   }&#xD;
   &#xD;
   .class2{&#xD;
      width:100px;font-size:12px;&#xD;
      /*直接inlcude .red的规则*/&#xD;
      .red&#xD;
   }&#xD;
&lt;/pre&gt;&#xD;
&lt;/div&gt;&#xD;
&lt;div&gt;&lt;strong&gt;&lt;br /&gt;&lt;/strong&gt;&lt;/div&gt;&#xD;
&lt;div&gt;&lt;strong&gt;嵌套规则:&lt;/strong&gt;&lt;/div&gt;&#xD;
&lt;div&gt;　　一般css的写法：&lt;/div&gt;&#xD;
&lt;div&gt;&#xD;
&lt;pre &gt;#header{color:red;}&#xD;
　　#header .logo{backgroud-image:url(logo.gif);}&#xD;
　　#header li{display:block;} &#xD;
&lt;/pre&gt;&#xD;
&lt;/div&gt;&#xD;
&lt;div&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp;LESS写法:&lt;/div&gt;&#xD;
&lt;div&gt;&#xD;
&lt;pre &gt;#header{&#xD;
     color:red;&#xD;
     .logo{&#xD;
         backgroud-image:url(logo.gif);&#xD;
      }&#xD;
      li{&#xD;
        display:block;&#xD;
      } &#xD;
   }&#xD;
&lt;/pre&gt;&#xD;
&lt;/div&gt;&#xD;
&lt;div&gt;&lt;strong&gt;&lt;br /&gt;&lt;/strong&gt;&lt;/div&gt;&#xD;
&lt;div&gt;&lt;strong&gt;运算符：&lt;/strong&gt;&lt;/div&gt;&#xD;
&lt;div&gt;　　LESS 写法:&lt;/div&gt;&#xD;
&lt;div&gt;&#xD;
&lt;pre &gt;@fontSize 12px;&#xD;
    .class1{&#xD;
	font-size : @fontSize + 2;&#xD;
    }&#xD;
    .class2{&#xD;
	font-size : @fontSize * 2;&#xD;
    }&#xD;
&lt;/pre&gt;&#xD;
&lt;/div&gt;&#xD;
&lt;div&gt;&lt;strong&gt;&lt;br /&gt;&lt;/strong&gt;&lt;/div&gt;&#xD;
&lt;div&gt;&lt;strong&gt;更多其它功能:&lt;/strong&gt;&lt;/div&gt;&#xD;
&lt;div&gt;　　请见LESS官方网站：&lt;a href="http://lesscss.org/" target="_blank"&gt;http://lesscss.org/&lt;/a&gt;&lt;/div&gt;&#xD;
&lt;div&gt;&lt;/div&gt;&#xD;
&lt;div&gt;&lt;strong&gt;&lt;br /&gt;&lt;/strong&gt;&lt;/div&gt;&#xD;
&lt;div&gt;&lt;strong&gt;原理分析:&lt;/strong&gt;&lt;/div&gt;&#xD;
&lt;div&gt;　　LESS js版本的实现方式是使用ajax获取style.less文件，然后根据该文件的规则生成最终浏览器能理解的css插入到html代码中。所以就出现前面说过的&amp;lt;link rel="stylesheet/less" href="style.less" /&amp;gt;必须在js前面。&lt;/div&gt;&#xD;
&lt;div&gt;&lt;/div&gt;&#xD;
&lt;div&gt;&lt;strong&gt;&lt;br /&gt;&lt;/strong&gt;&lt;/div&gt;&#xD;
&lt;div&gt;&lt;strong&gt;总结:&lt;/strong&gt;&lt;/div&gt;&#xD;
&lt;div&gt;　　LESS JS版本的实现原理，是每次请求都需要通过JS去动态生成原始的css，如果css比较大的话，对于客户端的性能影响比较大，所以个人觉的less的js版本实用性不强。&lt;/div&gt;&#xD;
&lt;div&gt;　　不知道LESS 的ruby版本的实现原理是怎么样的，我认为如果真的觉得less方式可以提高css的开发效率，到是可以参考它的代码实现一套java或net的源代码，在程序启动的时候一次根据.less文件生成所有的css文件，而不是每次请求都用js动态生成。&lt;/div&gt;&#xD;
&lt;p&gt;&lt;/p&gt;&#xD;
&lt;div&gt;&lt;span style="color: #ff0000;"&gt;PS:刚刚无意间搜索，竟然找到1个net版本的less，大家可以看看这个版本怎么实现的&lt;/span&gt;：&lt;a target="_blank" href="http://www.dotlesscss.com/"&gt;http://www.dotlesscss.com/&lt;/a&gt;&lt;/div&gt;&lt;img src="http://www.cnblogs.com/BearsTaR/aggbug/1768741.html?type=1" width="1" height="1" alt=""/&gt;&lt;p&gt;&lt;a href="http://www.cnblogs.com/BearsTaR/archive/2010/07/01/less.html" target="_blank"&gt;本文链接&lt;/a&gt;&lt;/p&gt;</content></entry><entry><id>http://www.cnblogs.com/BearsTaR/archive/2010/06/25/css_tip_round_gradients_shadow.html</id><title type="text">CSS技巧 — 不使用图片实现圆角、阴影、渐变等功能</title><summary type="text">UI要求越来越高，界面越做越华丽，给我们开发人员带来的就是使用大量的背景图片，下面介绍一些通过css(不使用图片或少使用图片)来实现一些很常见的效果:圆角、阴影、渐变等等。</summary><published>2010-06-25T00:51:00Z</published><updated>2010-06-25T00:51:00Z</updated><author><name>BearRui(AK-47)</name><uri>http://www.cnblogs.com/BearsTaR/</uri></author><link rel="alternate" href="http://www.cnblogs.com/BearsTaR/archive/2010/06/25/css_tip_round_gradients_shadow.html"/><link rel="alternate" type="text/html" href="http://www.cnblogs.com/BearsTaR/archive/2010/06/25/css_tip_round_gradients_shadow.html"/><content type="html">&lt;style type="text/css"&gt;&lt;!--&#xD;
.b_box{&#xD;
	text-align:center;width:200px;line-height:60px;&#xD;
	border:1px solid #C0C0C0;background-color:#DBEAFF;&#xD;
	/*firefox*/&#xD;
	-moz-border-radius: 5px;&#xD;
	/*css3*/&#xD;
	border-radius: 5px;&#xD;
	/*webkit*/&#xD;
  -webkit-border-radius: 5px;&#xD;
}&#xD;
.b_shadow{&#xD;
  height:60px;line-height:60px;text-align:center;&#xD;
  width:200px;border:1px solid #C0C0C0;background-color:#DBEAFF;&#xD;
  -webkit-box-shadow: 5px 5px 5px rgba(0, 0, 0, 0.5);&#xD;
  -moz-box-shadow: 5px 5px 5px rgba(0, 0, 0, 0.5);&#xD;
  box-shadow: 5px 5px 5px rgba(0, 0, 0, 0.5);&#xD;
  /*IE6,IE7语法*/&#xD;
  filter:progid:DXImageTransform.Microsoft.dropshadow(OffX=5, OffY=5, Color='gray');&#xD;
  /*IE8语法,可恶的IE，不同的版本还要写的不一样*/&#xD;
  -ms-filter:"progid:DXImageTransform.Microsoft.dropshadow(OffX=5, OffY=5, Color='gray')"&#xD;
  -moz-border-radius: 5px;border-radius: 5px;-webkit-border-radius: 5px;&#xD;
}&#xD;
.gradients{&#xD;
  text-align:center;width:200px;line-height:60px;&#xD;
  background-&lt;mce:script type="text/javascript" mce_src="http://www.cnblogs.com/editor/tiny_mce/themes/advanced/langs/zh.js"&gt;&lt;/mce:script&gt;&lt;mce:script type="text/javascript" mce_src="http://www.cnblogs.com/editor/tiny_mce/plugins/insertCode/langs/zh.js"&gt;&lt;/mce:script&gt;&lt;mce:script type="text/javascript" mce_src="http://www.cnblogs.com/editor/tiny_mce/plugins/syntaxHighlighter/langs/zh.js"&gt;&lt;/mce:script&gt;&lt;mce:script type="text/javascript" mce_src="http://www.cnblogs.com/editor/tiny_mce/plugins/uploadImage/langs/zh.js"&gt;&lt;/mce:script&gt;&lt;mce:script type="text/javascript" mce_src="http://www.cnblogs.com/editor/tiny_mce/plugins/insertMusic/langs/zh.js"&gt;&lt;/mce:script&gt;image: -moz-linear-gradient(top, #BDD738, #7E9516);&#xD;
  background-image: -webkit-gradient(linear, left top, left bottom, from(#BDD738), to(#7E9516));&#xD;
  filter:progid:DXImageTransform.Microsoft.gradient(startColorstr=#BDD738,endColorstr=#7E9516);&#xD;
  -ms-filter: "progid:DXImageTransform.Microsoft.gradient(startColorstr=#BDD738,endColorstr=#7E9516)";&#xD;
}&#xD;
.b_btn{&#xD;
	padding:5px 10px;color: #fff!important;&#xD;
	background:url(http://pic002.cnblogs.com/img/bearstar/201006/2010062420253961.png) repeat-x;&#xD;
	text-decoration: none;font-weight: bold;&#xD;
}&#xD;
.b_btn:hover{&#xD;
	background:url(http://pic002.cnblogs.com/img/bearstar/201006/2010062420254656.png) repeat-x;&#xD;
}&#xD;
.b_box_ie{&#xD;
		text-align:center;width:200px;line-height:60px;&#xD;
		background-color:#DBEAFF;&#xD;
		position:relative;&#xD;
	}&#xD;
	.b_r{width:3px;height:3px;font-size:0;background:url(http://pic002.cnblogs.com/img/bearstar/201006/2010062419324216.gif) no-repeat;position:absolute;}&#xD;
	.r_1{top:0;left:0;}&#xD;
	.r_2{background-position:-3px 0;top:0;right:0;}&#xD;
	.r_3{background-position:0 -3px;left:0;bottom:0;}&#xD;
	.r_4{background-position:-3px -3px;bottom:0;right:0;}&#xD;
--&gt;&lt;/style&gt;&#xD;
&lt;p&gt;UI要求越来越高，界面越做越华丽，给我们开发人员带来的就是使用大量的背景图片，下面介绍一些通过css(不使用图片或少使用图片)来实现一些很常见的效果，&lt;/p&gt;&#xD;
&lt;p&gt;&lt;/p&gt;&#xD;
&lt;p&gt;&lt;strong&gt;圆角效果&lt;/strong&gt;&lt;/p&gt;&#xD;
&lt;p&gt;圆角用的越来越多，因为圆角确实好看，效果如下：&lt;/p&gt;&#xD;
&lt;p&gt;&lt;img src="http://pic002.cnblogs.com/img/bearstar/201006/2010062416362898.jpg" /&gt;&lt;/p&gt;&#xD;
&lt;p&gt;要实现上面的圆角，一般切图是左，右(或上下)各切1个图片做背景，但这样做只适合固定宽度或高度的box,而且如果box背景不一样，图片需要另外切。&lt;/p&gt;&#xD;
&lt;p&gt;现在很多浏览器都支持圆角的css，css3也支持，代码如下：&lt;/p&gt;&#xD;
&lt;pre &gt;.b_box{&#xD;
   		text-align:center;width:200px;line-height:60px;&#xD;
   		border:1px solid #C0C0C0;background-color:#DBEAFF;&#xD;
   		/*firefox*/&#xD;
   		-moz-border-radius: 5px;&#xD;
   		/*css3*/&#xD;
   		border-radius: 5px;&#xD;
   		/*webkit*/&#xD;
  	  -webkit-border-radius: 5px;&#xD;
    }&lt;/pre&gt;&#xD;
&lt;div style="padding-left: 30px;"&gt;效果：&#xD;
&lt;div &gt;CSS 小技巧&lt;/div&gt;&#xD;
&lt;/div&gt;&#xD;
&lt;p&gt;但IE9以下的版本都不支持圆角,所以上面的效果在ie9以下显示还是直角的.&lt;/p&gt;&#xD;
&lt;p&gt;目前我们针对ie9以下的浏览器使用下面的方法实现，切1个透明的圆形图片(这个图片要求圆角内测是透明的，而外侧是不透明的)，用绝对定位来显示4个圆角，这样做的好处是只使用1个图片，即可以实现任何大小，任何背景颜色的box圆角，但缺点就是需要多余的HTML代码，代码如下：&lt;/p&gt;&#xD;
&lt;pre &gt;&amp;lt;style type="text/css"&amp;gt;&#xD;
	.b_box_ie{&#xD;
		text-align:center;width:200px;line-height:60px;&#xD;
		background-color:#DBEAFF;&#xD;
		position:relative;&#xD;
	}&#xD;
	.b_r{width:3px;height:3px;font-size:0;background:url(http://pic002.cnblogs.com/img/bearstar/201006/2010062419324216.gif) no-repeat;position:absolute;}&#xD;
	.r_1{top:0;left:0;}&#xD;
	.r_2{background-position:-3px 0;top:0;right:0;}&#xD;
	.r_3{background-position:0 -3px;left:0;bottom:0;}&#xD;
	.r_4{background-position:-3px -3px;bottom:0;right:0;}&#xD;
&amp;lt;style&amp;gt;&#xD;
&#xD;
&amp;lt;div &amp;gt;&#xD;
	CSS 小技巧&#xD;
	&amp;lt;div &amp;gt;&amp;lt;/div&amp;gt;&#xD;
	&amp;lt;div &amp;gt;&amp;lt;/div&amp;gt;&#xD;
	&amp;lt;div &amp;gt;&amp;lt;/div&amp;gt;&#xD;
	&amp;lt;div &amp;gt;&amp;lt;/div&amp;gt;&#xD;
&amp;lt;/div&amp;gt;&#xD;
&#xD;
&lt;/pre&gt;&#xD;
&lt;p&gt;因我切的图片是gif，而不是png，所以效果不太好看(不像真真的圆角)。效果如下：&lt;/p&gt;&#xD;
&lt;div style="padding-left: 30px;"&gt;&#xD;
&lt;div style="display: inline-block;" &gt;&#xD;
	CSS 小技巧&#xD;
&lt;div &gt;&lt;/div&gt;&#xD;
&lt;div &gt;&lt;/div&gt;&#xD;
&lt;div &gt;&lt;/div&gt;&#xD;
&lt;div &gt;&lt;/div&gt;&#xD;
&lt;/div&gt;&#xD;
&amp;nbsp;&amp;nbsp;&#xD;
&lt;div  style="background-color: #ccc; display: inline-block;"&gt;&#xD;
	CSS 小技巧&#xD;
&lt;div &gt;&lt;/div&gt;&#xD;
&lt;div &gt;&lt;/div&gt;&#xD;
&lt;div &gt;&lt;/div&gt;&#xD;
&lt;div &gt;&lt;/div&gt;&#xD;
&lt;/div&gt;&#xD;
&lt;/div&gt;&#xD;
&lt;p&gt;&lt;/p&gt;&#xD;
&lt;p&gt;&lt;strong&gt;&#xD;
阴影效果&lt;/strong&gt;&lt;/p&gt;&#xD;
&lt;p&gt;大家注意我签名的阴影效果，如果要实现这样的效果，使用图片，切图都很麻烦，让我们看看css如何实现吧，代码：&lt;/p&gt;&#xD;
&lt;pre &gt;.b_shadow{&#xD;
  height:60px;line-height:60px;&#xD;
  width:200px;border:1px solid #C0C0C0;background-color:#DBEAFF;&#xD;
  -webkit-box-shadow: 5px 5px 5px rgba(0, 0, 0, 0.5);&#xD;
  -moz-box-shadow: 5px 5px 5px rgba(0, 0, 0, 0.5);&#xD;
  box-shadow: 5px 5px 5px rgba(0, 0, 0, 0.5);&#xD;
  /*IE6,IE7语法*/&#xD;
  filter:progid:DXImageTransform.Microsoft.dropshadow(OffX=5, OffY=5, Color='gray');&#xD;
  /*IE8语法,可恶的IE，不同的版本还要写的不一样*/&#xD;
  -ms-filter:"progid:DXImageTransform.Microsoft.dropshadow(OffX=5, OffY=5, Color='gray')"&#xD;
} &#xD;
&lt;/pre&gt;&#xD;
&lt;style type="text/css"&gt;&lt;!--&#xD;
&#xD;
--&gt;&lt;/style&gt;&#xD;
&lt;div style="padding-left: 30px;"&gt;结合圆角，实现效果如下：&#xD;
&lt;div&gt;&#xD;
&lt;div &gt;&#xD;
      CSS 小技巧&#xD;
   &lt;/div&gt;&#xD;
&lt;/div&gt;&#xD;
&lt;/div&gt;&#xD;
&lt;p&gt;&lt;/p&gt;&#xD;
&lt;p&gt;&lt;span style="color: #0000ff;"&gt;注：针对IE的filter,再测试过程中发现必须加height和background-color,如果不设置height，则无阴影效果，如果不设置背景色，则阴影效果不是作用在box &amp;nbsp; &amp;nbsp; 上，而是在文字上，原因不是很清楚，有兴趣的同学可以自己测下。&lt;/span&gt;&lt;/p&gt;&#xD;
&lt;p&gt;&lt;strong&gt;&lt;br /&gt;&lt;/strong&gt;&lt;/p&gt;&#xD;
&lt;p&gt;&lt;strong&gt;渐变效果：&lt;/strong&gt;&lt;/p&gt;&#xD;
&lt;p&gt;这个效果也应该也是用的最多的，这次先上效果：&lt;/p&gt;&#xD;
&lt;div style="padding-left: 30px;"&gt;&#xD;
&lt;div &gt;&#xD;
  CSS 小技巧&#xD;
&lt;/div&gt;&#xD;
&lt;/div&gt;&#xD;
&lt;p&gt;代码：&lt;/p&gt;&#xD;
&lt;pre &gt;.gradients{&#xD;
	text-align:center;width:200px;line-height:60px;&#xD;
	background-image: -moz-linear-gradient(top, #BDD738, #7E9516);&#xD;
	background-image: -webkit-gradient(linear, left top, left bottom, from(#BDD738), to(#7E9516));&#xD;
	filter:progid:DXImageTransform.Microsoft.gradient(startColorstr=#BDD738,endColorstr=#7E9516);&#xD;
	-ms-filter: "progid:DXImageTransform.Microsoft.gradient(startColorstr=#BDD738,endColorstr=#7E9516)";&#xD;
}&#xD;
&lt;/pre&gt;&#xD;
&lt;p&gt;&lt;/p&gt;&#xD;
&lt;p&gt;&lt;strong&gt;按钮发光效果&lt;/strong&gt;：&lt;/p&gt;&#xD;
&lt;p&gt;这个效果在我签名中的评论按钮实现了(我签名的效果没有考虑IE6,IE7)，大家看到那几个按钮，都有些发光效果，而且鼠标移上去也有效果，可能有人看到以为我用了很多图片，其实只用了2个png图片，1个图片是上半部分完全透明，下半部分半透明，另1个图片是上半部分半透明，下半部分完全透明。用这2个图片+背景色就可以实现所有按钮的发光效果。因为我的签名中使用data:image/png;base64嵌入的图片，所以不支持IE6,IE7。&lt;/p&gt;&#xD;
&lt;p&gt;DEMO效果(该效果在IE6下看不出来，是因为没有对PNG进行处理)：&lt;/p&gt;&#xD;
&lt;div style="padding-left: 30px;"&gt;&#xD;
   &lt;a style="background-color: #2daebf;" href="javascript:void(0);" &gt;精彩推荐&lt;/a&gt;&amp;nbsp;&amp;nbsp;&lt;a style="background-color: #e33100;" href="javascript:void(0);" &gt;水平一般&lt;/a&gt;&#xD;
&lt;/div&gt;&#xD;
&lt;p&gt;&lt;/p&gt;&#xD;
&lt;p&gt;代码：&lt;/p&gt;&#xD;
&lt;pre &gt;&amp;lt;style&amp;gt;&#xD;
.b_btn{&#xD;
	padding:5px 10px;color: #fff;&#xD;
	background:url(http://pic002.cnblogs.com/img/bearstar/201006/2010062420253961.png) repeat-x;&#xD;
	text-decoration: none;font-weight: bold;&#xD;
}&#xD;
.b_btn:hover{&#xD;
	background:url(http://pic002.cnblogs.com/img/bearstar/201006/2010062420254656.png) repeat-x;&#xD;
}&#xD;
&amp;lt;/style&amp;gt;&#xD;
&amp;lt;a  href="javascript:void(0);" style="background-color:#2daebf;"&amp;gt;精彩推荐&amp;lt;/a&amp;gt;&amp;nbsp;&amp;nbsp;&#xD;
&amp;lt;a  href="javascript:void(0);" style="background-color:#e33100;"&amp;gt;水平一般&amp;lt;/a&amp;gt;&#xD;
&lt;/pre&gt;&#xD;
&lt;p&gt;&lt;/p&gt;&#xD;
&lt;p&gt;&lt;/p&gt;&#xD;
&lt;p&gt;&lt;span style="color: #ff0000;"&gt;PS：本文中只是做一些简单的介绍，每种效果都没做很详细的说明，对于具体方法的使用，请大家自己查查资料。&lt;/span&gt;&lt;/p&gt;&#xD;
&lt;p&gt;&lt;span style="color: #ff0000;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/p&gt;&#xD;
&lt;p&gt;&lt;span style="color: #ff0000;"&gt;评论更新：本来设置个快捷评论，没想到很多朋友都随便点着玩，虽然赚去了很多评论数，但大部分都是无意义的评论，而不是技术交流的评论，所以决定把快捷评论关闭掉，并以后再也不启用该功能了。希望大家都用心交流。&lt;/span&gt;&lt;/p&gt;&lt;img src="http://www.cnblogs.com/BearsTaR/aggbug/1764540.html?type=1" width="1" height="1" alt=""/&gt;&lt;p&gt;&lt;a href="http://www.cnblogs.com/BearsTaR/archive/2010/06/25/css_tip_round_gradients_shadow.html" target="_blank"&gt;本文链接&lt;/a&gt;&lt;/p&gt;</content></entry></feed>
