<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>小李刀刀博客 &#187; 所谓技术</title>
	<atom:link href="http://wukangrui.com/category/tech/feed" rel="self" type="application/rss+xml" />
	<link>http://wukangrui.com</link>
	<description>独立 自由 诚信 宽容 责任 平常心</description>
	<lastBuildDate>Mon, 21 Dec 2009 15:05:01 +0000</lastBuildDate>
	<generator>http://wordpress.org/?v=2.9.2</generator>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
			<item>
		<title>web开发从头说起：理解css盒模型</title>
		<link>http://wukangrui.com/2009/12/21/web-developer-understand-css-box-model.html</link>
		<comments>http://wukangrui.com/2009/12/21/web-developer-understand-css-box-model.html#comments</comments>
		<pubDate>Mon, 21 Dec 2009 14:58:41 +0000</pubDate>
		<dc:creator>小李刀刀</dc:creator>
				<category><![CDATA[所谓技术]]></category>
		<category><![CDATA[CSS]]></category>
		<category><![CDATA[javascript]]></category>
		<category><![CDATA[web标准]]></category>
		<category><![CDATA[XHTML]]></category>
		<category><![CDATA[网页]]></category>

		<guid isPermaLink="false">http://wukangrui.com/2009/12/21/web-developer-understand-css-box-model.html</guid>
		<description><![CDATA[在布局的时候，实际上主要是借助元素的宽、高、定位、浮动、边距、边框、间距、背景颜色、背景图片的组合来实现的。而所有这些，都要基于对css盒模型的理解。网上对盒模型的论述很多，我这里想从实用的角度来谈谈。]]></description>
			<content:encoded><![CDATA[<p>在掌握了丰富而强大的<a href="http://wukangrui.com/2009/12/16/web-developer-about-css-selector.html" rel="prev">css选择符</a>之后，就具备了将css样式根据需要应用到网页中任何元素的能力。能够应用规则了，接下来就需要熟练掌握规则的制定方法——什么样的属性组合能够实现什么样的效果。一般的颜色、字体、字号、行高等的设置比较容易掌握，而初学者在应用css的时候，主要头疼的还是如何用css实现复杂的网页布局，从两栏布局、三栏布局，到表单设计等。在布局的时候，实际上主要是借助元素的宽、高、定位、浮动、边距、边框、间距、背景颜色、背景图片的组合来实现的。而所有这些，都要基于对css盒模型的理解。网上对盒模型的论述很多（推荐阅读《<a href="http://www.blueidea.com/tech/web/2007/4545.asp" rel="reference" target="_blank">彻底理解css盒子模式</a>》），我这里想从实用的角度来谈谈。</p>
<p> <span id="more-891"></span>
<p>网上有两张著名的图片，分别以2D和3D的形式描述css盒模型：</p>
<p><img style="border-right-width: 0px; display: block; float: none; border-top-width: 0px; border-bottom-width: 0px; margin-left: auto; border-left-width: 0px; margin-right: auto" title="图片1" border="0" alt="图片1" src="http://file.wukangrui.com/blog/webcss_13001/1_thumb.gif" width="460" height="262" /></p>
<p align="center"><a href="http://file.wukangrui.com/blog/webcss_13001/cssbox3d.gif"><img style="border-bottom: 0px; border-left: 0px; display: inline; border-top: 0px; border-right: 0px" title="cssbox3d" border="0" alt="cssbox3d" src="http://file.wukangrui.com/blog/webcss_13001/cssbox3d_thumb.gif" width="478" height="383" /></a> </p>
<p>通过这两张图，一般来说对于margin、border、background-color、background-image、padding以及width和height有较直观的了解了。</p>
<p>更为重要的是要了解以下几点：</p>
<ol>
<li>对于所有以“块(block)”方式呈现的元素都具备这个模型的特性，而不只是div；</li>
<li>margin是以所指定元素的父级元素（常称为“容器”）为基准的； </li>
<li>一个元素（通常为块元素）在页面中所占的位置尺寸为：宽度= <strong>width + padding-left + padding-right + border-left-width + border-right-width + margin-left + margin-right</strong>；高度 = <strong>height + padding-top + padding-bottom + border-top-width + border-bottom-width + margin-top + margin-bottom</strong>；（部分浏览器有差异，以后再具体讨论）； </li>
<li>background-color将填满border内部的全部范围；background-image默认以图片左上角对齐border内部左上角点，然后完整显示整个图片（超出部分不予显示），如果图片尺寸不足铺满整个范围，图片默认重复自己直至铺满或超出范围； </li>
<li>background-image将叠加到background-color之上；通过指定图片的对齐方式，可以改变background-image的位置； </li>
</ol>
<p>通过以上这些规则的组合，就能在有限的元素组合下，实现各种修饰性效果。一个简单的例子如下：</p>
<p>将一个15像素高，颜色为#c00的纯色图片<a href="http://file.wukangrui.com/blog/webcss_13001/c00.gif"><img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="c00" border="0" alt="c00" src="http://file.wukangrui.com/blog/webcss_13001/c00_thumb.gif" width="14" height="19" /></a> 放入一个高度为30像素，背景色为#f00的块元素，设定图片在Y轴方向不平铺，在x轴方向平铺。结果得到一个类似下图的效果：</p>
<p><a href="http://file.wukangrui.com/blog/webcss_13001/c00f33.gif"><img style="border-right-width: 0px; display: block; float: none; border-top-width: 0px; border-bottom-width: 0px; margin-left: auto; border-left-width: 0px; margin-right: auto" title="c00f33" border="0" alt="c00f33" src="http://file.wukangrui.com/blog/webcss_13001/c00f33_thumb.gif" width="104" height="34" /></a> 这是简单的由背景色与背景图组合实现的效果。根据这样的原理，当我们的文档结构有两层时，例如：&lt;a href=”#&quot;&gt;&lt;span&gt;文字&lt;/span&gt;&lt;/a&gt;，我们可以通过由a元素的背景颜色图片和span元素的背景颜色图片组合，从而得到较为复杂的效果，例如：</p>
<p align="center"><a href="http://file.wukangrui.com/blog/webcss_13001/button.gif"><img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="button" border="0" alt="button" src="http://file.wukangrui.com/blog/webcss_13001/button_thumb.gif" width="204" height="40" /></a>&#160;</p>
<p align="left">这个按钮效果，用纯图片很容易实现，但是用图片实现就会面临一个问题：不通用。如果要通用，应该把文字和背景图片分离开来，同时，由于文字有多有少，因此按钮的宽度要是可变的，但是按钮并不是从左到右完全一致的背景，于是不能使用一张图片进行横向平铺，按照以前的做法，可能会使用一个一行三列的表格，第一个单元格放入左侧的图片，中间的单元格放文字和平铺的背景，右边的单元格放右侧的图片。这种思维传递到了“div+css”布局思维模式下，于是就出现了这样的结构：</p>
<pre class="code"><span style="color: blue">&lt;</span><span style="color: #a31515">div </span><span style="color: red">class</span><span style="color: blue">=”button”&gt;&lt;</span><span style="color: #a31515">div </span><span style="color: red">class</span><span style="color: blue">=”left”&gt;&lt;/</span><span style="color: #a31515">div</span><span style="color: blue">&gt;&lt;</span><span style="color: #a31515">div </span><span style="color: red">class</span><span style="color: blue">=”center”&gt;&lt;/</span><span style="color: #a31515">div</span><span style="color: blue">&gt;&lt;</span><span style="color: #a31515">div </span><span style="color: red">class</span><span style="color: blue">=”right”&gt;&lt;/</span><span style="color: #a31515">div</span><span style="color: blue">&gt;</span></pre>
<p>这个结构的出现，就是为了实现自适应宽度的按钮，今天依然存在。实际上，使用上面的a+span的基本结构，就能实现这个效果。将中间平铺部分和左侧或右侧的边缘图片组合在一起，重复部分做得宽一些，作为a的背景图片，把另一侧的图片作为span的背景图片覆盖到a的背景图片上。组合起来看上去就成为一个整体。代码如下：</p>
<p>效果如下：</p>
<p align="center"><a href="http://file.wukangrui.com/blog/webcss_13001/image.png"><img style="border-bottom: 0px; border-left: 0px; display: inline; border-top: 0px; border-right: 0px" title="image" border="0" alt="image" src="http://file.wukangrui.com/blog/webcss_13001/image_thumb.png" width="232" height="60" /></a> </p>
<pre class="code"><span style="color: #a31515">a </span>{<span style="color: red">display</span>:<span style="color: blue">block</span>;<span style="color: red">width</span>:<span style="color: blue">200px</span>;<span style="color: red">height</span>:<span style="color: blue">36px</span>;<span style="color: red">background</span>:<span style="color: blue">url(button.gif) no-repeat right bottom</span>;}
<span style="color: #a31515">a span </span>{<span style="color: red">display</span>:<span style="color: blue">block</span>;<span style="color: red">line-height</span>:<span style="color: blue">36px</span>;<span style="color: red">background</span>:<span style="color: blue">url(button.gif) no-repeat left top</span>;<span style="color: red">color</span>:<span style="color: blue">#fff</span>;<span style="color: red">text-decoration</span>:<span style="color: blue">none</span>;<span style="color: red">text-align</span>:<span style="color: blue">center</span>;}</pre>
<p><a href="http://11011.net/software/vspaste"></a></p>
<p>用到的背景图片如下：</p>
<p align="center"><a href="http://file.wukangrui.com/blog/webcss_13001/button_3.gif"><img style="border-bottom: 0px; border-left: 0px; display: inline; border-top: 0px; border-right: 0px" title="button" border="0" alt="button" src="http://file.wukangrui.com/blog/webcss_13001/button_thumb_3.gif" width="200" height="72" /></a>&#160;</p>
<p align="left">这个例子很简单，但是需要对“背景组合”有足够的理解，能够想到应用。而要想到如此应用，首先是对于盒模型中的“background”足够的理解。否则，就只会想到三个div（或者其它元素组合方式），但是由于左右两个结构完全一样，为了区分它们，只好使用class或者id来标记。这就是我在<a href="http://wukangrui.com/2009/12/16/web-developer-about-css-selector.html" rel="prev">上一篇</a>中所提到的不必要的class和id。</p>
<p align="left">除了利用display:block让行内元素改变为块元素从而使用盒模型特征外，在浮动的时候，也经常会用到盒模型的一些特征。再举个例子：</p>
<p align="left">使用浮动布局的时候，并列呈现的浮动元素中的第一个如果设置与浮动方向相同的margin，则IE 6下会出现margin加倍的bug（这就是著名的IE6浮动边距加倍bug）。为了解决这个问题，很多人喜欢给一组浮动元素的第一个加上class=”first”，从而可以对这个元素单独应用样式。或者对这一组浮动元素加上display:inline的属性以解决这个bug。</p>
<p align="left">上述两种方式都是没有使用hack选择符或者类似“_margin”这样的非标准属性的很好的hack方式。但是，如果不是非用margin不可，只要使用padding来代替margin，就能解决这个问题。或者采用与浮动方向相反的margin也可以。不需要任何额外的hack。这也是在充分理解盒模型的基础上，由于对这个bug的了解，从而在实现样式的时候直接避开，而不是出现了之后再用额外手段去hack。</p>
<p align="left">对盒模型的理解，除了margin、border、padding、width、height五大属性以及两种背景的应用之外，还要了解父级元素与子元素之间的关系。比如父元素没有设置尺寸，而对子元素设置margin-top属性，在某些浏览器下，本来是想针对父元素的边缘设置margin，结果margin被设置到了父元素之外，造成父元素与外部元素的margin。这种情况，将子元素的margin改成父元素的padding，也可以在不改变表现的情况下实现相同的效果。</p>
<p align="left">要想通过对盒模型特征的充分应用来减少css中的hack使用，或者以更简洁的代码实现更复杂的效果，需要对盒模型不断地尝试和总结。这是《css权威指南》之类的经典巨著也没法教给你的。</p>
<p align="left">只有越理解盒模型，才能越好地利用浮动和定位来实现复杂、精确的布局。关于浮动的问题，下一次我们再一起来了解一下。</p>
<h3  class="related_post_title">相关日志</h3><ul class="related_post"><li>2009-12-16 -- <a href="http://wukangrui.com/2009/12/16/web-developer-about-css-selector.html" title="前台开发从头说起：谈谈CSS选择符">前台开发从头说起：谈谈CSS选择符</a></li><li>2009-12-15 -- <a href="http://wukangrui.com/2009/12/15/web-developer-from-web-standard.html" title="前台开发从头说起：关于web标准化">前台开发从头说起：关于web标准化</a></li><li>2009-06-22 -- <a href="http://wukangrui.com/2009/06/22/whatever-hover-pseudo-class-without-javascript.html" title="Whatever:hover &#8211; 无需javascript让IE支持丰富伪类">Whatever:hover &#8211; 无需javascript让IE支持丰富伪类</a></li><li>2009-04-16 -- <a href="http://wukangrui.com/2009/04/16/best-practices-of-css-dropdown-menu.html" title="来自微软站点的纯CSS下拉菜单">来自微软站点的纯CSS下拉菜单</a></li><li>2009-04-13 -- <a href="http://wukangrui.com/2009/04/13/portable-interchangeable-jquery-based-tabs.html" title="简单、通用的JQuery Tab实现">简单、通用的JQuery Tab实现</a></li><li>2006-04-04 -- <a href="http://wukangrui.com/2006/04/04/dynamic-mouse-event-of-image-transparency.html" title="动态实现指定图片半透明及鼠标事件">动态实现指定图片半透明及鼠标事件</a></li><li>2006-03-28 -- <a href="http://wukangrui.com/2006/03/28/simulate-window-in-center-with-css.html" title="CSS:模拟Windows窗口及DIV居中">CSS:模拟Windows窗口及DIV居中</a></li><li>2005-12-12 -- <a href="http://wukangrui.com/2005/12/12/action-of-refactor-page-with-css.html" title="实践：用Div+CSS重构网页">实践：用Div+CSS重构网页</a></li><li>2005-11-29 -- <a href="http://wukangrui.com/2005/11/29/css-learn-in-action.html" title="CSS学习之综合运用">CSS学习之综合运用</a></li><li>2009-04-09 -- <a href="http://wukangrui.com/2009/04/09/aspnetmvc-hands-on-labs-create-application.html" title="[翻译]ASP.NET MVC动手实验1-2：创建ASP.NET MVC应用">[翻译]ASP.NET MVC动手实验1-2：创建ASP.NET MVC应用</a></li></ul>]]></content:encoded>
			<wfw:commentRss>http://wukangrui.com/2009/12/21/web-developer-understand-css-box-model.html/feed</wfw:commentRss>
		<slash:comments>3</slash:comments>
		</item>
		<item>
		<title>前台开发从头说起：谈谈CSS选择符</title>
		<link>http://wukangrui.com/2009/12/16/web-developer-about-css-selector.html</link>
		<comments>http://wukangrui.com/2009/12/16/web-developer-about-css-selector.html#comments</comments>
		<pubDate>Wed, 16 Dec 2009 06:14:03 +0000</pubDate>
		<dc:creator>小李刀刀</dc:creator>
				<category><![CDATA[所谓技术]]></category>
		<category><![CDATA[CSS]]></category>
		<category><![CDATA[javascript]]></category>
		<category><![CDATA[web标准]]></category>
		<category><![CDATA[XHTML]]></category>
		<category><![CDATA[网页]]></category>

		<guid isPermaLink="false">http://wukangrui.com/2009/12/16/web-developer-about-css-selector.html</guid>
		<description><![CDATA[去除了不必要的表现元素和属性（font、center、align、height）之后，又去除了不必要的id、class、onclick、onmouseover之类的样式和行为属性，我们的网页源代码尺寸越来越小，抓一个页面下来，少量必要的结构元素之外，剩下的全是链接和内容，这样的网站，搜索引擎能不喜欢吗？]]></description>
			<content:encoded><![CDATA[<p>以前我接受了网上不少博文的说法，一直认为学习css的三大最重要问题是：盒模型、定位、浮动。因为这三块的内容决定了css布局的能力。但是通过<a href="http://wukangrui.com/2009/12/15/web-developer-from-web-standard.html" rel="prev">上一篇</a>日志的分析，xhtml要实现和css的解耦，就要尽量不依赖于css（或者说不要纯粹为了给css预留接口而添加<strong>不必要</strong>的class和id），那么，在用css布局之前，其实就有一个更紧迫的任务摆在我们的面前——如何将css规则准确应用到目标元素。于是，css选择符的地位在这个前提下就空前的提高了。所以，在开始学习盒模型、浮动、定位之前，有必要回顾一下选择符。</p>
</p>
</p>
<p> <span id="more-888"></span>
</p>
<p>一般稍微接触过css的网页设计人员，都会很快地学会三种css选择符：</p>
<ul>
<li>元素选择符（例如：body 、a 、li ） </li>
<li>ID选择符（例如：#head、#body、#foot） </li>
<li>类选择符（例如：.red、.item、.content） </li>
</ul>
<p>更进一步之后，开始了解到一些进阶的选择符：</p>
<ul>
<li>后代选择符（例如 #head .menu、#foot #copyright） </li>
<li>伪类选择符（例如 a:hover、a:link） </li>
</ul>
<p>以及由这些选择符组合起来形成的综合选择符。实际上css还支持一些更丰富的选择符。但是能够被浏览器广泛支持的其实主要就是上面这几种，其它的选择符在css中往往用来区别处理不同的浏览器，或者用在jQuery一类的框架中。本文就不提了。有兴趣的可以自己在网上查一下，像属性选择符（input[type=’password’]、input[type=’radio’]）、直接后代选择符（body &gt; div、 #head &gt; ul）等。</p>
<p>实际上，有了上面列出的五种主要的选择符，通过对它们的组合，已经能够满足我们绝大部分时候的要求了，这也就意味着，相同结构下的元素，父级元素或者祖先元素只要有一点点区别，我们就能够在不借助id或者class的情况下直接访问到。例如：</p>
<pre class="code"><span style="color: blue">&lt;</span><span style="color: #a31515">ul</span><span style="color: blue">&gt;
  &lt;</span><span style="color: #a31515">li</span><span style="color: blue">&gt;&lt;</span><span style="color: #a31515">a </span><span style="color: red">href</span><span style="color: blue">=&quot;#&quot;&gt;</span>菜单1<span style="color: blue">&lt;/</span><span style="color: #a31515">a</span><span style="color: blue">&gt;
    &lt;</span><span style="color: #a31515">ul</span><span style="color: blue">&gt;
      &lt;</span><span style="color: #a31515">li</span><span style="color: blue">&gt;&lt;</span><span style="color: #a31515">a </span><span style="color: red">href</span><span style="color: blue">=&quot;#&quot;&gt;</span>菜单1-1<span style="color: blue">&lt;/</span><span style="color: #a31515">a</span><span style="color: blue">&gt;&lt;/</span><span style="color: #a31515">li</span><span style="color: blue">&gt;
      &lt;</span><span style="color: #a31515">li</span><span style="color: blue">&gt;&lt;</span><span style="color: #a31515">a </span><span style="color: red">href</span><span style="color: blue">=&quot;#&quot;&gt;</span>菜单1-2<span style="color: blue">&lt;/</span><span style="color: #a31515">a</span><span style="color: blue">&gt;&lt;/</span><span style="color: #a31515">li</span><span style="color: blue">&gt;
      &lt;</span><span style="color: #a31515">li</span><span style="color: blue">&gt;&lt;</span><span style="color: #a31515">a </span><span style="color: red">href</span><span style="color: blue">=&quot;#&quot;&gt;</span>菜单1-3<span style="color: blue">&lt;/</span><span style="color: #a31515">a</span><span style="color: blue">&gt;&lt;/</span><span style="color: #a31515">li</span><span style="color: blue">&gt;
    &lt;/</span><span style="color: #a31515">ul</span><span style="color: blue">&gt;
  &lt;/</span><span style="color: #a31515">li</span><span style="color: blue">&gt;
  &lt;</span><span style="color: #a31515">li</span><span style="color: blue">&gt;&lt;</span><span style="color: #a31515">a </span><span style="color: red">href</span><span style="color: blue">=&quot;#&quot;&gt;</span>菜单2<span style="color: blue">&lt;/</span><span style="color: #a31515">a</span><span style="color: blue">&gt;
    &lt;</span><span style="color: #a31515">ul</span><span style="color: blue">&gt;
      &lt;</span><span style="color: #a31515">li</span><span style="color: blue">&gt;&lt;</span><span style="color: #a31515">a </span><span style="color: red">href</span><span style="color: blue">=&quot;#&quot;&gt;</span>菜单2-1<span style="color: blue">&lt;/</span><span style="color: #a31515">a</span><span style="color: blue">&gt;&lt;/</span><span style="color: #a31515">li</span><span style="color: blue">&gt;
      &lt;</span><span style="color: #a31515">li</span><span style="color: blue">&gt;&lt;</span><span style="color: #a31515">a </span><span style="color: red">href</span><span style="color: blue">=&quot;#&quot;&gt;</span>菜单2-2<span style="color: blue">&lt;/</span><span style="color: #a31515">a</span><span style="color: blue">&gt;&lt;/</span><span style="color: #a31515">li</span><span style="color: blue">&gt;
      &lt;</span><span style="color: #a31515">li</span><span style="color: blue">&gt;&lt;</span><span style="color: #a31515">a </span><span style="color: red">href</span><span style="color: blue">=&quot;#&quot;&gt;</span>菜单2-3<span style="color: blue">&lt;/</span><span style="color: #a31515">a</span><span style="color: blue">&gt;&lt;/</span><span style="color: #a31515">li</span><span style="color: blue">&gt;
    &lt;/</span><span style="color: #a31515">ul</span><span style="color: blue">&gt;
  &lt;/</span><span style="color: #a31515">li</span><span style="color: blue">&gt;
&lt;/</span><span style="color: #a31515">ul</span><span style="color: blue">&gt;</span></pre>
<p>这个结构是我在<a href="http://wukangrui.com/2009/04/16/best-practices-of-css-dropdown-menu.html" rel="prev">《来自微软的纯css下拉菜单》</a>一文中用到的下拉菜单结构。在那个示例中，没有使用任何的class或者id，但是我们通过不同优先级的元素+后台选择符，对结构中的不同层次的ul、li、a实现了精确定位。如下面的代码：</p>
<pre class="code"><span style="color: #a31515">ul </span>{}
<span style="color: #a31515">li </span>{}
<span style="color: #a31515">ul ul </span>{}
<span style="color: #a31515">ul ul li </span>{}
<span style="color: #a31515">li a </span>{}
<span style="color: #a31515">ul li a </span>{}
<span style="color: #a31515">ul li:hover ul </span>{}</pre>
<p><a href="http://11011.net/software/vspaste"></a></p>
<p>那么，在实际开发中，为什么很多网页设计人员还是离不开多如牛毛的ID和class呢（我要声明一下，我从来没有说完全抛弃id和class，我的观点是他们应该尽量少，并且由文档结构决定而不是由css需要决定）？我觉得有三方面的原因：</p>
<p>第一、xhtml文档结构不合理，通过元素不能体现文档的层次结构。满篇都是div。没有有效利用Hx系列标签和ul、ol、dl等不同含义的列表标签、没有有效利用p、quote、pre等标签。xhtml为我们提供了丰富的标签元素，但是如果我们只会用div，那还不如人家用table来布局的。至少他的table在一定程度上也是文档结构的体现，而满篇嵌套的div，文档结构完全没体现。</p>
<p>第二、css选择符掌握得不够，不善于借助文档结构层次上的细微区别，用不同的组合选择符来区别相似但其实不同的元素。例如上面的下拉菜单结构，有的人就非要用“menu”和“submenu”来区别。</p>
<p>第三、css选择符的优先级不清楚。css是支持继承和覆盖的，什么时候继承，什么时候覆盖。两条规则都对相同元素做出了样式规定而且样式规定重复的情况下，哪一条规则会被应用呢？这些问题不清楚，就没办法充分利用优先级实现规则的覆盖。于是只好每个要应用样式的元素都加上id或者class。关于css选择符的优先级，网上也有很多文章，我就不赘述了。</p>
<p>所以说，如果感觉离不了class，离不了id，那只能说明两个问题——xhtml结构不合理或者css掌握得还不够。我<a href="http://wukangrui.com/2009/12/15/web-developer-from-web-standard.html" rel="prev">上一篇</a>博文发了以后，有位朋友评论说我没做过前台开发。因为没有class和id，就不能实现css和javascript的分离。实际上，只要是长期深入学习css和javascript的朋友应该都清楚：在结构有差异的情况下，用css选择符就能精确定位某个元素；在结构完全相同的情况下，借助javascript和DOM，同样可以精确定位某个元素。</p>
<p>仍然以上面的下拉菜单列表为例。首先使用 ul a 对父级菜单的链接应用样式，然后用ul ul a就可以精确定位到次级菜单的链接，应用新的样式，对ul a的定义进行覆盖。那么，如果是要精确定位到第二级菜单的第二个元素呢？由于css3的选择符目前还没被广泛支持，而结构又没有差异，不借助javascript有困难了。但是借助于javascript，非常轻松，比如在jQuery中，我们可以用 $(&quot;ul ul:nth(2) li:nth(2)”) 或者 $(&quot;ul ul”).eq(1).find(“li”).eq(1) 都能得到第二个子菜单的第二个菜单元素。</p>
<p>css和javascript能够自己精确找到网页中的任何一个元素，那么网页自然就不用自己标识自己的每个元素。少了这层负担，我们在设计网页文档结构的时候，自然就可以抛弃一切后顾之忧，那么，xhtml中和结构无关的id和class，还有什么必要存在呢？</p>
<p>去除了不必要的表现元素和属性（font、center、align、height）之后，又去除了不必要的id、class、onclick、onmouseover之类的样式和行为属性，我们的网页源代码尺寸越来越小，抓一个页面下来，少量必要的结构元素之外，剩下的全是链接和内容，这样的网站，搜索引擎能不喜欢吗？</p>
<p>没有了后顾之忧，认清了努力方向，那么下一次我们就来谈谈css的盒模型。</p>
<h3  class="related_post_title">相关日志</h3><ul class="related_post"><li>2009-12-21 -- <a href="http://wukangrui.com/2009/12/21/web-developer-understand-css-box-model.html" title="web开发从头说起：理解css盒模型">web开发从头说起：理解css盒模型</a></li><li>2009-12-15 -- <a href="http://wukangrui.com/2009/12/15/web-developer-from-web-standard.html" title="前台开发从头说起：关于web标准化">前台开发从头说起：关于web标准化</a></li><li>2009-06-22 -- <a href="http://wukangrui.com/2009/06/22/whatever-hover-pseudo-class-without-javascript.html" title="Whatever:hover &#8211; 无需javascript让IE支持丰富伪类">Whatever:hover &#8211; 无需javascript让IE支持丰富伪类</a></li><li>2009-04-16 -- <a href="http://wukangrui.com/2009/04/16/best-practices-of-css-dropdown-menu.html" title="来自微软站点的纯CSS下拉菜单">来自微软站点的纯CSS下拉菜单</a></li><li>2009-04-13 -- <a href="http://wukangrui.com/2009/04/13/portable-interchangeable-jquery-based-tabs.html" title="简单、通用的JQuery Tab实现">简单、通用的JQuery Tab实现</a></li><li>2006-04-04 -- <a href="http://wukangrui.com/2006/04/04/dynamic-mouse-event-of-image-transparency.html" title="动态实现指定图片半透明及鼠标事件">动态实现指定图片半透明及鼠标事件</a></li><li>2006-03-28 -- <a href="http://wukangrui.com/2006/03/28/simulate-window-in-center-with-css.html" title="CSS:模拟Windows窗口及DIV居中">CSS:模拟Windows窗口及DIV居中</a></li><li>2005-12-12 -- <a href="http://wukangrui.com/2005/12/12/action-of-refactor-page-with-css.html" title="实践：用Div+CSS重构网页">实践：用Div+CSS重构网页</a></li><li>2005-11-29 -- <a href="http://wukangrui.com/2005/11/29/css-learn-in-action.html" title="CSS学习之综合运用">CSS学习之综合运用</a></li><li>2009-04-09 -- <a href="http://wukangrui.com/2009/04/09/aspnetmvc-hands-on-labs-create-application.html" title="[翻译]ASP.NET MVC动手实验1-2：创建ASP.NET MVC应用">[翻译]ASP.NET MVC动手实验1-2：创建ASP.NET MVC应用</a></li></ul>]]></content:encoded>
			<wfw:commentRss>http://wukangrui.com/2009/12/16/web-developer-about-css-selector.html/feed</wfw:commentRss>
		<slash:comments>4</slash:comments>
		</item>
		<item>
		<title>前台开发从头说起：关于web标准化</title>
		<link>http://wukangrui.com/2009/12/15/web-developer-from-web-standard.html</link>
		<comments>http://wukangrui.com/2009/12/15/web-developer-from-web-standard.html#comments</comments>
		<pubDate>Mon, 14 Dec 2009 17:00:43 +0000</pubDate>
		<dc:creator>小李刀刀</dc:creator>
				<category><![CDATA[所谓技术]]></category>
		<category><![CDATA[CSS]]></category>
		<category><![CDATA[javascript]]></category>
		<category><![CDATA[web标准]]></category>
		<category><![CDATA[XHTML]]></category>
		<category><![CDATA[网页]]></category>

		<guid isPermaLink="false">http://wukangrui.com/2009/12/15/web-developer-from-web-standard.html</guid>
		<description><![CDATA[虽然CSS在表现方面天生具有很多优势，但是如果不是web标准化的盛行，估计CSS不会达到今天这样的热门。所以要说CSS，肯定要从web标准化说起。实际上，对CSS的理解越深，才能越好地理解和使用CSS。]]></description>
			<content:encoded><![CDATA[<p>虽然CSS在表现方面天生具有很多优势，但是如果不是web标准化的盛行，估计CSS不会达到今天这样的热门。所以要说CSS，肯定要从web标准化说起。实际上，对CSS的理解越深，才能越好地理解和使用CSS。</p>
<p>很多人对于web标准化的理解就是“DIV+CSS”，或者“IE、FF、Chrome、Opera、Safari测试无错”，或者就是“通过w3c校验”。实际上，这些都只是web标准化以后附带的一些好处或者说一些表现。web标准化的精髓并不是为了抛弃表格，或者浏览器兼容，或者通过w3c校验。有时候，标准化了的网页未必一定能达到上述这些特征。</p>
<p> <span id="more-887"></span>
</p>
<p>web标准化的精髓或者说本质到底是什么呢？其实很简单，就是“结构、表现、行为分离”。这句话看起来简单，但是真的实现起来，就不那么容易了。分离，分离到什么程度算是标准？分离的目的是什么？举例来说吧。</p>
<p>既然要分离，那么耦合度当然是越低越好。</p>
<p>以样式为例。我们可以把所有的样式都放到外部CSS文件中，那么，CSS规则如何影响你的页面元素呢？有时候用到ID，有时候用到class。如果你的页面充满了ID和class，那么实际上分离得就不怎么彻底，因为你的页面上仍然有大量的ID或者class实际上是为了样式表现而存在的，他们并不是文档结构本身的要求。所以现在有“class hell”的说法。就是为了完全由外部css对页面实现精确控制，而在页面文档中加入大量，甚至过多的class。</p>
<p>再以行为为例。很多时候我们需要和用户交互，于是要给页面上的元素添加“onclick”，“onchange”，“onmouseover”等属性，这些属性编写在页面文档中，依赖于外部javascript。一旦外部的javascript被拿走，页面就出现执行脚本错误，甚至完全不能正常阅读。在这种情况下，javascript实际上和xhtml就没有能够解除耦合。</p>
<p>实际上，由于只有xhtml、css、javascript三者存在，我们不可能在网页开发中引入“面向接口编程”之类的设计模式。那么，我们所谓的彻底分离，其实从三者分离的最根本目的来说，就是要实现xhtml对另外两者不依赖。即使去除了所有的css和javascript，xhtml本身也能很好地完成自己的职责——文档结构。而css和javascript呢？依赖于xhtml是必然的。</p>
<p>如此一来，如何解除耦合呢？其实答案就呼之欲出了。那就是尽量避免和文档结构无关的元素嵌套，尽量去除class和事件属性。比如：</p>
<pre class="code"><span style="color: blue">&lt;</span><span style="color: #a31515">ul</span><span style="color: blue">&gt;
    &lt;</span><span style="color: #a31515">li</span><span style="color: blue">&gt;&lt;</span><span style="color: #a31515">a </span><span style="color: red">href</span><span style="color: blue">=&quot;#&quot;&gt;</span>国内新闻<span style="color: blue">&lt;/</span><span style="color: #a31515">a</span><span style="color: blue">&gt;&lt;/</span><span style="color: #a31515">li</span><span style="color: blue">&gt;
    &lt;</span><span style="color: #a31515">li</span><span style="color: blue">&gt;&lt;</span><span style="color: #a31515">a </span><span style="color: red">href</span><span style="color: blue">=&quot;#&quot;&gt;</span>国际新闻<span style="color: blue">&lt;/</span><span style="color: #a31515">a</span><span style="color: blue">&gt;&lt;/</span><span style="color: #a31515">li</span><span style="color: blue">&gt;
    &lt;</span><span style="color: #a31515">li</span><span style="color: blue">&gt;&lt;</span><span style="color: #a31515">a </span><span style="color: red">href</span><span style="color: blue">=&quot;#&quot;&gt;</span>财经新闻<span style="color: blue">&lt;/</span><span style="color: #a31515">a</span><span style="color: blue">&gt;&lt;/</span><span style="color: #a31515">li</span><span style="color: blue">&gt;
    &lt;</span><span style="color: #a31515">li</span><span style="color: blue">&gt;&lt;</span><span style="color: #a31515">a </span><span style="color: red">href</span><span style="color: blue">=&quot;#&quot;&gt;</span>体育新闻<span style="color: blue">&lt;/</span><span style="color: #a31515">a</span><span style="color: blue">&gt;&lt;/</span><span style="color: #a31515">li</span><span style="color: blue">&gt;
&lt;/</span><span style="color: #a31515">ul</span><span style="color: blue">&gt;</span></pre>
<p>这样一段源代码，从文档结构的角度来理解，它就是一组彼此关联，没有先后和主次之分的列表，可以理解为列表，也可以理解为目录。</p>
<p>但是在css的作用下，它可以变成菜单、导航条等各种形式，如果css和javascript相结合起来，它还可以变成滑动门、三态菜单等。在这种情况下，css负责表现，javascript负责行为，而xhtml并没有因为css想实现什么样式或者javascript想实现什么交互行为而改变自己。不管css和javascript想做什么，都跟它没关系。那么实际上就真正达到了我们“彻底分离”的目的。保证了文档结构的纯粹性。这就是web标准的思维模式。</p>
<p>随之而来的好处，那就是页面的兼容性，不管在什么样的浏览器里，这段xhtml都是合法有效的。w3c校验也不会有任何问题。并且SEO也会非常好。因为搜索引擎想要的并不是class或者onmouseover，搜索引擎想要的只不过是链接地址和链接文字。</p>
<p>那么，没有class，怎么实现样式呢？没有onmouseover或者onclick，怎么实现javascript事件呢？这就需要网页开发人员的css功力和javascript功力了。</p>
<p>所以，越是标准化，对css和javascript的技术要求越高。反过来，css的能力达不到，或者javascript的能力达不到，那就需要借助于class（id和文档结构有关，不算在这里，后面我们再谈）、借助于onmouseover或者onclick这些与结构无关的属性来帮助实现样式或者行为。</p>
<p>在博客园上，<a href="http://www.cnblogs.com/yuntian/archive/2008/01/08/1029433.html" rel="reference" target="_blank">暴牙齿提出“独立于根”的想法</a>。我个人认为从文档结构的角度，并没有“独立于根”的要求。但是如果能够达到“独立于根”的开发能力，那么实现起标准化来就绝对会非常得心应手。因为连“独立于根”都能实现自己的设计样式和行为的话，有了结构的文档就更不在话下了。</p>
<p>理解了标准化的本质和终极目标，如何通过css和javascript来达到这个目标呢？这个问题，留到本系列以后的文章再谈。</p>
<h3  class="related_post_title">相关日志</h3><ul class="related_post"><li>2009-12-21 -- <a href="http://wukangrui.com/2009/12/21/web-developer-understand-css-box-model.html" title="web开发从头说起：理解css盒模型">web开发从头说起：理解css盒模型</a></li><li>2009-12-16 -- <a href="http://wukangrui.com/2009/12/16/web-developer-about-css-selector.html" title="前台开发从头说起：谈谈CSS选择符">前台开发从头说起：谈谈CSS选择符</a></li><li>2009-06-22 -- <a href="http://wukangrui.com/2009/06/22/whatever-hover-pseudo-class-without-javascript.html" title="Whatever:hover &#8211; 无需javascript让IE支持丰富伪类">Whatever:hover &#8211; 无需javascript让IE支持丰富伪类</a></li><li>2009-04-16 -- <a href="http://wukangrui.com/2009/04/16/best-practices-of-css-dropdown-menu.html" title="来自微软站点的纯CSS下拉菜单">来自微软站点的纯CSS下拉菜单</a></li><li>2009-04-13 -- <a href="http://wukangrui.com/2009/04/13/portable-interchangeable-jquery-based-tabs.html" title="简单、通用的JQuery Tab实现">简单、通用的JQuery Tab实现</a></li><li>2006-04-04 -- <a href="http://wukangrui.com/2006/04/04/dynamic-mouse-event-of-image-transparency.html" title="动态实现指定图片半透明及鼠标事件">动态实现指定图片半透明及鼠标事件</a></li><li>2006-03-28 -- <a href="http://wukangrui.com/2006/03/28/simulate-window-in-center-with-css.html" title="CSS:模拟Windows窗口及DIV居中">CSS:模拟Windows窗口及DIV居中</a></li><li>2005-12-12 -- <a href="http://wukangrui.com/2005/12/12/action-of-refactor-page-with-css.html" title="实践：用Div+CSS重构网页">实践：用Div+CSS重构网页</a></li><li>2005-11-29 -- <a href="http://wukangrui.com/2005/11/29/css-learn-in-action.html" title="CSS学习之综合运用">CSS学习之综合运用</a></li><li>2009-04-09 -- <a href="http://wukangrui.com/2009/04/09/aspnetmvc-hands-on-labs-create-application.html" title="[翻译]ASP.NET MVC动手实验1-2：创建ASP.NET MVC应用">[翻译]ASP.NET MVC动手实验1-2：创建ASP.NET MVC应用</a></li></ul>]]></content:encoded>
			<wfw:commentRss>http://wukangrui.com/2009/12/15/web-developer-from-web-standard.html/feed</wfw:commentRss>
		<slash:comments>4</slash:comments>
		</item>
		<item>
		<title>ASP.NET MVC 最佳实践（四）</title>
		<link>http://wukangrui.com/2009/07/08/asp-net-mvc-best-practices-part-4.html</link>
		<comments>http://wukangrui.com/2009/07/08/asp-net-mvc-best-practices-part-4.html#comments</comments>
		<pubDate>Tue, 07 Jul 2009 17:34:45 +0000</pubDate>
		<dc:creator>小李刀刀</dc:creator>
				<category><![CDATA[所谓技术]]></category>
		<category><![CDATA[ASP.NET]]></category>
		<category><![CDATA[MVC]]></category>
		<category><![CDATA[开发]]></category>
		<category><![CDATA[最佳实践]]></category>
		<category><![CDATA[翻译]]></category>

		<guid isPermaLink="false">http://wukangrui.net/2009/07/08/asp-net-mvc-best-practices-part-4.html</guid>
		<description><![CDATA[本系列翻译自 Kazi Manzur Rashid 的博客，由于篇幅关系，原文中的一篇文章在本系列中将拆解成多篇发布。本篇包括原文第二部分第18-21节。]]></description>
			<content:encoded><![CDATA[<p><em>本系列翻译自 </em><a href="http://weblogs.asp.net/rashid/default.aspx"><em>Kazi Manzur Rashid</em></a><em> 的博客，由于翻译水平有限，本系列可能存在误解偏差或者翻译不准的地方，建议对比<a href="http://weblogs.asp.net/rashid/archive/2009/04/01/asp-net-mvc-best-practices-part-1.aspx">原文</a>进行阅读。由于篇幅关系，原文中的一篇文章在本系列中将拆解成多篇发布。本篇包括原文第二部分第18-21节。如果你没有看过之前的第一部分，也许你想先看看 <a href="http://wukangrui.net/2009/06/28/asp-net-mvc-best-practices-part-1.html">《ASP.NET MVC 最佳实践（一）》</a>、《<a href="http://wukangrui.net/2009/06/28/asp-net-mvc-best-practices-part-1.html">ASP.NET MVC 最佳实践（二）</a>》和《<a href="http://wukangrui.net/2009/07/07/asp-net-mvc-best-practices-part-1-2.html" rel="prev" target="_blank">ASP.NET MVC 最佳实践（三）</a>》。</em></p>
</p>
<p><em></em></p>
</p>
<p> <span id="more-858"></span>
</p>
<h4>18. HtmlHelper 扩展</h4>
<p>首先，参考一下 <a href="http://blog.wekeroad.com/" rel="external" target="_blank">Rob Conery</a> 的<a href="http://blog.wekeroad.com/blog/asp-net-mvc-avoiding-tag-soup/" rel="external" target="_blank">这篇文章</a>，我完全同意他的观点，你应该为每种情况创建 Helper 方法，此外我还建议你像 <a href="http://www.asp.net/mvc/" rel="tag" target="_blank">ASP.NET MVC</a> 团队那样为可重用的 UI 元素创建 Helper 方法，但是对于在哪里放置我们正在实践的这些方法，我有不同的建议。</p>
<h6>应用程序开发者</h6>
<p>只为你需要在多个视图中重复使用的HtmlHealper创建单独的扩展方法。对于只在一个视图中使用的帮助方法，你可以为整个视图创建一个Helper类，然后创建一个HtmlHelper来返回这个视图Helper类，而把只在这个视图中使用的扩展方法作为类内部的方法。（这部分未按原文翻译，请自行参照原文）例如：</p>
<pre class="code"><span style="color: blue">public class </span><span style="color: #2b91af">DashboardHtmlHelper </span>{
    <span style="color: blue">private readonly </span><span style="color: #2b91af">HtmlHelper </span>_htmlHelper;

    <span style="color: blue">public </span>DashboardHtmlHelper(<span style="color: #2b91af">HtmlHelper </span>htmlHelper) {
        _htmlHelper = htmlHelper;
    }

    <span style="color: blue">public string </span>DoThis() {
        <span style="color: green">//Your Code
    </span>}

    <span style="color: blue">public string </span>DoThat() {
        <span style="color: green">//Your Code
    </span>}
}

<span style="color: blue">public static class </span><span style="color: #2b91af">HtmlHelperExtension </span>{
    <span style="color: blue">public static </span><span style="color: #2b91af">DashboardHtmlHelper </span>Dashboard(<span style="color: blue">this </span><span style="color: #2b91af">HtmlHelper </span>htmlHelper) {
        <span style="color: blue">return new </span><span style="color: #2b91af">DashboardHtmlHelper</span>(htmlHelper);
    }
}</pre>
<p>然后在视图中这样调用：</p>
<pre class="code"><span style="background: #ffee62">&lt;%</span><span style="color: blue">= </span>Html.Dashboard().DoThis() <span style="background: #ffee62">%&gt;</span></pre>
<h6>UI 组件开发人员</h6>
<p>如果你在开发的是可以在多个 <a href="http://www.asp.net/mvc/" rel="tag" target="_blank">ASP.NET MVC</a> 应用程序中重用的 UI 组件系列，你可以像上面那样为你的整个系列组件创建一个单一名字的Helper。假如你开发的是商业组件，那你可以用你的公司名字来为这个单一的Helper命名，然后在这个Helper中添加方法。否则很容易出现方法的命名冲突。</p>
<p>要是你正在学习 <a href="http://mvccontrib.codeplex.com" rel="external" target="_blank">MVCContrib.org</a> 的做法，为 IViewDataContainer 做扩展的话，道理也是一样的。</p>
<h4>19. Html编码</h4>
<p>在从用户端获取信息的任何情况下，总是使用 Html.Encode(“User Input”) 来编码文本节点，用 Html.AttributeEncode(“User Input”) 来编码Html 元素属性。</p>
<h4>20. 不要把Javascript脚本放在你的视图中</h4>
<p>不要把你的javascript脚本和html混杂在一起，创建一个单独的 js 文件，把脚本代码放在里面。有时候你可能需要在你的 javascript 代码中传递视图数据，这种特殊的情况下，也只把初始化代码放在视图中。例如，你正在开发 web 2.0 风格的应用，你需要在这个应用中传递 ajax 方法的url，并且需要在 javascript 脚本中传递一些其它的模型数据，这种情况下，你可以参考下面的方式：</p>
<p>视图：</p>
<pre class="code"><span style="color: blue">&lt;</span><span style="color: #a31515">div </span><span style="color: red">id</span><span style="color: blue">=&quot;sideBar&quot; </span><span style="color: red">class</span><span style="color: blue">=&quot;column&quot;&gt;&lt;/</span><span style="color: #a31515">div</span><span style="color: blue">&gt;
        &lt;</span><span style="color: #a31515">script </span><span style="color: red">type</span><span style="color: blue">=&quot;text/javascript&quot;&gt;
            </span>$(document).ready(<span style="color: blue">function</span>(){
                Story.init(<span style="color: #a31515">'&lt;%= Model.UrlFormat %&gt;'</span>, <span style="color: #a31515">'&lt;%= Url.NoIcon() %&gt;'</span>, &lt;%= Model.PageCount %&gt;, &lt;%= Model.StoryPerPage %&gt;, &lt;%= Model.CurrentPage %&gt;, <span style="color: #a31515">'&lt;%= Model.SelectedTab %&gt;'</span>, <span style="color: #a31515">'&lt;%= Model.SelectedOrderBy %&gt;'</span>);
            });
        <span style="color: blue">&lt;/</span><span style="color: #a31515">script</span><span style="color: blue">&gt;
    &lt;/</span><span style="color: #a31515">div</span><span style="color: blue">&gt;
&lt;/</span><span style="color: #a31515">asp</span><span style="color: blue">:</span><span style="color: #a31515">Content</span><span style="color: blue">&gt;</span></pre>
<p><a href="http://11011.net/software/vspaste"></a></p>
<p>Javascript：</p>
<pre class="code"><span style="color: blue">var </span>Story = {
    _urlFormat: <span style="color: #a31515">''</span>,
    _noIconUrl: <span style="color: #a31515">''</span>,
    _pageCount: 0,
    _storyPerPage: 0,
    _currentPage: 0,
    _currentTab: <span style="color: #a31515">''</span>,
    _currentOrderBy: <span style="color: #a31515">''</span>,

    init: <span style="color: blue">function</span>(urlFormat, noIconUrl, pageCount, storyPerPage, currentPage, currentTab, currentOrderBy) {
        Story._urlFormat = urlFormat;
        Story._noIconUrl = noIconUrl;
        Story._pageCount = pageCount;
        Story._storyPerPage = storyPerPage;
        Story._currentPage = currentPage;
        Story._currentTab = currentTab;
        Story._currentOrderBy = currentOrderBy;

        <span style="color: green">//More Codes
    </span>}
}</pre>
<p>这里要为不太熟悉上面的 javascript 的同学解释一下，这是一个在javascript中创建静态类的示例代码。对了，我还差点忘了提一点，永远不要在你的javascript文件中硬编码 ajax 方法的url，虽然 <a href="http://videos.visitmix.com/MIX09/T62F" rel="external" target="_blank">Rob Conery</a> 和 <a href="http://aspnetpodcast.com/CS11/blogs/asp.net_podcast/archive/2008/07/28/asp-net-podcast-show-121-phil-haack-with-an-asp-net-mvc-demo-video.aspx" rel="external" target="_blank">Phil Haack</a> 在他们的教程中是这样干的。这是一个很不好的方式，它破坏了 ASP.NET 路径重写的优雅性。</p>
<h4>21. 使用 jQuery 和 jQuery UI</h4>
<p>使用 jQuery 和 jQuery UI，它是最好的js库，并且可以使用 Google CDN 托管服务来加载这些库（对于国内用户，如果使用 google 托管的库一定要有承担风险的准备，具体原因嘛，看看国内6月24日左右的IT新闻就知道了）。</p>
<pre class="code"><span style="color: blue">&lt;</span><span style="color: #a31515">link </span><span style="color: red">type</span><span style="color: blue">=&quot;text/css&quot; </span><span style="color: red">href</span><span style="color: blue">=&quot;http://ajax.googleapis.com/ajax/libs/jqueryui/1.7.1/themes/{YOUR Prefered Theme}/jquery-ui.css&quot; </span><span style="color: red">rel</span><span style="color: blue">=&quot;stylesheet&quot;/&gt;
&lt;</span><span style="color: #a31515">script </span><span style="color: red">type</span><span style="color: blue">=&quot;text/javascript&quot; </span><span style="color: red">src</span><span style="color: blue">=&quot;http://ajax.googleapis.com/ajax/libs/jquery/1.3.2/jquery.min.js&quot;&gt;&lt;/</span><span style="color: #a31515">script</span><span style="color: blue">&gt;
&lt;</span><span style="color: #a31515">script </span><span style="color: red">type</span><span style="color: blue">=&quot;text/javascript&quot; </span><span style="color: red">src</span><span style="color: blue">=&quot;http://ajax.googleapis.com/ajax/libs/jqueryui/1.7.1/jquery-ui.js&quot;&gt;&lt;/</span><span style="color: #a31515">script</span><span style="color: blue">&gt;</span></pre>
<p>还有一种更好的方式：</p>
<pre class="code"><span style="color: blue">&lt;</span><span style="color: #a31515">link </span><span style="color: red">type</span><span style="color: blue">=&quot;text/css&quot; </span><span style="color: red">href</span><span style="color: blue">=&quot;http://ajax.googleapis.com/ajax/libs/jqueryui/1.7.1/themes/{YOUR Prefered Theme}/jquery-ui.css&quot; </span><span style="color: red">rel</span><span style="color: blue">=&quot;stylesheet&quot;/&gt;
&lt;</span><span style="color: #a31515">script </span><span style="color: red">type</span><span style="color: blue">=&quot;text/javascript&quot; </span><span style="color: red">src</span><span style="color: blue">=&quot;http://www.google.com/jsapi&quot;&gt;&lt;/</span><span style="color: #a31515">script</span><span style="color: blue">&gt;
&lt;</span><span style="color: #a31515">script </span><span style="color: red">type</span><span style="color: blue">=&quot;text/javascript&quot;&gt;
    </span>google.load(<span style="color: #a31515">&quot;jquery&quot;</span>, <span style="color: #a31515">&quot;1.3.2&quot;</span>);
    google.load(<span style="color: #a31515">&quot;jqueryui&quot;</span>, <span style="color: #a31515">&quot;1.7.1&quot;</span>);
<span style="color: blue">&lt;/</span><span style="color: #a31515">script</span><span style="color: blue">&gt;</span></pre>
<p>以上就是这一次的全部内容。</p>
<p>最后，我要祝贺 <a href="http://www.asp.net/mvc/" rel="tag" target="_blank">ASP.NET MVC</a> 团队开发了如此杰出的框架，尤其是他们从社区接受反馈的方式。我希望能用这个框架开发出<a href="http://dotnetshoutout.com/" rel="external" target="_blank">更多</a>杀手级的应用（注：杀手级的应用程序，一般指极其优秀的应用程序，这类程序超越了语言本身，比语言更有吸引力而且能增加语言的吸引力）。</p>
<h3  class="related_post_title">相关日志</h3><ul class="related_post"><li>2009-07-07 -- <a href="http://wukangrui.com/2009/07/07/asp-net-mvc-best-practices-part-3.html" title="ASP.NET MVC 最佳实践（三）">ASP.NET MVC 最佳实践（三）</a></li><li>2009-07-01 -- <a href="http://wukangrui.com/2009/07/01/asp-net-mvc-best-practices-part-2.html" title="ASP.NET MVC 最佳实践（二）">ASP.NET MVC 最佳实践（二）</a></li><li>2009-06-28 -- <a href="http://wukangrui.com/2009/06/28/asp-net-mvc-best-practices-part-1.html" title="ASP.NET MVC 最佳实践（一）">ASP.NET MVC 最佳实践（一）</a></li><li>2009-04-13 -- <a href="http://wukangrui.com/2009/04/13/aspnetmvc-hands-on-labs-develop-application.html" title="[翻译]ASP.NET MVC动手实验1-3：开发ASP.NET MVC应用">[翻译]ASP.NET MVC动手实验1-3：开发ASP.NET MVC应用</a></li><li>2009-04-09 -- <a href="http://wukangrui.com/2009/04/09/aspnetmvc-hands-on-labs-create-application.html" title="[翻译]ASP.NET MVC动手实验1-2：创建ASP.NET MVC应用">[翻译]ASP.NET MVC动手实验1-2：创建ASP.NET MVC应用</a></li><li>2009-04-09 -- <a href="http://wukangrui.com/2009/04/09/aspnetmvc-hands-on-labs-introduction.html" title="[翻译]ASP.NET MVC动手系列1-1：ASP.NET MVC概述">[翻译]ASP.NET MVC动手系列1-1：ASP.NET MVC概述</a></li><li>2009-07-05 -- <a href="http://wukangrui.com/2009/07/05/php-5-3-0-release-new-feature.html" title="PHP 5.3.0 发布">PHP 5.3.0 发布</a></li><li>2009-06-22 -- <a href="http://wukangrui.com/2009/06/22/whatever-hover-pseudo-class-without-javascript.html" title="Whatever:hover &#8211; 无需javascript让IE支持丰富伪类">Whatever:hover &#8211; 无需javascript让IE支持丰富伪类</a></li><li>2009-04-30 -- <a href="http://wukangrui.com/2009/04/30/solution-for-js-intellisense-error.html" title="VS2008 中 JS IntelliSense出错的解决">VS2008 中 JS IntelliSense出错的解决</a></li><li>2008-06-22 -- <a href="http://wukangrui.com/2008/06/22/api-bug-in-powereasy-siteweaver-part2.html" title="动易SW中的一个严重但不影响使用的bug（二）">动易SW中的一个严重但不影响使用的bug（二）</a></li></ul>]]></content:encoded>
			<wfw:commentRss>http://wukangrui.com/2009/07/08/asp-net-mvc-best-practices-part-4.html/feed</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>ASP.NET MVC 最佳实践（三）</title>
		<link>http://wukangrui.com/2009/07/07/asp-net-mvc-best-practices-part-3.html</link>
		<comments>http://wukangrui.com/2009/07/07/asp-net-mvc-best-practices-part-3.html#comments</comments>
		<pubDate>Mon, 06 Jul 2009 17:21:16 +0000</pubDate>
		<dc:creator>小李刀刀</dc:creator>
				<category><![CDATA[所谓技术]]></category>
		<category><![CDATA[ASP.NET]]></category>
		<category><![CDATA[MVC]]></category>
		<category><![CDATA[开发]]></category>
		<category><![CDATA[最佳实践]]></category>
		<category><![CDATA[翻译]]></category>

		<guid isPermaLink="false">http://wukangrui.net/2009/07/07/asp-net-mvc-best-practices-part-1-2.html</guid>
		<description><![CDATA[本系列翻译自 Kazi Manzur Rashid 的博客，由于翻译水平有限，本系列可能存在误解偏差或者翻译不准的地方，建议对比原文进行阅读。由于篇幅关系，原文中的一篇文章在本系列中将拆解成多篇发布。本篇包括原文第二部分。如果你没有看过之前的第一部分，也许你想先看看 《ASP.NET MVC 最佳实践（一）》和《ASP.NET MVC 最佳实践（二）》。]]></description>
			<content:encoded><![CDATA[<p><em>本系列翻译自 </em><a href="http://weblogs.asp.net/rashid/default.aspx"><em>Kazi Manzur Rashid</em></a><em> 的博客，由于翻译水平有限，本系列可能存在误解偏差或者翻译不准的地方，建议对比<a href="http://weblogs.asp.net/rashid/archive/2009/04/01/asp-net-mvc-best-practices-part-1.aspx">原文</a>进行阅读。由于篇幅关系，原文中的一篇文章在本系列中将拆解成多篇发布。本篇包括原文第二部分。如果你没有看过之前的第一部分，也许你想先看看 <a rel="prev" href="http://wukangrui.net/2009/06/28/asp-net-mvc-best-practices-part-1.html">《ASP.NET MVC 最佳实践（一）》</a>和《<a rel="prev" href="http://wukangrui.net/2009/06/28/asp-net-mvc-best-practices-part-2.html">ASP.NET MVC 最佳实践（二）</a>》。</em> <span id="more-848"></span><em></em></p>
<h4>15. 关于路由的思考</h4>
<p>如果你在开发的是一个纯 ASP.NET MVC 的应用程序，可以先关闭已有的路由文件检查，这样可以去除不必要的文件系统检查。如果你这样做了，那么就还需要考虑另外的一些事情。请记住如果你的应用程序运行于 IIS 7集成模式，那么 ASP.NET 应用程序将会拦截所有的请求，不管文件的后缀名是什么。所以你必须要在过滤列表中加一些东西，以便让 <a rel="tag" href="http://www.asp.net/mvc/" target="_blank">ASP.NET MVC</a> 应用程序不处理它们。这其中可能包括静态文件，例如 html、htm、文本文件(尤其是robots.txt)、favicon.ico、脚本、图片和css等等。这也是我在<a rel="prev" href="http://wukangrui.net/2009/06/28/asp-net-mvc-best-practices-part-1.html">第一部分第2节</a>中提到不喜欢默认文件结构的原因之一。以下是我为 IIS7 定制的路由定义标准模板：</p>
<pre class="code">_routes.Clear();

<span style="color: green">// Turns off the unnecessary file exists check
</span>_routes.RouteExistingFiles = <span style="color: blue">true</span>;

<span style="color: green">// Ignore text, html, files.
</span>_routes.IgnoreRoute(<span style="color: #a31515">"{file}.txt"</span>);
_routes.IgnoreRoute(<span style="color: #a31515">"{file}.htm"</span>);
_routes.IgnoreRoute(<span style="color: #a31515">"{file}.html"</span>);

<span style="color: green">// Ignore axd files such as assest, image, sitemap etc
</span>_routes.IgnoreRoute(<span style="color: #a31515">"{resource}.axd/{*pathInfo}"</span>);

<span style="color: green">// Ignore the assets directory which contains images, js, css &amp; html
</span>_routes.IgnoreRoute(<span style="color: #a31515">"assets/{*pathInfo}"</span>);

<span style="color: green">// Ignore the error directory which contains error pages
</span>_routes.IgnoreRoute(<span style="color: #a31515">"ErrorPages/{*pathInfo}"</span>);

<span style="color: green">//Exclude favicon (google toolbar request gif file as fav icon which is weird)
</span>_routes.IgnoreRoute(<span style="color: #a31515">"{*favicon}"</span>, <span style="color: blue">new </span>{ favicon = <span style="color: #a31515">@"(.*/)?favicon.([iI][cC][oO]|[gG][iI][fF])(/.*)?" </span>});

<span style="color: green">//Actual routes of my application</span></pre>
<p>接下来是我的一些不同于手册指南的个人偏好。默认情况下 <a rel="tag" href="http://www.asp.net/mvc/" target="_blank">ASP.NET MVC</a> 产生的 url 形如 {controller}/{action}，在你开发一个多模块的应用程序是这是不错的选择，但是对于一些很小的应用程序，我通常喜欢从 url 中去掉控制器(controller)只留下方法名(action name)。如此一来，原来的“www.yourdomain.com/Story/Dashboard” 及 “www.yourdomain.com/Membership/Signin” 就会变成 “www.yourdomain.com/Dashboard” 和“www.yourmain.com/Signin”。所以我要添加一些新路由：</p>
<pre class="code">_routes.MapRoute(<span style="color: #a31515">"SignUp"</span>, <span style="color: #a31515">"SignUp"</span>, <span style="color: blue">new </span>{ controller = <span style="color: #a31515">"Membership"</span>, action = <span style="color: #a31515">"SignUp" </span>});
_routes.MapRoute(<span style="color: #a31515">"SignIn"</span>, <span style="color: #a31515">"SignIn"</span>, <span style="color: blue">new </span>{ controller = <span style="color: #a31515">"Membership"</span>, action = <span style="color: #a31515">"SignIn" </span>});
_routes.MapRoute(<span style="color: #a31515">"ForgotPassword"</span>, <span style="color: #a31515">"ForgotPassword"</span>, <span style="color: blue">new </span>{ controller = <span style="color: #a31515">"Membership"</span>, action = <span style="color: #a31515">"ForgotPassword" </span>});
_routes.MapRoute(<span style="color: #a31515">"SignOut"</span>, <span style="color: #a31515">"SignOut"</span>, <span style="color: blue">new </span>{ controller = <span style="color: #a31515">"Membership"</span>, action = <span style="color: #a31515">"SignOut" </span>});
_routes.MapRoute(<span style="color: #a31515">"Profile"</span>, <span style="color: #a31515">"Profile"</span>, <span style="color: blue">new </span>{ controller = <span style="color: #a31515">"Membership"</span>, action = <span style="color: #a31515">"Profile" </span>});
_routes.MapRoute(<span style="color: #a31515">"ChangePassword"</span>, <span style="color: #a31515">"ChangePassword"</span>, <span style="color: blue">new </span>{ controller = <span style="color: #a31515">"Membership"</span>, action = <span style="color: #a31515">"ChangePassword" </span>});

_routes.MapRoute(<span style="color: #a31515">"Dashboard"</span>, <span style="color: #a31515">"Dashboard/{tab}/{orderBy}/{page}"</span>, <span style="color: blue">new </span>{ controller = <span style="color: #a31515">"Story"</span>, action = <span style="color: #a31515">"Dashboard"</span>, tab = StoryListTab.Unread.ToString(), orderBy = OrderBy.CreatedAtDescending.ToString(), page = 1 });
_routes.MapRoute(<span style="color: #a31515">"Update"</span>, <span style="color: #a31515">"Update"</span>, <span style="color: blue">new </span>{ controller = <span style="color: #a31515">"Story"</span>, action = <span style="color: #a31515">"Update" </span>});
_routes.MapRoute(<span style="color: #a31515">"Submit"</span>, <span style="color: #a31515">"Submit"</span>, <span style="color: blue">new </span>{ controller = <span style="color: #a31515">"Story"</span>, action = <span style="color: #a31515">"Submit" </span>});

_routes.MapRoute(<span style="color: #a31515">"Home"</span>, <span style="color: #a31515">"{controller}/{action}/{id}"</span>, <span style="color: blue">new </span>{ controller = <span style="color: #a31515">"Home"</span>, action = <span style="color: #a31515">"Index"</span>, id = <span style="color: blue">string</span>.Empty });</pre>
<h4> </h4>
<h4>16. 如果需要的话，创建新的ActionResult</h4>
<p><a rel="tag" href="http://www.asp.net/mvc/" target="_blank">ASP.NET MVC</a> 包含有很多种用于不同目的的 ActionResult，但我们仍有可能会需要新的 ActionResult。例如xml、rss、atom等等。在这种情况下，我的建议是不要使用通用的 ContentResult， 而是创建一种新的 ActionResult. <a rel="external" href="http://mvccontrib.codeplex.com" target="_blank">MVCContrib</a> 项目中有一个 XmlResult，你可以用它来返回 xml，但是不支持 feed。显然依靠它来将未知对象转换为 rss/atom 是很困难的，这时你就可以创建一个定义ActionResult的模型。例如：</p>
<pre class="code"><span style="color: blue">public class </span><span style="color: #2b91af">AtomResult </span>: <span style="color: #2b91af">ActionResult </span>{
    <span style="color: blue">public </span>AtomResult(<span style="color: blue">string </span>siteTitle, <span style="color: blue">string </span>feedTitle, <span style="color: #2b91af">IEnumerable</span>&lt;IStory&gt; stories) {
        SiteTitle = siteTitle;
        FeedTitle = feedTitle;
        Stories = stories;
    }

    <span style="color: blue">public string </span>SiteTitle {
        <span style="color: blue">get</span>;
        <span style="color: blue">private set</span>;
    }

    <span style="color: blue">public string </span>FeedTitle {
        <span style="color: blue">get</span>;
        <span style="color: blue">private set</span>;
    }

    <span style="color: blue">public </span><span style="color: #2b91af">IEnumerable</span>&lt;IStory&gt; Stories {
        <span style="color: blue">get</span>;
        <span style="color: blue">private set</span>;
    }

    <span style="color: blue">public override void </span>ExecuteResult(<span style="color: #2b91af">ControllerContext </span>context) {
        <span style="color: blue">string </span>xml = Build(context);

        <span style="color: #2b91af">HttpResponseBase </span>response = context.HttpContext.Response;
        response.ContentType = <span style="color: #a31515">"application/atom+xml"</span>;
        response.Write(xml);
    }
}</pre>
<p>然后在控制器中就可以这样写：<a href="http://11011.net/software/vspaste"></a></p>
<pre class="code">[<span style="color: #2b91af">AcceptVerbs</span>(<span style="color: #2b91af">HttpVerbs</span>.Get), <span style="color: #2b91af">OutputCache</span>(CacheProfile = <span style="color: #a31515">"Atom"</span>)]
<span style="color: blue">public </span><span style="color: #2b91af">ActionResult </span>Shared() {
    <span style="color: #2b91af">IEnumerable</span>&lt;stories&gt; stories = GetSharedStories();

    <span style="color: blue">return new </span><span style="color: #2b91af">AtomResult</span>(<span style="color: #a31515">"My Site"</span>, <span style="color: #a31515">"My shared stories in atom"</span>, stories);
}</pre>
<h4>17. 把你的视图拆分为多个视图控件</h4>
<p>如果你的视图文件变得越来越大，那你可以考虑把它拆分为多个视图控件。至于视图空间是否在多个页面中重用，并没有关系。因为这样做可以让真正的视图文件变得更加具有可读性。考虑一下下面的视图：</p>
<pre class="code"><span style="color: blue">&lt;</span><span style="color: #a31515">asp</span><span style="color: blue">:</span><span style="color: #a31515">Content </span><span style="color: red">ID</span><span style="color: blue">="Content1" </span><span style="color: red">ContentPlaceHolderID</span><span style="color: blue">="TitleContent" </span><span style="color: red">runat</span><span style="color: blue">="server"&gt;
    </span>My Secret App : Dashboard
<span style="color: blue">&lt;/</span><span style="color: #a31515">asp</span><span style="color: blue">:</span><span style="color: #a31515">Content</span><span style="color: blue">&gt;
&lt;</span><span style="color: #a31515">asp</span><span style="color: blue">:</span><span style="color: #a31515">Content </span><span style="color: red">ID</span><span style="color: blue">="Content2" </span><span style="color: red">ContentPlaceHolderID</span><span style="color: blue">="MainContent" </span><span style="color: red">runat</span><span style="color: blue">="server"&gt;
    &lt;</span><span style="color: #a31515">div </span><span style="color: red">id</span><span style="color: blue">="heading"&gt;&lt;/</span><span style="color: #a31515">div</span><span style="color: blue">&gt;
    &lt;</span><span style="color: #a31515">div </span><span style="color: red">class</span><span style="color: blue">="columns"&gt;
        &lt;</span><span style="color: #a31515">div </span><span style="color: red">id</span><span style="color: blue">="main" </span><span style="color: red">class</span><span style="color: blue">="column"&gt;
            &lt;</span><span style="color: #a31515">div </span><span style="color: red">id</span><span style="color: blue">="storyListTabs" </span><span style="color: red">class</span><span style="color: blue">="ui-tabs ui-widget ui-widget-content ui-corner-all"&gt;
                </span><span style="background: #ffee62">&lt;%</span> Html.RenderPartial(<span style="color: #a31515">"TabHeader"</span>, Model);<span style="background: #ffee62">%&gt;
</span>                <span style="color: blue">&lt;</span><span style="color: #a31515">div </span><span style="color: red">id</span><span style="color: blue">="tabContent" </span><span style="color: red">class</span><span style="color: blue">="ui-tabs-panel ui-widget-content ui-corner-bottom"&gt;
                    &lt;</span><span style="color: #a31515">div </span><span style="color: red">id</span><span style="color: blue">="storyList"&gt;
                        </span><span style="background: #ffee62">&lt;%</span> Html.RenderPartial(<span style="color: #a31515">"SortBar"</span>, Model);<span style="background: #ffee62">%&gt;
</span>                        <span style="color: blue">&lt;</span><span style="color: #a31515">div </span><span style="color: red">class</span><span style="color: blue">="clear"&gt;&lt;/</span><span style="color: #a31515">div</span><span style="color: blue">&gt;
                        </span><span style="background: #ffee62">&lt;%</span> Html.RenderPartial(<span style="color: #a31515">"NoLinkMessage"</span>, Model);<span style="background: #ffee62">%&gt;
</span>                        <span style="color: blue">&lt;</span><span style="color: #a31515">form </span><span style="color: red">id</span><span style="color: blue">="update" </span><span style="color: red">action</span><span style="color: blue">="</span><span style="background: #ffee62">&lt;%</span>= Url.Update()<span style="background: #ffee62">%&gt;</span><span style="color: blue">" </span><span style="color: red">method</span><span style="color: blue">="post"&gt;
                            </span><span style="background: #ffee62">&lt;%</span> Html.RenderPartial(<span style="color: #a31515">"List"</span>, Model);<span style="background: #ffee62">%&gt;
</span>                            <span style="background: #ffee62">&lt;%</span> Html.RenderPartial(<span style="color: #a31515">"ActionBar"</span>, Model);<span style="background: #ffee62">%&gt;
</span>                            <span style="background: #ffee62">&lt;%</span> Html.RenderPartial(<span style="color: #a31515">"Pager"</span>, Model);<span style="background: #ffee62">%&gt;
</span>                        <span style="color: blue">&lt;/</span><span style="color: #a31515">form</span><span style="color: blue">&gt;
                    &lt;/</span><span style="color: #a31515">div</span><span style="color: blue">&gt;
                &lt;/</span><span style="color: #a31515">div</span><span style="color: blue">&gt;
            &lt;/</span><span style="color: #a31515">div</span><span style="color: blue">&gt;
            </span><span style="background: #ffee62">&lt;%</span>Html.RenderPartial(<span style="color: #a31515">"Submit"</span>, <span style="color: blue">new </span>StorySubmitViewModel());<span style="background: #ffee62">%&gt;
</span>        <span style="color: blue">&lt;/</span><span style="color: #a31515">div</span><span style="color: blue">&gt;
        &lt;</span><span style="color: #a31515">div </span><span style="color: red">id</span><span style="color: blue">="sideBar" </span><span style="color: red">class</span><span style="color: blue">="column"&gt;&lt;/</span><span style="color: #a31515">div</span><span style="color: blue">&gt;
    &lt;/</span><span style="color: #a31515">div</span><span style="color: blue">&gt;
&lt;/</span><span style="color: #a31515">asp</span><span style="color: blue">:</span><span style="color: #a31515">Content</span><span style="color: blue">&gt;</span></pre>
<p>继续阅读：《<a rel="next" href="http://wukangrui.net/2009/07/08/asp-net-mvc-best-practices-part-4.html">ASP.NET MVC 最佳实践（四）</a>》</p>
<h3  class="related_post_title">相关日志</h3><ul class="related_post"><li>2009-07-08 -- <a href="http://wukangrui.com/2009/07/08/asp-net-mvc-best-practices-part-4.html" title="ASP.NET MVC 最佳实践（四）">ASP.NET MVC 最佳实践（四）</a></li><li>2009-07-01 -- <a href="http://wukangrui.com/2009/07/01/asp-net-mvc-best-practices-part-2.html" title="ASP.NET MVC 最佳实践（二）">ASP.NET MVC 最佳实践（二）</a></li><li>2009-06-28 -- <a href="http://wukangrui.com/2009/06/28/asp-net-mvc-best-practices-part-1.html" title="ASP.NET MVC 最佳实践（一）">ASP.NET MVC 最佳实践（一）</a></li><li>2009-04-13 -- <a href="http://wukangrui.com/2009/04/13/aspnetmvc-hands-on-labs-develop-application.html" title="[翻译]ASP.NET MVC动手实验1-3：开发ASP.NET MVC应用">[翻译]ASP.NET MVC动手实验1-3：开发ASP.NET MVC应用</a></li><li>2009-04-09 -- <a href="http://wukangrui.com/2009/04/09/aspnetmvc-hands-on-labs-create-application.html" title="[翻译]ASP.NET MVC动手实验1-2：创建ASP.NET MVC应用">[翻译]ASP.NET MVC动手实验1-2：创建ASP.NET MVC应用</a></li><li>2009-04-09 -- <a href="http://wukangrui.com/2009/04/09/aspnetmvc-hands-on-labs-introduction.html" title="[翻译]ASP.NET MVC动手系列1-1：ASP.NET MVC概述">[翻译]ASP.NET MVC动手系列1-1：ASP.NET MVC概述</a></li><li>2009-07-05 -- <a href="http://wukangrui.com/2009/07/05/php-5-3-0-release-new-feature.html" title="PHP 5.3.0 发布">PHP 5.3.0 发布</a></li><li>2009-06-22 -- <a href="http://wukangrui.com/2009/06/22/whatever-hover-pseudo-class-without-javascript.html" title="Whatever:hover &#8211; 无需javascript让IE支持丰富伪类">Whatever:hover &#8211; 无需javascript让IE支持丰富伪类</a></li><li>2009-04-30 -- <a href="http://wukangrui.com/2009/04/30/solution-for-js-intellisense-error.html" title="VS2008 中 JS IntelliSense出错的解决">VS2008 中 JS IntelliSense出错的解决</a></li><li>2008-06-22 -- <a href="http://wukangrui.com/2008/06/22/api-bug-in-powereasy-siteweaver-part2.html" title="动易SW中的一个严重但不影响使用的bug（二）">动易SW中的一个严重但不影响使用的bug（二）</a></li></ul>]]></content:encoded>
			<wfw:commentRss>http://wukangrui.com/2009/07/07/asp-net-mvc-best-practices-part-3.html/feed</wfw:commentRss>
		<slash:comments>3</slash:comments>
		</item>
		<item>
		<title>PHP 5.3.0 发布</title>
		<link>http://wukangrui.com/2009/07/05/php-5-3-0-release-new-feature.html</link>
		<comments>http://wukangrui.com/2009/07/05/php-5-3-0-release-new-feature.html#comments</comments>
		<pubDate>Sat, 04 Jul 2009 19:33:30 +0000</pubDate>
		<dc:creator>小李刀刀</dc:creator>
				<category><![CDATA[所谓技术]]></category>
		<category><![CDATA[PHP]]></category>
		<category><![CDATA[开发]]></category>
		<category><![CDATA[编程]]></category>

		<guid isPermaLink="false">http://wukangrui.net/2009/07/05/php-5-3-0-release-new-feature.html</guid>
		<description><![CDATA[如今PHP 5.3.0也像ASP.NET一样，引入了命名空间、延迟绑定、匿名函数、Lambda表达式等先进特性，可见编程语言与平台无关性在未来将更加凸显，而混合编程的正确性和先进性也将不断得到体现。封闭自己，拒绝变化的产品和思想，在开发领域只有死路一条。]]></description>
			<content:encoded><![CDATA[<p><a href="http://www.php.net/" rel="external" target="_blank">PHP 官方网站</a> 6月30日放出了<a href="http://www.php.net/archive/2009.php#id2009-06-30-1" rel="external" target="_blank">PHP 5.3.0 正式发布的消息</a>，该版本是PHP 5.x系列的一个重要里程碑。根据 PHP 官方网站7月3日更新的 <a href="http://cn2.php.net/manual/en/migration53.new-features.php" rel="external" target="_blank">PHP 5.3.0 新特性</a> 介绍，PHP 5.3.0 主要包括以下新增特性或功能：</p>
<p> <span id="more-845"></span>
</p>
<ul>
<li>支持<a href="http://php.net/namespaces" rel="external" target="_blank">命名空间</a> </li>
<li>支持<a href="http://cn2.php.net/manual/en/language.oop5.late-static-bindings.php" rel="external" target="_blank">延迟静态绑定</a>技术 </li>
<li>支持<a href="http://cn2.php.net/manual/en/control-structures.goto.php" rel="external" target="_blank">跳转标签</a>（受限制的goto） </li>
<li>支持<a href="http://cn2.php.net/manual/en/functions.anonymous.php" rel="external" target="_blank">闭包</a>（Lambda表达式和匿名函数） </li>
<li>新增两个魔法函数，<a href="http://cn2.php.net/manual/en/language.oop5.overloading.php#language.oop5.overloading.methods" rel="external" target="_blank">__callStatic</a> 和 <a href="http://cn2.php.net/manual/en/language.oop5.magic.php#language.oop5.magic.invoke" rel="external" target="_blank">__invoke</a> </li>
<li>新增 <a href="http://cn2.php.net/manual/en/language.types.string.php#language.types.string.syntax.nowdoc" rel="external" target="_blank">Nowdoc</a> 语法支持，与 <a href="http://cn2.php.net/manual/en/language.types.string.php#language.types.string.syntax.heredoc" rel="external" target="_blank">Heredoc</a> 语法相同但是带有单引号 </li>
<li>可以在静态变量和类成员、类构造函数中使用 Heredoc 语法 </li>
<li>Heredoc 可以用双引号定义，以便与 Nowdoc 的单引号区别 </li>
<li><a href="http://cn2.php.net/manual/en/language.constants.syntax.php" rel="external" target="_blank">构造函数</a>可以在类之外用 <em>const</em> 关键词进行定义 </li>
<li>增加了<a href="http://cn2.php.net/manual/en/language.operators.comparison.php#language.operators.comparison.ternary" rel="external" target="_blank">条件操作符</a>的简短形式 ?: (例如 a = condition ? true : false） </li>
<li>200 到 399 的状态码在HTTP数据流容器被认为是成功 </li>
<li>允许动态访问静态成员 </li>
<li>允许对<a href="http://cn2.php.net/manual/en/language.operators.comparison.php#language.operators.comparison.ternary" rel="external" target="_blank">异常</a>进行嵌套 </li>
<li>增加并且默认启用垃圾回收机制 </li>
</ul>
<p>此外，针对Windows版本的改变有：</p>
<ul>
<li>不再支持Windows98,ME和NT4，最低支持Windows 2000 </li>
<li>Windows 二进制版本针对 i586 或更高版本编译，不再支持 i386和i486 </li>
<li>对 Windows 系统上的 64位 PHP 提供支持（实验性的） </li>
<li>支持Visual C++ 9（VC9）编译，可以使用 Visual Studio 2008。 </li>
<li><a href="http://cn2.php.net/manual/en/ref.pdo-oci.php" rel="external" target="_blank">PDO_OCI</a> 的 php_pdo_oci8.dll 库（用于Oracle 8的客户端类库）不再构建，替代它的是 php_pdo_oci.dll（去掉了“8”），用于 Oracle 10 或者 11。与其他版本的数据库连接继续支持。 </li>
<li>针对 <a href="http://cn2.php.net/manual/en/book.oci8.php" rel="external" target="_blank">OCI8</a> 的扩展，除了php_oci8.dll之外增加了一个php_oci8_11g.dll，但是不能同时启用。php_oci8.dll与Oracle 10.2客户端类库结合使用，而php_oci8_11g.dll 和 Oracle 11客户端类库结合使用。与其他版本数据库的连接继续支持。 </li>
</ul>
<p>Windows版本新增加了对下列函数的支持：</p>
<ul>
<li><a href="http://cn2.php.net/function.checkdnsrr.php">checkdnsrr()</a> </li>
<li>d<a href="http://cn2.php.net/function.dns-get-record.php">ns_get_record()</a> </li>
<li><a href="http://cn2.php.net/function.fnmatch.php">fnmatch()</a> </li>
<li><a href="http://cn2.php.net/function.getmxrr.php">getmxrr()</a> </li>
<li><a href="http://cn2.php.net/function.getopt.php">getopt()</a> </li>
<li><a href="http://cn2.php.net/function.imagecolorclosesthwb.php">imagecolorclosesthwb()</a> </li>
<li><a href="http://cn2.php.net/function.inet-ntop.php">inet_ntop()</a> </li>
<li><a href="http://cn2.php.net/function.inet-pton.php">inet_pton()</a> </li>
<li><a href="http://cn2.php.net/function.link.php">link()</a> </li>
<li><a href="http://cn2.php.net/function.linkinfo.php">linkinfo()</a> </li>
<li><a href="http://cn2.php.net/function.mcrypt-create-iv.php">mcrypt_create_iv()</a> </li>
<li><a href="http://cn2.php.net/function.readlink.php">readlink()</a> </li>
<li><a href="http://cn2.php.net/function.socket-create-pair.php">socket_create_pair()</a> &#8211; 这个函数以前就在Windows中支持，但是由于在PHP 4.3.0中的一个bug而被禁用 </li>
<li><a href="http://cn2.php.net/function.stream-socket-pair.php">stream_socket_pair()</a> </li>
<li><a href="http://cn2.php.net/function.symlink.php">symlink()</a> </li>
<li><a href="http://cn2.php.net/function.time-nanosleep.php">time_nanosleep()</a> </li>
<li><a href="http://cn2.php.net/function.time-sleep-until.php">time_sleep_until()</a> </li>
</ul>
<p>除了上述改变外，Windows版本还有一些其它提升性能或者增加兼容性的改进，而最为重要的则是一条针对Windows的说明：</p>
<p>在windows下采用ISAPI方式运行PHP已经被遗弃，采用改进的FastCGI SAPI模块来代替。我在<a href="http://wukangrui.net/2008/06/23/fastcgi-for-php-in-iis.html" rel="external" target="_blank">2008年6月23日的日志</a>中曾经笑称“PHP成为IIS‘一等公民’”，那是只是从微软IIS团队官方发布PHP的FastCGI模块，以及微软和Zend的合作而对PHP在Windows平台上的使用做了最乐观的展望，而后来微软在IIS7以后的版本内置FastCGI模块，甚至在云服务中也内置FastCGI支持，则更说明了PHP与Windows的联姻将继续增强。可惜的是直到Windows7发布之后，网上的绝大部分教程依然在教新手采用ISAPI方式运行PHP，甚至是采用PHP4的安装方式。甚至还有人专门跑到我的空间里叫嚣在Windows下运行PHP是如何如何。开源社区对Windows平台的妖魔化，至今影响深远。正是由于拒绝导致了他们对Windows、ASP.NET、C#的不了解，甚至直至今日还死抱着Windows比Linux慢、不如Linux安全之类的陈旧观念。</p>
<p>如今PHP 5.3.0也像ASP.NET一样，引入了命名空间、延迟绑定、匿名函数、Lambda表达式等先进特性，可见编程语言与平台无关性在未来将更加凸显，而混合编程的正确性和先进性也将不断得到体现。封闭自己，拒绝变化的产品和思想，在开发领域只有死路一条。</p>
<h3  class="related_post_title">相关日志</h3><ul class="related_post"><li>2008-06-04 -- <a href="http://wukangrui.com/2008/06/04/unix-timestamp-in-asp.html" title="在ASP中实现UNIX时间戳">在ASP中实现UNIX时间戳</a></li><li>2008-05-23 -- <a href="http://wukangrui.com/2008/05/23/disadvantages-of-discuz-ucenter.html" title="给UCenter的拥蹩们泼点冷水">给UCenter的拥蹩们泼点冷水</a></li><li>2009-07-08 -- <a href="http://wukangrui.com/2009/07/08/asp-net-mvc-best-practices-part-4.html" title="ASP.NET MVC 最佳实践（四）">ASP.NET MVC 最佳实践（四）</a></li><li>2009-07-07 -- <a href="http://wukangrui.com/2009/07/07/asp-net-mvc-best-practices-part-3.html" title="ASP.NET MVC 最佳实践（三）">ASP.NET MVC 最佳实践（三）</a></li><li>2009-07-01 -- <a href="http://wukangrui.com/2009/07/01/asp-net-mvc-best-practices-part-2.html" title="ASP.NET MVC 最佳实践（二）">ASP.NET MVC 最佳实践（二）</a></li><li>2009-06-28 -- <a href="http://wukangrui.com/2009/06/28/asp-net-mvc-best-practices-part-1.html" title="ASP.NET MVC 最佳实践（一）">ASP.NET MVC 最佳实践（一）</a></li><li>2009-06-08 -- <a href="http://wukangrui.com/2009/06/08/using-fastcgi-to-host-php-applications-on-iis-7x.html" title="在 IIS 7.x 中用 FastCGI 运行 PHP">在 IIS 7.x 中用 FastCGI 运行 PHP</a></li><li>2008-06-23 -- <a href="http://wukangrui.com/2008/06/23/fastcgi-for-php-in-iis.html" title="微软官方FastCGI，PHP成为IIS“一等公民”">微软官方FastCGI，PHP成为IIS“一等公民”</a></li><li>2008-06-22 -- <a href="http://wukangrui.com/2008/06/22/api-bug-in-powereasy-siteweaver-part2.html" title="动易SW中的一个严重但不影响使用的bug（二）">动易SW中的一个严重但不影响使用的bug（二）</a></li><li>2008-06-22 -- <a href="http://wukangrui.com/2008/06/22/thinking-about-html-page-creating.html" title="静态页面生成的思考">静态页面生成的思考</a></li></ul>]]></content:encoded>
			<wfw:commentRss>http://wukangrui.com/2009/07/05/php-5-3-0-release-new-feature.html/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>ASP.NET MVC 最佳实践（二）</title>
		<link>http://wukangrui.com/2009/07/01/asp-net-mvc-best-practices-part-2.html</link>
		<comments>http://wukangrui.com/2009/07/01/asp-net-mvc-best-practices-part-2.html#comments</comments>
		<pubDate>Tue, 30 Jun 2009 21:03:41 +0000</pubDate>
		<dc:creator>小李刀刀</dc:creator>
				<category><![CDATA[所谓技术]]></category>
		<category><![CDATA[ASP.NET]]></category>
		<category><![CDATA[MVC]]></category>
		<category><![CDATA[开发]]></category>
		<category><![CDATA[最佳实践]]></category>
		<category><![CDATA[翻译]]></category>

		<guid isPermaLink="false">http://wukangrui.net/2009/07/01/asp-net-mvc-best-practices-part-2.html</guid>
		<description><![CDATA[本系列翻译自 Kazi Manzur Rashid 的博客，由于翻译水平有限，本系列可能存在误解偏差或者翻译不准的地方，建议对比原文进行阅读。由于篇幅关系，原文中的一篇文章在本系列中将拆解成多篇发布。本篇包括原文第一部分中的7-14节。如果你没有看过之前的第一部分，也许你想先看看 《ASP.NET MVC 最佳实践（一）》。]]></description>
			<content:encoded><![CDATA[<p><em>本系列翻译自 </em><a href="http://weblogs.asp.net/rashid/default.aspx"><em>Kazi Manzur Rashid</em></a><em> 的博客，由于翻译水平有限，本系列可能存在误解偏差或者翻译不准的地方，建议对比<a href="http://weblogs.asp.net/rashid/archive/2009/04/01/asp-net-mvc-best-practices-part-1.aspx">原文</a>进行阅读。由于篇幅关系，原文中的一篇文章在本系列中将拆解成多篇发布。本篇包括原文第一部分中的7-14节。如果你没有看过之前的第一部分，也许你想先看看 <a rel="prev" href="http://wukangrui.net/2009/06/28/asp-net-mvc-best-practices-part-1.html">《ASP.NET MVC 最佳实践（一）》</a>。</em></p>
<p><span id="more-829"></span></p>
<h4>7. 不要在控制器中使用HttpContext类及其派生类</h4>
<p>在你的控制器中不要引用到HttpContext以及它的派生类。这让你能比较容易地进行控制器的单元测试。如果你需要访问与HttpContext相关的对象比如User、QueryString、Cookie等，你可以使用自定义的行为过滤器（<a rel="external" href="http://www.cnblogs.com/" target="_blank">博客园</a>的<a rel="external" href="http://www.cnblogs.com/JeffreyZhao/" target="_blank">老赵</a>有<a rel="external" href="http://www.cnblogs.com/JeffreyZhao/archive/2009/03/09/no-dependency-to-httpcontext.html" target="_blank">一篇文章</a>对这一条进行了深入的论述，并提出了自己的解决方案，建议阅读）或者创建一些接口和容器，并把它传入控制器的构造函数。例如，下面的路由：</p>
<pre class="code">routes.MapRoute(
    <span style="color: #a31515">"Dashboard"</span>,
    <span style="color: #a31515">"Dashboard/{tab}/{orderBy}/{page}"</span>,
    <span style="color: blue">new </span>{
        controller = <span style="color: #a31515">"Story"</span>,
        action = <span style="color: #a31515">"Dashboard"</span>,
        tab = StoryListTab.Unread.ToString(),
        orderBy = OrderBy.CreatedAtDescending.ToString(),
        page = 1
    }
);</pre>
<p><a href="http://11011.net/software/vspaste"></a></p>
<p>而控制器的行为方法则定义为：</p>
<pre class="code">[<span style="color: #2b91af">AcceptVerbs</span>(<span style="color: #2b91af">HttpVerbs</span>.Get),<span style="color: #2b91af">OutputCache</span>(CacheProfile = <span style="color: #a31515">"Dashboard"</span>),UserNameFilter]
<span style="color: blue">public </span><span style="color: #2b91af">ActionResult </span>Dashboard(<span style="color: blue">string </span>userName, StoryListTab tab, OrderBy orderBy, <span style="color: blue">int</span>? page) {
}</pre>
<p><a href="http://11011.net/software/vspaste"></a></p>
<p>UserNameFilter这个过滤器负责传递UserName：</p>
<pre class="code"><span style="color: blue">public class </span><span style="color: #2b91af">UserNameFilter </span>: <span style="color: #2b91af">ActionFilterAttribute </span>{
    <span style="color: blue">public override void </span>OnActionExecuting(<span style="color: #2b91af">ActionExecutingContext </span>filterContext) {
        <span style="color: blue">const string </span>Key = <span style="color: #a31515">"userName"</span>;

        <span style="color: blue">if </span>(filterContext.ActionParameters.ContainsKey(Key)) {
            <span style="color: blue">if </span>(filterContext.HttpContext.User.Identity.IsAuthenticated) {
                filterContext.ActionParameters[Key] = filterContext.HttpContext.User.Identity.Name;
            }
        }

        <span style="color: blue">base</span>.OnActionExecuting(filterContext);
    }
}</pre>
<p><a href="http://11011.net/software/vspaste"></a></p>
<p><strong>[更新：一定要明确你已经对控制器或者是对控制器中的行为添加了 Authorize 属性，参见<a rel="external" href="http://weblogs.asp.net/rashid/archive/2009/04/01/asp-net-mvc-best-practices-part-1.aspx#comments" target="_blank">原文评论</a>。]</strong></p>
<h4>8. 用行为控制器来转换行为方法参数</h4>
<p>用行为过滤器来把传入值转换为你的控制器行为方法参数，再看一下 Dashboard方法的代码，我们以 Enum 类型接受 tab 和 orderBy这两个参数。</p>
<pre class="code">[<span style="color: #2b91af">AcceptVerbs</span>(<span style="color: #2b91af">HttpVerbs</span>.Get), <span style="color: #2b91af">OutputCache</span>(CacheProfile = <span style="color: #a31515">"Dashboard"</span>), StoryListFilter]
<span style="color: blue">public </span><span style="color: #2b91af">ActionResult </span>Dashboard(<span style="color: blue">string </span>userName, StoryListTab tab, OrderBy orderBy, <span style="color: blue">int</span>? page) {
}</pre>
<p><a href="http://11011.net/software/vspaste"></a></p>
<p> </p>
<p>过滤器 StoryListFilter 将负责把它由 路由的值/查询字符串 转换为适当的数据类型。</p>
<pre class="code"><span style="color: blue">public class </span><span style="color: #2b91af">StoryListFilter </span>: <span style="color: #2b91af">ActionFilterAttribute </span>{
    <span style="color: blue">public override void </span>OnActionExecuting(<span style="color: #2b91af">ActionExecutingContext </span>filterContext) {
        <span style="color: blue">const string </span>TabKey = <span style="color: #a31515">"tab"</span>;
        <span style="color: blue">const string </span>OrderByKey = <span style="color: #a31515">"orderBy"</span>;

        NameValueCollection queryString = filterContext.HttpContext.Request.QueryString;

        StoryListTab tab = <span style="color: blue">string</span>.IsNullOrEmpty(queryString[TabKey]) ?
                            filterContext.RouteData.Values[TabKey].ToString().ToEnum(StoryListTab.Unread) :
                            queryString[TabKey].ToEnum(StoryListTab.Unread);

        filterContext.ActionParameters[TabKey] = tab;

        OrderBy orderBy = <span style="color: blue">string</span>.IsNullOrEmpty(queryString[OrderByKey]) ?
                            filterContext.RouteData.Values[OrderByKey].ToString().ToEnum(OrderBy.CreatedAtDescending) :
                            queryString[OrderByKey].ToEnum(OrderBy.CreatedAtDescending);

        filterContext.ActionParameters[OrderByKey] = orderBy;

        <span style="color: blue">base</span>.OnActionExecuting(filterContext);
    }
}</pre>
<p>你也可以用自定义模型绑定器来达到同样的目的。如果要那样做的话，你需要为每个枚举创建一个独立的模型绑定器，而不是用一个行为过滤器来处理所有的枚举参数。用模型绑定器还有一个问题，一旦你注册了一个类型，在行为中它就总是被使用，而行为过滤器则是可以根据需要选择使用的。</p>
<h4>9. 行为过滤器的位置</h4>
<p>如果你要对你的控制器的所有行为方法应用同一个行为过滤器，你可以把这个过滤器放在控制器的定义上而不必给每个行为方法应用。如果你要对你的所有控制器应用同一个行为过滤器，你应该创建一个基控制器，对它应用该过滤器，并让所有的控制器继承这个基控制器。例如 story 控制器应该只在用户已经登陆的情况下才可以使用，并且我们需要把当前用户的用户名传入 story 控制器下的方法，另外Story控制器应该压缩返回的数据：</p>
<pre class="code">[<span style="color: #2b91af">Authorize</span>, <span style="color: #2b91af">UserNameFilter</span>]
<span style="color: blue">public class </span><span style="color: #2b91af">StoryController </span>: <span style="color: #2b91af">BaseController </span>{
}

[CompressFilter]
<span style="color: blue">public class </span><span style="color: #2b91af">BaseController </span>: <span style="color: #2b91af">Controller </span>{
}</pre>
<p><a href="http://11011.net/software/vspaste"></a></p>
<p>但是如果继承的层次达到或者高于2层，应该另找方法来应用过滤器。最新的 <a rel="external" href="http://oxite.codeplex.com/" target="_blank">Oxite</a> 代码里有一些非常出色的动态应用过滤器的方法，我强烈推荐你去看一下。</p>
<h4>10. 小心使用UpdateModel</h4>
<p>我要再次强调 Justin Ethredge 在他的文章中已经提过的这个问题，开发中一定小心，避免陷进UpdateModel的陷阱里去。</p>
<h4>11.控制器不要包含任何域逻辑</h4>
<p>控制器应该只负责：</p>
<ul>
<li>验证输入</li>
<li>调用Model层来为显示视图准备数据</li>
<li>返回视图或者跳转到另一个行为</li>
</ul>
<p>如果你在控制器中坐了其它的事情，那就说明你把它们放错了地方。你在控制器中坐的这些事情或许更应该交给模型去处理。只要你遵守了这条规则，你的每个控制器方法代码应该不会超过20到25行。 <a rel="external" href="http://codebetter.com/blogs/ian_cooper/default.aspx" target="_blank">Ian Cooper</a> 有一篇很棒的文章《<a rel="external" href="http://codebetter.com/blogs/ian_cooper/archive/2008/12/03/the-fat-controller.aspx" target="_blank">Skin Controller Fat Model</a>》，有空的时候你一定要读一下。</p>
<h4>12. 避免使用 ViewData，尽量使用ViewData.Model</h4>
<p>依赖于数据字典不仅使你的代码难以重构，而且你还不得不在试图中编写转换代码。实际上即使你给你的控制器的每个方法都单独编写一个类作为数据模型，那也是完全可以的。如果你觉得编写这些视图数据模型类是一项非常乏味的工作的话，你可以使用 MVCContrib 项目中 ViewDataExtensions，它包含一些用于返回强类型对象的不错的扩展。但是如果你的视图数据的数据字典中包含了多个数据类型的话，你还是没办法摆脱数据字典和他的字符串名。</p>
<h4>13. 用 PRG 模式来修改数据</h4>
<p>Tim Barcz, Matt Hawley, Stephen Wather 甚至 Scott Gu 都写了这方面的文章，你可以在 <a rel="external" href="http://devlicio.us/blogs/tim_barcz/archive/2008/08/22/prg-pattern-in-the-asp-net-mvc-framework.aspx" target="_blank">这里</a>、<a rel="external" href="http://blog.eworldui.net/post/2008/05/ASPNET-MVC---Using-Post2c-Redirect2c-Get-Pattern.aspx" target="_blank">这里</a>、<a rel="external" href="http://stephenwalther.com/blog/archive/2008/06/20/asp-net-mvc-tip-6-call-redirecttoaction-after-submitting-a-form.aspx" target="_blank">这里</a>和<a rel="external" href="http://weblogs.asp.net/scottgu/archive/2008/09/02/asp-net-mvc-preview-5-and-form-posting-scenarios.aspx" target="_blank">这里</a>找到它们。这个模式的一个问题是当一项验证失败或者发生任何错误的时候，你不得不把ModelState复制到TempData里面。如果你是手动来做这件事，请不要再那样做了，你可以用行为过滤器自动处理它，就像下面这样：</p>
<pre class="code">[<span style="color: #2b91af">AcceptVerbs</span>(<span style="color: #2b91af">HttpVerbs</span>.Get), <span style="color: #2b91af">OutputCache</span>(CacheProfile = <span style="color: #a31515">"Dashboard"</span>), StoryListFilter, ImportModelStateFromTempData]
<span style="color: blue">public </span><span style="color: #2b91af">ActionResult </span>Dashboard(<span style="color: blue">string </span>userName, StoryListTab tab, OrderBy orderBy, <span style="color: blue">int</span>? page)
{
    <span style="color: green">//Other Codes
    </span><span style="color: blue">return </span>View();
}

[<span style="color: #2b91af">AcceptVerbs</span>(<span style="color: #2b91af">HttpVerbs</span>.Post), ExportModelStateToTempData]
<span style="color: blue">public </span><span style="color: #2b91af">ActionResult </span>Submit(<span style="color: blue">string </span>userName, <span style="color: blue">string </span>url)
{
    <span style="color: blue">if </span>(ValidateSubmit(url))
    {
        <span style="color: blue">try
        </span>{
            _storyService.Submit(userName, url);
        }
        <span style="color: blue">catch </span>(Exception e)
        {
            ModelState.AddModelError(ModelStateException, e);
        }
    }

    <span style="color: blue">return </span>Redirect(Url.Dashboard());
}</pre>
<p><a href="http://11011.net/software/vspaste"></a></p>
<p>还有行为过滤器的代码：</p>
<pre class="code"><span style="color: blue">public abstract class </span><span style="color: #2b91af">ModelStateTempDataTransfer </span>: <span style="color: #2b91af">ActionFilterAttribute </span>{
    <span style="color: blue">protected static readonly string </span>Key = <span style="color: blue">typeof</span>(<span style="color: #2b91af">ModelStateTempDataTransfer</span>).FullName;
}

<span style="color: blue">public class </span><span style="color: #2b91af">ExportModelStateToTempData </span>: <span style="color: #2b91af">ModelStateTempDataTransfer </span>{
    <span style="color: blue">public override void </span>OnActionExecuted(<span style="color: #2b91af">ActionExecutedContext </span>filterContext) {
        <span style="color: green">//Only export when ModelState is not valid
        </span><span style="color: blue">if </span>(!filterContext.Controller.ViewData.ModelState.IsValid) {
            <span style="color: green">//Export if we are redirecting
            </span><span style="color: blue">if </span>((filterContext.Result <span style="color: blue">is </span><span style="color: #2b91af">RedirectResult</span>) || (filterContext.Result <span style="color: blue">is </span><span style="color: #2b91af">RedirectToRouteResult</span>)) {
                filterContext.Controller.TempData[Key] = filterContext.Controller.ViewData.ModelState;
            }
        }

        <span style="color: blue">base</span>.OnActionExecuted(filterContext);
    }
}

<span style="color: blue">public class </span><span style="color: #2b91af">ImportModelStateFromTempData </span>: <span style="color: #2b91af">ModelStateTempDataTransfer </span>{
    <span style="color: blue">public override void </span>OnActionExecuted(<span style="color: #2b91af">ActionExecutedContext </span>filterContext) {
        <span style="color: #2b91af">ModelStateDictionary </span>modelState = filterContext.Controller.TempData[Key] <span style="color: blue">as </span><span style="color: #2b91af">ModelStateDictionary</span>;

        <span style="color: blue">if </span>(modelState != <span style="color: blue">null</span>) {
            <span style="color: green">//Only Import if we are viewing
            </span><span style="color: blue">if </span>(filterContext.Result <span style="color: blue">is </span><span style="color: #2b91af">ViewResult</span>) {
                filterContext.Controller.ViewData.ModelState.Merge(modelState);
            } <span style="color: blue">else </span>{
                <span style="color: green">//Otherwise remove it.
                </span>filterContext.Controller.TempData.Remove(Key);
            }
        }

        <span style="color: blue">base</span>.OnActionExecuted(filterContext);
    }
}</pre>
<p><a href="http://11011.net/software/vspaste"></a></p>
<p><a rel="external" href="http://mvccontrib.codeplex.com" target="_blank">MVCContrib</a> 项目也有这个功能，但是我不喜欢他们在用一个单独类来处理的方式，我喜欢对“哪个方法输出”和“哪个方法输入”有更多的控制权。</p>
<h4>14. 为你的视图模型创建父类层并用行为过滤器来构成公共部分</h4>
<p>为你的视图模型类编写一个父类层，并用过滤器来构成它的公共部分。例如我正在开发的这个非常小的应用程序，我需要知道用户是否已经认证，已及用户名。</p>
<pre class="code"><span style="color: blue">public class </span><span style="color: #2b91af">ViewModel </span>{
    <span style="color: blue">public bool </span>IsUserAuthenticated {
        <span style="color: blue">get</span>;
        <span style="color: blue">set</span>;
    }

    <span style="color: blue">public string </span>UserName {
        <span style="color: blue">get</span>;
        <span style="color: blue">set</span>;
    }
}</pre>
<p><a href="http://11011.net/software/vspaste"></a></p>
<p>还有行为过滤器的代码：</p>
<pre class="code"><span style="color: blue">public class </span><span style="color: #2b91af">UserNameFilter </span>: <span style="color: #2b91af">ActionFilterAttribute </span>{
    <span style="color: blue">public override void </span>OnActionExecuting(<span style="color: #2b91af">ActionExecutingContext </span>filterContext) {
        <span style="color: blue">const string </span>Key = <span style="color: #a31515">"userName"</span>;

        <span style="color: blue">if </span>(filterContext.ActionParameters.ContainsKey(Key)) {
            <span style="color: blue">if </span>(filterContext.HttpContext.User.Identity.IsAuthenticated) {
                filterContext.ActionParameters[Key] = filterContext.HttpContext.User.Identity.Name;
            }
        }

        <span style="color: blue">base</span>.OnActionExecuting(filterContext);
    }
}

<span style="color: blue">public class </span><span style="color: #2b91af">ViewModelUserFilter </span>: <span style="color: #2b91af">ActionFilterAttribute </span>{
    <span style="color: blue">public override void </span>OnActionExecuted(<span style="color: #2b91af">ActionExecutedContext </span>filterContext) {
        ViewModel model;

        <span style="color: blue">if </span>(filterContext.Controller.ViewData.Model == <span style="color: blue">null</span>) {
            model = <span style="color: blue">new </span>ViewModel();
            filterContext.Controller.ViewData.Model = model;
        } <span style="color: blue">else </span>{
            model = filterContext.Controller.ViewData.Model <span style="color: blue">as </span>ViewModel;
        }

        <span style="color: blue">if </span>(model != <span style="color: blue">null</span>) {
            model.IsUserAuthenticated = filterContext.HttpContext.User.Identity.IsAuthenticated;

            <span style="color: blue">if </span>(model.IsUserAuthenticated) {
                model.UserName = filterContext.HttpContext.User.Identity.Name;
            }
        }

        <span style="color: blue">base</span>.OnActionExecuted(filterContext);
    }
}</pre>
<p><a href="http://11011.net/software/vspaste"></a></p>
<p>正如你所看到的，如果在控制器里预先设定它的话，它并没有替换模型，而是在它发现模型与它符合的时候，才作为控制器的公共部分起作用。另一个好处是，由于视图只依赖于父类层，你可以不必返回具体的model，而只需要返回 View()。</p>
<p>继续阅读：《<a rel="prev" href="http://wukangrui.net/2009/07/07/asp-net-mvc-best-practices-part-1-2.html">ASP.NET MVC 最佳实践（三）</a>》</p>
<h3  class="related_post_title">相关日志</h3><ul class="related_post"><li>2009-07-08 -- <a href="http://wukangrui.com/2009/07/08/asp-net-mvc-best-practices-part-4.html" title="ASP.NET MVC 最佳实践（四）">ASP.NET MVC 最佳实践（四）</a></li><li>2009-07-07 -- <a href="http://wukangrui.com/2009/07/07/asp-net-mvc-best-practices-part-3.html" title="ASP.NET MVC 最佳实践（三）">ASP.NET MVC 最佳实践（三）</a></li><li>2009-06-28 -- <a href="http://wukangrui.com/2009/06/28/asp-net-mvc-best-practices-part-1.html" title="ASP.NET MVC 最佳实践（一）">ASP.NET MVC 最佳实践（一）</a></li><li>2009-04-13 -- <a href="http://wukangrui.com/2009/04/13/aspnetmvc-hands-on-labs-develop-application.html" title="[翻译]ASP.NET MVC动手实验1-3：开发ASP.NET MVC应用">[翻译]ASP.NET MVC动手实验1-3：开发ASP.NET MVC应用</a></li><li>2009-04-09 -- <a href="http://wukangrui.com/2009/04/09/aspnetmvc-hands-on-labs-create-application.html" title="[翻译]ASP.NET MVC动手实验1-2：创建ASP.NET MVC应用">[翻译]ASP.NET MVC动手实验1-2：创建ASP.NET MVC应用</a></li><li>2009-04-09 -- <a href="http://wukangrui.com/2009/04/09/aspnetmvc-hands-on-labs-introduction.html" title="[翻译]ASP.NET MVC动手系列1-1：ASP.NET MVC概述">[翻译]ASP.NET MVC动手系列1-1：ASP.NET MVC概述</a></li><li>2009-07-05 -- <a href="http://wukangrui.com/2009/07/05/php-5-3-0-release-new-feature.html" title="PHP 5.3.0 发布">PHP 5.3.0 发布</a></li><li>2009-06-22 -- <a href="http://wukangrui.com/2009/06/22/whatever-hover-pseudo-class-without-javascript.html" title="Whatever:hover &#8211; 无需javascript让IE支持丰富伪类">Whatever:hover &#8211; 无需javascript让IE支持丰富伪类</a></li><li>2009-04-30 -- <a href="http://wukangrui.com/2009/04/30/solution-for-js-intellisense-error.html" title="VS2008 中 JS IntelliSense出错的解决">VS2008 中 JS IntelliSense出错的解决</a></li><li>2008-06-22 -- <a href="http://wukangrui.com/2008/06/22/api-bug-in-powereasy-siteweaver-part2.html" title="动易SW中的一个严重但不影响使用的bug（二）">动易SW中的一个严重但不影响使用的bug（二）</a></li></ul>]]></content:encoded>
			<wfw:commentRss>http://wukangrui.com/2009/07/01/asp-net-mvc-best-practices-part-2.html/feed</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>ASP.NET MVC 最佳实践（一）</title>
		<link>http://wukangrui.com/2009/06/28/asp-net-mvc-best-practices-part-1.html</link>
		<comments>http://wukangrui.com/2009/06/28/asp-net-mvc-best-practices-part-1.html#comments</comments>
		<pubDate>Sun, 28 Jun 2009 06:18:23 +0000</pubDate>
		<dc:creator>小李刀刀</dc:creator>
				<category><![CDATA[所谓技术]]></category>
		<category><![CDATA[ASP.NET]]></category>
		<category><![CDATA[MVC]]></category>
		<category><![CDATA[开发]]></category>
		<category><![CDATA[最佳实践]]></category>
		<category><![CDATA[翻译]]></category>

		<guid isPermaLink="false">http://wukangrui.net/2009/06/28/asp-net-mvc-best-practices-part-1.html</guid>
		<description><![CDATA[本系列翻译自 Kazi Manzur Rashid 的博客，由于翻译水平有限，本系列可能存在误解偏差或者翻译不准的地方，建议对比原文进行阅读。由于篇幅关系，原文中的一篇文章在本系列中将拆解成多篇发布。本篇包括原文第一部分中的1-6节。]]></description>
			<content:encoded><![CDATA[<p><em>本系列翻译自 </em><a rel="external" href="http://weblogs.asp.net/rashid/default.aspx" target="_blank"><em>Kazi Manzur Rashid</em></a><em> 的博客，由于翻译水平有限，本系列可能存在误解偏差或者翻译不准的地方，建议对比<a rel="external" href="http://weblogs.asp.net/rashid/archive/2009/04/01/asp-net-mvc-best-practices-part-1.aspx" target="_blank">原文</a>进行阅读。由于篇幅关系，原文中的一篇文章在本系列中将拆解成多篇发布。本篇包括原文第一部分中的1-6节。</em></p>
<p><span id="more-821"></span></p>
<h4>1. 创建UrlHelper的扩展方法来生成url</h4>
<p>尽量避免以字符串方式直接传递controller, action 或者 route name，最好是为创建为UrlHelper创建扩展方法来封装url。例如：</p>
<pre class="code"><span style="color: blue">public static class </span><span style="color: #2b91af">UrlHelperExtension </span>{
    <span style="color: blue">public static string </span>Home(<span style="color: blue">this </span>UrlHelper helper) {
        <span style="color: blue">return </span>helper.Content(<span style="color: #a31515">"~/"</span>);
    }

    <span style="color: blue">public static string </span>SignUp(<span style="color: blue">this </span>UrlHelper helper) {
        <span style="color: blue">return </span>helper.RouteUrl(<span style="color: #a31515">"Signup"</span>);
    }

    <span style="color: blue">public static string </span>Dashboard(<span style="color: blue">this </span>UrlHelper helper) {
        <span style="color: blue">return </span>Dashboard(helper, StoryListTab.Unread);
    }

    <span style="color: blue">public static string </span>Dashboard(<span style="color: blue">this </span>UrlHelper helper, StoryListTab tab) {
        <span style="color: blue">return </span>Dashboard(helper, tab, OrderBy.CreatedAtDescending, 1);
    }

    <span style="color: blue">public static string </span>Dashboard(<span style="color: blue">this </span>UrlHelper helper, StoryListTab tab, OrderBy orderBy, <span style="color: blue">int </span>page) {
        <span style="color: blue">return </span>helper.RouteUrl(<span style="color: #a31515">"Dashboard"</span>, <span style="color: blue">new </span>{ tab = tab.ToString(), orderBy = orderBy.ToString(), page });
    }

    <span style="color: blue">public static string </span>Update(<span style="color: blue">this </span>UrlHelper helper) {
        <span style="color: blue">return </span>helper.RouteUrl(<span style="color: #a31515">"Update"</span>);
    }

    <span style="color: blue">public static string </span>Submit(<span style="color: blue">this </span>UrlHelper helper) {
        <span style="color: blue">return </span>helper.RouteUrl(<span style="color: #a31515">"Submit"</span>);
    }
}</pre>
<p>这样，如果在你的视图中有类似这样的代码：</p>
<pre class="code">    <span style="background: #ffee62">&lt;%</span><span style="color: blue">= </span>Html.ActionLink(<span style="color: #a31515">"Dashboard"</span>, <span style="color: #a31515">"Dashboard"</span>, <span style="color: #a31515">"Story"</span>) <span style="background: #ffee62">%&gt;
</span>    <span style="color: blue">&lt;</span><span style="color: #a31515">a </span><span style="color: red">href</span><span style="color: blue">="</span><span style="background: #ffee62">&lt;%</span>= Url.RouteUrl("Profile")<span style="background: #ffee62">%&gt;</span><span style="color: blue">"&gt;</span>Profile<span style="color: blue">&lt;/</span><span style="color: #a31515">a</span><span style="color: blue">&gt;</span></pre>
<p>你就可以用下面的这种方式来代替它们：</p>
<p><a href="http://11011.net/software/vspaste"></a></p>
<pre class="code"><span style="color: blue">&lt;</span><span style="color: #a31515">a </span><span style="color: red">href</span><span style="color: blue">="</span><span style="background: #ffee62">&lt;%</span>= Url.Dashboard() <span style="background: #ffee62">%&gt;</span><span style="color: blue">"&gt;</span>Dashboard<span style="color: blue">&lt;/</span><span style="color: #a31515">a</span><span style="color: blue">&gt;
&lt;</span><span style="color: #a31515">a </span><span style="color: red">href</span><span style="color: blue">="</span><span style="background: #ffee62">&lt;%</span>= Url.Profile() <span style="background: #ffee62">%&gt;</span><span style="color: blue">"&gt;</span>Profile<span style="color: blue">&lt;/</span><span style="color: #a31515">a</span><span style="color: blue">&gt;</span></pre>
<p><a href="http://11011.net/software/vspaste"></a></p>
<p>在控制器里也可以用，原来的代码：</p>
<pre class="code"><span style="color: blue">return </span>RedirectToAction(
    <span style="color: #a31515">"Dashboard"</span>,
    <span style="color: #a31515">"Story"</span>,
    <span style="color: blue">new </span>{
        tab = StoryListTab.Favorite,
        orderBy = OrderBy.CreatedAtAscending,
        page = 1
    }
);</pre>
<p>可以写成：</p>
<pre class="code"><span style="color: blue">return </span>Redirect(Url.Dashboard(StoryListTab.Favorite,
                                OrderBy.CreatedAtAscending, 1));</pre>
<p>当然了，你也可以使用 <a rel="external" href="http://www.tampadev.org/News/Details/DownloadASPNETMVCFuturesMicrosoftWebMvcAssembly" target="_blank">future assembly</a> 中的强类型版本来获得控制器、方法以及参数值，或者创建你自己的强类型版本以免将来进行重构时太过于痛苦，但是请一定记住，它没有官方支持并且将来有可能会发生改变。上面的方式也可以和强类型版本搭配使用。当然“另外增加一个间接层”（Scott Ha 喜欢用的引语）有一些好处，在编写单元测试的时候还有一个好处是你只需处理 <a rel="tag" href="http://msdn.microsoft.com/zh-cn/library/system.web.mvc.redirectresult.aspx" target="_blank">RedirectResult</a> 而无须同时处理 RedirectResult 和 <a rel="tag" href="http://msdn.microsoft.com/zh-cn/library/system.web.mvc.redirecttorouteresult.aspx" target="_blank">RedirectToRouteResult</a>。</p>
<h4>2. Create Extension Method of UrlHelper to map your JavaScript, Stylesheet and Image Folder</h4>
<p>默认情况下 <a rel="tag" href="http://www.asp.net/mvc/" target="_blank">ASP.NET MVC</a> 创建Content、Scripts文件夹来做这些事，这一点我不喜欢，我更喜欢下面的这种文件夹结构，这样在IIS里我可以只让静态文件缓存在Assets文件夹而不是多个文件夹：</p>
<ul>
<li>Assets</li>
<li>+images</li>
<li>+scripts</li>
<li>+stylesheets</li>
</ul>
<p>无论是结构是什么样的，还是要为UrlHelper创建一些扩展方法来映射这些文件夹，以便你在视图中可以很方便地指向它们，这样以后如果你要改变目录结构，你就无须做大量查找替换的工作。我还建议你为所有经常在视图中用到的资源创建UrlHelper的扩展方法。例如：</p>
<pre class="code"><span style="color: blue">public static string </span>Image(<span style="color: blue">this </span>UrlHelper helper, <span style="color: blue">string </span>fileName) {
    <span style="color: blue">return </span>helper.Content(<span style="color: #a31515">"~/assets/images/{0}"</span>.FormatWith(fileName));
}

<span style="color: blue">public static string </span>Stylesheet(<span style="color: blue">this </span>UrlHelper helper, <span style="color: blue">string </span>fileName) {
    <span style="color: blue">return </span>helper.Content(<span style="color: #a31515">"~/assets/stylesheets/{0}"</span>.FormatWith(fileName));
}

<span style="color: blue">public static string </span>NoIcon(<span style="color: blue">this </span>UrlHelper helper) {
    <span style="color: blue">return </span>Image(helper, <span style="color: #a31515">"noIcon.png"</span>);
}</pre>
<p><a href="http://11011.net/software/vspaste"></a></p>
<p>然后当需要用到这些路径的时候，原来的代码</p>
<pre class="code"><span style="color: blue">&lt;</span><span style="color: #a31515">link </span><span style="color: red">href</span><span style="color: blue">="../../Content/Site.css" </span><span style="color: red">rel</span><span style="color: blue">="stylesheet" </span><span style="color: red">type</span><span style="color: blue">="text/css" /&gt;</span></pre>
<p>就可以写成这样：<a href="http://11011.net/software/vspaste"></a></p>
<pre class="code"><span style="color: blue">&lt;</span><span style="color: #a31515">link </span><span style="color: red">href</span><span style="color: blue">="</span><span style="background: #ffee62">&lt;%</span>= Url.Stylesheet("site.css")<span style="background: #ffee62">%&gt;</span><span style="color: blue">" </span><span style="color: red">rel</span><span style="color: blue">="stylesheet" </span><span style="color: red">type</span><span style="color: blue">="text/css" /&gt;</span></pre>
<h4>3. 中使用启动加载器</h4>
<p>我在<a rel="prev" href="http://weblogs.asp.net/rashid/archive/2009/02/17/use-bootstrapper-in-your-asp-net-mvc-application-and-reduce-code-smell.aspx" target="_blank">以前的文章</a>中已经提到过这一点，总的来说就是：如果你要在 Global.asax 的 Application_Start 中做很多处理，比如 注册路由规则(Routers)、注册控制器工厂(Controller Factory)、模型绑定(Model Binders)、视图引擎(View Engine)、启动程序级的特定<a rel="external" href="http://weblogs.asp.net/rashid/archive/2009/03/05/use-event-aggregator-to-make-your-application-more-extensible.aspx" target="_blank">后台服务</a>或者为特定部分创建独立任务等，那就用<a rel="prev" href="http://weblogs.asp.net/rashid/archive/2009/03/05/use-event-aggregator-to-make-your-application-more-extensible.aspx" target="_blank">启动加载器</a>来执行这些操作。这会让你的代码更简洁，更可测。这一点在用 <a rel="tag" href="http://www.asp.net/mvc/" target="_blank">ASP.NET MVC</a> 构建门户级应用时尤其有用，因为这类应用中的每个模块都可能有一些不影响到其他模块的启动初始化操作。但是如果你只是开发一个小应用，上面提到的这些对你来说都不是问题，你当然也可以继续用默认的 global.asax。</p>
<h4>4. 不要硬编码对依赖注入容器的调用，用通用服务定位器来代替。</h4>
<p>不要让任何特定的依赖注入容器(DI Container)打乱你的代码，更好的办法是使用通用服务定位器(<a rel="external" href="http://commonservicelocator.codeplex.com/" target="_blank">Common Service Locator</a>)，它是对底层依赖注入进行的抽象，已经支持几乎所有流行的依赖注入容器，它让你可以任意替换底层的依赖注入对象而无须修改代码，因为每个依赖注入容器都具有一些不同于其它容器的特性。<a rel="external" href="http://devlicio.us/blogs/tim_barcz/" target="_blank">Tim Barcz</a> 最近写了一篇关于这个话题的<a rel="external" href="http://devlicio.us/blogs/tim_barcz/archive/2009/03/29/your-ioc-container-choice-is-not-a-feature-of-your-application.aspx" target="_blank">很棒的文章</a>，我不太明白他为什么没有提到我们对我们偏爱的依赖注入容器有多痴迷。通用服务定位器对绝大部分常用情景都提供了支持，而对一些特殊情况比如对已实体化对象的依赖注入，我印象里有 <a rel="external" href="http://codebetter.com/blogs/jeremy.miller/archive/2009/01/16/quot-buildup-quot-existing-objects-with-structuremap.aspx" target="_blank">StructureMap</a>、<a rel="external" href="http://codeclimber.net.nz/archive/2009/02/10/how-to-use-ninject-to-inject-dependencies-into-asp.net-mvc.aspx" target="_blank">Ninject</a> 和 Unity，你可以调用静态方法 ServiceLocator.Current.GetInstance 来代替。 通用服务定位器 是 <a rel="external" href="http://codebetter.com/blogs/jeremy.miller/archive/2008/08/16/it-s-time-for-ioc-container-detente.aspx" target="_blank">Jeremy D Miller</a> 发起的 依赖注入容器开发者(the DI Containers creators)的集体作品。</p>
<p>用通用服务定位器创建控制器工厂非常容易：</p>
<pre class="code"><span style="color: blue">public class </span><span style="color: #2b91af">CommonServiceLocatorControllerFactory </span>: <span style="color: #2b91af">DefaultControllerFactory </span>{
    <span style="color: blue">protected override </span><span style="color: #2b91af">IController </span>GetControllerInstance(<span style="color: #2b91af">Type </span>controllerType) {
        <span style="color: blue">return </span>(controllerType == <span style="color: blue">null</span>) ? <span style="color: blue">base</span>.GetControllerInstance(controllerType) : ServiceLocator.Current.GetInstance(controllerType) <span style="color: blue">as </span><span style="color: #2b91af">IController</span>;
    }
}</pre>
<p>我希望 MVCContrib 的成员们也用这样的方式，而不是为每个容器创建一个独立的控制器工厂。</p>
<h4>5. 用恰当的的AcceptVerbs属性来修饰你的控制器方法</h4>
<p><a rel="tag" href="http://www.asp.net/mvc/" target="_blank">ASP.NET MVC</a> 比 Web Forms 更容易遭受攻击。所以务必让对数据进行修改的控制器方法只接受 Post 方式请求（HttpVerbs.Post）。如果安全对你来说至关重要，你还可以用 ValidateAntiForgeryToken 或者 Captcha。我强烈推荐 <a rel="external" href="http://devlicio.us/blogs/derik_whittaker/" target="_blank">Derik Whittaker</a> 写的一篇 <a rel="external" href="http://devlicio.us/blogs/derik_whittaker/archive/2008/12/02/using-recaptcha-with-asp-net-mvc.aspx" target="_blank">很好的文章</a> 以及<a rel="external" href="http://www.dimecasts.net/Casts/CastDetails/76" target="_blank">视频</a>介绍了怎么把 reCaptcha 整合到 <a rel="tag" href="http://www.asp.net/mvc/" target="_blank">ASP.NET MVC</a> 应用程序（作者注：不要错过了 <a rel="external" href="http://www.dimecasts.net/" target="_blank">DimeCasts.net</a> 的另一个短片，我从中学到了很多）。我的经验法则是对所有数据修改方法使用 HttpVerbs.Post，对所有数据读取操作使用 HttpVerbs.Get。</p>
<h4>6. 用OutputCache修饰你的频繁调用的操作方法</h4>
<p>当你需要返回不频繁更新的数据时使用 OutputCache 属性，最常见的例子是首页、Feed等。你在返回Html以及Json数据类型的方法中都可以使用这个属性。在使用的时候，注意只指定CacheProfile参数，不要指定任何其它东西，用 web.config 输出缓存控制节可以很好地调整它。例如：</p>
<pre class="code">[<span style="color: #2b91af">AcceptVerbs</span>(<span style="color: #2b91af">HttpVerbs</span>.Get), <span style="color: #2b91af">OutputCache</span>(CacheProfile = <span style="color: #a31515">"Dashboard"</span>)]
<span style="color: blue">public </span><span style="color: #2b91af">ActionResult </span>Dashboard(<span style="color: blue">string </span>userName, StoryListTab tab, OrderBy orderBy, <span style="color: blue">int</span>? page) {
}</pre>
<p>在 web.config 文件中的配置：<a href="http://11011.net/software/vspaste"></a></p>
<pre class="code"><span style="color: blue">&lt;</span><span style="color: #a31515">system.web</span><span style="color: blue">&gt;
    &lt;</span><span style="color: #a31515">caching</span><span style="color: blue">&gt;
        &lt;</span><span style="color: #a31515">outputCacheSettings</span><span style="color: blue">&gt;
            &lt;</span><span style="color: #a31515">outputCacheProfiles</span><span style="color: blue">&gt;
                &lt;</span><span style="color: #a31515">clear</span><span style="color: blue">/&gt;
                &lt;!-- </span><span style="color: green">15 Seconds </span><span style="color: blue">--&gt;
                &lt;</span><span style="color: #a31515">add
                    </span><span style="color: red">name</span><span style="color: blue">=</span>"<span style="color: blue">Dashboard</span>"
                    <span style="color: red">duration</span><span style="color: blue">=</span>"<span style="color: blue">15</span>"
                    <span style="color: red">varyByParam</span><span style="color: blue">=</span>"<span style="color: blue">*</span>"
                    <span style="color: red">location</span><span style="color: blue">=</span>"<span style="color: blue">Client</span>"
                    <span style="color: blue">/&gt;
            &lt;/</span><span style="color: #a31515">outputCacheProfiles</span><span style="color: blue">&gt;
        &lt;/</span><span style="color: #a31515">outputCacheSettings</span><span style="color: blue">&gt;
    &lt;/</span><span style="color: #a31515">caching</span><span style="color: blue">&gt;
&lt;/</span><span style="color: #a31515">system.web</span><span style="color: blue">&gt;</span></pre>
<p>请继续阅读：《<a rel="next" href="http://wukangrui.net/2009/07/01/asp-net-mvc-best-practices-part-2.html">ASP.NET MVC 最佳实践（二）</a>》</p>
<h3  class="related_post_title">相关日志</h3><ul class="related_post"><li>2009-07-08 -- <a href="http://wukangrui.com/2009/07/08/asp-net-mvc-best-practices-part-4.html" title="ASP.NET MVC 最佳实践（四）">ASP.NET MVC 最佳实践（四）</a></li><li>2009-07-07 -- <a href="http://wukangrui.com/2009/07/07/asp-net-mvc-best-practices-part-3.html" title="ASP.NET MVC 最佳实践（三）">ASP.NET MVC 最佳实践（三）</a></li><li>2009-07-01 -- <a href="http://wukangrui.com/2009/07/01/asp-net-mvc-best-practices-part-2.html" title="ASP.NET MVC 最佳实践（二）">ASP.NET MVC 最佳实践（二）</a></li><li>2009-04-13 -- <a href="http://wukangrui.com/2009/04/13/aspnetmvc-hands-on-labs-develop-application.html" title="[翻译]ASP.NET MVC动手实验1-3：开发ASP.NET MVC应用">[翻译]ASP.NET MVC动手实验1-3：开发ASP.NET MVC应用</a></li><li>2009-04-09 -- <a href="http://wukangrui.com/2009/04/09/aspnetmvc-hands-on-labs-create-application.html" title="[翻译]ASP.NET MVC动手实验1-2：创建ASP.NET MVC应用">[翻译]ASP.NET MVC动手实验1-2：创建ASP.NET MVC应用</a></li><li>2009-04-09 -- <a href="http://wukangrui.com/2009/04/09/aspnetmvc-hands-on-labs-introduction.html" title="[翻译]ASP.NET MVC动手系列1-1：ASP.NET MVC概述">[翻译]ASP.NET MVC动手系列1-1：ASP.NET MVC概述</a></li><li>2009-07-05 -- <a href="http://wukangrui.com/2009/07/05/php-5-3-0-release-new-feature.html" title="PHP 5.3.0 发布">PHP 5.3.0 发布</a></li><li>2009-06-22 -- <a href="http://wukangrui.com/2009/06/22/whatever-hover-pseudo-class-without-javascript.html" title="Whatever:hover &#8211; 无需javascript让IE支持丰富伪类">Whatever:hover &#8211; 无需javascript让IE支持丰富伪类</a></li><li>2009-04-30 -- <a href="http://wukangrui.com/2009/04/30/solution-for-js-intellisense-error.html" title="VS2008 中 JS IntelliSense出错的解决">VS2008 中 JS IntelliSense出错的解决</a></li><li>2008-06-22 -- <a href="http://wukangrui.com/2008/06/22/api-bug-in-powereasy-siteweaver-part2.html" title="动易SW中的一个严重但不影响使用的bug（二）">动易SW中的一个严重但不影响使用的bug（二）</a></li></ul>]]></content:encoded>
			<wfw:commentRss>http://wukangrui.com/2009/06/28/asp-net-mvc-best-practices-part-1.html/feed</wfw:commentRss>
		<slash:comments>3</slash:comments>
		</item>
		<item>
		<title>Whatever:hover &#8211; 无需javascript让IE支持丰富伪类</title>
		<link>http://wukangrui.com/2009/06/22/whatever-hover-pseudo-class-without-javascript.html</link>
		<comments>http://wukangrui.com/2009/06/22/whatever-hover-pseudo-class-without-javascript.html#comments</comments>
		<pubDate>Mon, 22 Jun 2009 15:50:40 +0000</pubDate>
		<dc:creator>小李刀刀</dc:creator>
				<category><![CDATA[所谓技术]]></category>
		<category><![CDATA[CSS]]></category>
		<category><![CDATA[javascript]]></category>
		<category><![CDATA[网页]]></category>
		<category><![CDATA[翻译]]></category>

		<guid isPermaLink="false">http://wukangrui.net/2009/06/22/whatever-hover-pseudo-class-without-javascript.html</guid>
		<description><![CDATA[绝大部分现代浏览器支持 css 中的 :hover 伪类选择器，可以用于所有 html 元素。这很酷，因为这使你可以仅通过 css 来对表格行(&#60;tr&#62;)应用鼠标滑过事件(mouseover)时的特殊效果。然而，万恶的IE，对 :hover 伪类顶多只提供了有限的支持，具体支持的程度要取决于你的IE浏览器的具体版本。
Whatever:hover 是一个小小的脚本，它可以迅速、自动地为IE6，IE7，IE8添加标准的 :hover、:active 和 :focus 伪类支持。第三版引入了 ajax 支持，意味着通过 javascript 动态添加到文档中的任意html元素也同样可以在IE中响应 :hover、:active 和 :focus 样式。
 
如果你已经对使用 whatever:hover 很熟练，现在只是想下载它，你可以直接跳转到获取最新版本。而对于其它想深入了解它的人，请继续阅读。
使用方法
你只需要将 whatever:hover 链接到 body 元素就可以了。注意这里的 behavior 属性中的 URL 是相对于 html 文件的，而不是像背景图片地址一样是相对于 css 文件的路径。
body { behavior: url(&#34;csshover3.htc&#34;); }
工作原理
所有的浏览器都提供了一些方法，让你用 javascript 查询样式表中定义好的规则或者动态地插入新规则。正常情况下，IE 对所有它不支持的规则返回 “unknown”。例如：一条关于 “div p:first-child” 的规则将会被改成 &#34;div p:unknown”， 而一条关于 &#34;p a[href]” [...]]]></description>
			<content:encoded><![CDATA[<p>绝大部分现代浏览器支持 css 中的 :hover 伪类选择器，可以用于所有 html 元素。这很酷，因为这使你可以仅通过 css 来对表格行(&lt;tr&gt;)应用鼠标滑过事件(mouseover)时的特殊效果。然而，万恶的IE，对 :hover 伪类顶多只提供了有限的支持，具体支持的程度要取决于你的IE浏览器的具体版本。</p>
<p>Whatever:hover 是一个小小的脚本，它可以迅速、自动地为IE6，IE7，IE8添加标准的 :hover、:active 和 :focus 伪类支持。第三版引入了 ajax 支持，意味着通过 javascript 动态添加到文档中的任意html元素也同样可以在IE中响应 :hover、:active 和 :focus 样式。</p>
<p> <span id="more-776"></span>
<p>如果你已经对使用 whatever:hover 很熟练，现在只是想下载它，你可以直接跳转到<a href="#changes" rel="enclosure">获取最新版本</a>。而对于其它想深入了解它的人，请继续阅读。</p>
<h3>使用方法</h3>
<p>你只需要将 whatever:hover 链接到 body 元素就可以了。注意这里的 behavior 属性中的 URL 是相对于 html 文件的，而不是像背景图片地址一样是相对于 css 文件的路径。</p>
<pre class="code"><span style="color: #a31515">body </span>{ <span style="color: red">behavior</span>: <span style="color: blue">url(&quot;csshover3.htc&quot;)</span>; }</pre>
<h3>工作原理</h3>
<p>所有的浏览器都提供了一些方法，让你用 javascript 查询样式表中定义好的规则或者动态地插入新规则。正常情况下，IE 对所有它不支持的规则返回 “unknown”。例如：一条关于 “div p:first-child” 的规则将会被改成 &quot;div p:unknown”， 而一条关于 &quot;p a[href]” 的规则将整体地作为 &quot;unknown&quot; 返回。幸运的是 IE 把 :hover 伪类认为是它支持的样式规则，并且会将它保持原样。</p>
<p>IE 还支持所谓的<a title="Internet Explorer 行为" href="http://msdn.microsoft.com/zh-cn/library/ms531078.aspx" rel="external" target="_blank">行为（behaviors）</a>，不仅包括预定义的功能比如动态加载内容或者持续数据存储，也包括你可以在一个后缀为 .htc 或者 .hta 为的文件中创建的自定义行为。这些行为通过 css 实现与 html 节点关联，并“增强”这些被指定行为中的样式选择器选中的节点。</p>
<p>综上所述，创建一个行为来查找样式表中 IE 不支持的元素，并以一些其它手段“欺骗”影响的到元素让它们应用样式表中关联的样式。这个复杂的操作中包含的步骤大致可以描述为：</p>
<ul>
<li>在所有的样式表中搜索 IE 不支持的 :hover 伪类规则； </li>
<li>插入一条 IE 支持的，例如带 class 名称的新规则； </li>
<li>最后，设置脚本事件来切换目标元素的 class 名称。 </li>
</ul>
<p>通过这种方式，:hover、:active 和 :focus 就可以得到（IE 的）支持了。而作为开发人员，你除了包含这个行为以外不需要做任何事。所有的工作都将自动完成。</p>
<p>与第1版和第2版比较，第3版对动态加入的 html (ajax) 也同样支持。另外还有一个改动是原来第1版和第2版采用的是在页面加载事件中主动搜索影响到的元素，而在第3版中改为借助表达式（<a title="MSDN - 动态属性" href="http://msdn.microsoft.com/zh-cn/library/ms537634.aspx" rel="external" target="_blank">expressions</a>）让节点自己回调。关于这部分你可以阅读带注释的版本获取更多细节。</p>
<h3>示例：菜单效果</h3>
<p>:hover 一个很常见的用途就是用列表创建菜单系统。用这个行为来创建一个两级的菜单系统是再容易不过的事情了。例如，如果你从 <a title="suckerfish dropdown" href="http://www.htmldog.com/articles/suckerfish/example/" rel="external" target="_blank">suckerfish dropdown</a> （一个带有下拉菜单的网页，关于这个页面和效果的描述，参见 <a href="http://www.alistapart.com/articles/dropdowns/" rel="external" target="_blank">A List Apart article</a>）上把 javascript 删除掉了，它仍然能正常工作。</p>
<p>但是多级的菜单需要做不同的处理。这是由于 IE 不支持子选择符 ‘&gt;’，子选择符可以完美地显示下级子菜单，而不是连更深层的菜单一起显示出来。</p>
<pre class="code"><span style="color: #a31515">li:hover &gt; ul </span>{ <span style="color: green">/* 在 IE 下无效 */ </span>}</pre>
<p>有一种可供选择的方法可以只使用简单的子孙选择符来模拟这种行为（主要是针对 IE）。还有种不太成熟的方法是应用多个类定义，但是更简单的方法是利用 CSS 选择符的不同<a href="http://www.w3.org/TR/CSS21/cascade.html#specificity" rel="external" target="_blank">优先级(specificity)</a>.每一条 css 规则都有特定的重要等级，这个等级可以简单地根据一条规则中的不同元素来计算。以元素名称为基准值 “1″，类、伪类和属性选择符重要性（权重）为 “10″，然后元素 id 为 “100″。比如下面的例子。</p>
<pre class="code"><span style="color: #a31515">ul ul </span>{ <span style="color: red">display</span>:<span style="color: blue">none</span>; }
<span style="color: #a31515">li:hover ul </span>{ <span style="color: red">display</span>:<span style="color: blue">block</span>; }</pre>
<p>这样做能够生效的原因，就是选择符的优先级不同。第一条规则只包含两个元素名称，这样它的权重值（优先级）就是2。第二条规则也包含两个元素名称，但是 :hover 伪类的权重值（优先级）是10，所以加起来的值就是12。由于第二条规则比第一条规则优先，因此被鼠标滑过的 li 元素内部的 ul 将被显示。</p>
<p>那么这个对于解决 &gt; 子选择符的问题有什么帮助呢？是这样，如果一条权重值（优先级）为12的规则定义所有的子菜单都要显示，我们只需要创建一条权重值（优先级）大于12的规则来把下一级的菜单隐藏起来。然后，那个菜单又需要另一条优先级更高的规则来显示，一直循环下去。对于3级的导航来说，需要的 css 代码短得让人意外：</p>
<pre class="code"><span style="color: green">/* 2 和 13 */
</span><span style="color: #a31515">ul ul</span>, <span style="color: #a31515">li:hover ul ul </span>{ <span style="color: red">display</span>:<span style="color: blue">none</span>; }
<span style="color: green">/* 12 和 23*/
</span><span style="color: #a31515">li:hover ul</span>, <span style="color: #a31515">li:hover li:hover ul </span>{ <span style="color: red">display</span>:<span style="color: blue">block</span>; }</pre>
<p>这种方式可以无需附加任何类样式实现无限级嵌套菜单（4级或更多级需要需要继续添加更多规则）。</p>
<h3><a name="optimizing"></a>脚本事件的性能优化</h3>
<p>现在还剩下一件事需要考虑。.htc 文件在所有样式表文件中搜索 :hover 规则，并且按照 css 文件的定义对所有它认为需要用脚本处理停留效果的元素附加鼠标滑过和移出事件。为了找出这些(被影响的)元素，<strong>所有</strong>去掉 :hover 伪类选择到的元素以及被 :hover 伪类修饰的元素本身，都会被选择并且进行处理。一条类似这样的规则</p>
<pre class="code"><span style="color: #a31515">#menu li:hover ul </span>{ ... }</pre>
<p>…将会被调整成下面这样来查找所有可能需要响应鼠标滑过事件的元素：</p>
<pre class="code"><span style="color: #a31515">#menu li  </span>{ ... }</pre>
<p>很显然这会选中整个菜单中的每一个 &lt;li&gt; 元素，并对其中一大堆不需要鼠标事件（在当前情况下）的元素附加事件。这个问题可以很轻松地得到解决，我们可以对包含子菜单的列表元素添加一个类样式，比如 &quot;folder&quot;。这样一来，调整（去除:hover）之后的样式规则变成了</p>
<pre class="code"><span style="color: #a31515">#menu li.folder </span>{ ... }</pre>
<p>…可以高效地直接选中那些真正需要事件的元素。缺点是为了改善脚本的性能，你需要添加一个类样式（这个类样式的添加纯粹是为了视觉效果，而且放弃了 li:hover 方式实现菜单的通用性）。但是，从另一个角度考虑的话，也许你反正也要用一个类来把这些列表元素与普通元素区别开来，那就无所谓了。</p>
<p>为了直观地说明上述问题，请查看<a title="the combined example" href="http://www.xs4all.nl/examples/cssmenu.html" rel="external" target="_blank">综合示例</a>。希望你喜欢。</p>
<h3>文件下载及更新说明：</h3>
<p><a name="changes"></a><strong>文件下载:</strong></p>
<p><strong>v3.00.081222 </strong>(:hover, :active 和 :focus)</p>
<p><a href="http://www.xs4all.nl/htc/csshover3.htc" rel="enclosure" target="_blank">下载 (已压缩, 2.5K)</a> | <a href="http://www.xs4all.nl/htc/csshover3-source.htc">下载 (源码, 9K) </a>| <a href="view-source:http://www.xs4all.nl/~peterned/htc/csshover3-source.htc" rel="external" target="_blank">查看</a></p>
<p><strong>v1.42.060206</strong> (:hover 和 :active) <a href="http://www.xs4all.nl/htc/csshover.htc" rel="enclosure" target="_blank">下载</a> | <a href="view-source:http://www.xs4all.nl/~peterned/htc/csshover.htc" rel="external">查看</a></p>
<p><strong>v2.02.060206</strong> (:hover, :active 和 :focus) <a href="http://www.xs4all.nl/htc/csshover2.htc" rel="enclosure" target="_blank">下载</a> | <a href="view-source:http://www.xs4all.nl/~peterned/htc/csshover2.htc" rel="external">查看</a></p>
<p><strong>说明:</strong></p>
<p><em>说明1：如果在使用 whatever:hover 的过程中遇到问题，请 <a href="http://www.xs4all.nl/contact.html" rel="nofollow" target="_blank">让我知道</a>! <img alt=":)" src="http://wukangrui.net/wp-includes/images/smilies/icon_smile.gif" /> 由于第3版比较新，可能会存在一些无法预知的问题。</em></p>
<p><em>说明2：确保你的web服务器把 htc 文件按照 text/x-component 的 mime类型发送。关于这方面的更多信息，可以参阅 Aldo的个人博客。如果你的主机支持 .htaccess 文件，可以添加下面这行代码： </em></p>
<pre class="code"><span style="color: #a31515">AddType text</span>/<span style="color: #a31515">x-component .htc</span></pre>
<p><a href="http://11011.net/software/vspaste"></a></p>
<p><em>说明3：第三版支持在 IE6 以上版本中使用 :hover 和 :active，对 IE7 和 IE8 还支持 :focus。由于表达式（expression)在 IE8 标准模式下不支持，所以 whatever:hover 只在 IE8 的 怪异模式(Quirks Mode) 下运行。实际上在 IE8 标准模式中也根本不需要这个脚本了。 </em></p>
<p><em>说明4：如果使用这个脚本之后网页变慢，请尝试对更加具体的选择符运用 :hover 伪类，比如添加元素名称、使用元素id，或者类名称。例如：&quot;div#someId li.group:hover”, 而不要只用 &quot;.group:hover”。这样能够很大程度上减少搜索和解析时间，并能减少需要应用的事件。请阅读 <a href="#optimizing" rel="tag">性能优化</a> 获得更多信息。</em></p>
<p><em>说明5：第2版也支持 :focus 伪类，仅限于 A、INPUT、和 TEXTAREA元素。但是，由于类似 &quot;input:focus&quot; 这样的选择符被 IE 的样式表对象返回为 &quot;input:unknown&quot;，脚本将基于这些 &quot;unkonwn&quot; 规则来附加获得焦点和失去焦点事件，这个问题同样存在于其它浏览器无法识别的伪类。因此，使用2.0版本的时候，你无法在 IE 中对 A、INPUT和 TEXTAREA 元素应用浏览器无法识别的伪类，因为他们统统都会被处理成获得焦点样式。如果你确实需要这个功能，请使用1.4版或者3.0版。</em></p>
<p>在 <a href="http://www.naarvoren.nl">Naar Voren</a> （一个关于web开发的德语网站）上，有我用德语写的一篇关于用纯css <a href="http://www.naarvoren.nl/artikel/hover.html" rel="external" target="_blank">在菜单系统中使用 :hover</a> 的更详细的文章（德语版）。对于不懂德语的网友，可以查看该文章的<a href="http://www.xs4all.nl/hovercraft.html" rel="external" target="_blank">英文翻译版</a>。</p>
<p>非常感谢 Arnoud Berendsen 和 <a href="http://www.windgazer.nl/">Martin Reurings</a> 提供的创意和支持，感谢 <a href="http://www.eend.nl/log/">Robert Jan Verkade</a> 和 Naar Voren 上的朋友们发表我的文章，还要感谢 <a href="http://www.meyerweb.com/">Eric Meyer</a> 对这个脚本给予支持和在他的书里提到我的这个网页（指 《<a href="http://www.china-pub.com/38007" rel="reference" target="_blank">Eric Meyer谈CSS（卷2）</a>》 第六章》——译者注）。</p>
<p>&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;</p>
<p>作者：<a href="http://www.xs4all.nl/~peterned/" rel="license" target="_blank">peter ned</a> 原文：<a title="whatever:hover" href="http://www.xs4all.nl/~peterned/csshover.html" rel="external" target="_blank">whatever:hover</a></p>
<p>译者：<a title="小李刀刀博客" href="http://wukangrui.net/" rel="license" target="_blank">小李刀刀</a> 首发：<a href="http://wukangrui.net/2009/06/22/whatever-hover-pseudo-class-without-javascript.html" rel="license" target="_blank">Whatever:hover &#8211; 无需javascript让IE支持丰富伪类</a></p>
<p>转载请注明出处。</p>
<h3  class="related_post_title">相关日志</h3><ul class="related_post"><li>2009-12-21 -- <a href="http://wukangrui.com/2009/12/21/web-developer-understand-css-box-model.html" title="web开发从头说起：理解css盒模型">web开发从头说起：理解css盒模型</a></li><li>2009-12-16 -- <a href="http://wukangrui.com/2009/12/16/web-developer-about-css-selector.html" title="前台开发从头说起：谈谈CSS选择符">前台开发从头说起：谈谈CSS选择符</a></li><li>2009-12-15 -- <a href="http://wukangrui.com/2009/12/15/web-developer-from-web-standard.html" title="前台开发从头说起：关于web标准化">前台开发从头说起：关于web标准化</a></li><li>2009-04-13 -- <a href="http://wukangrui.com/2009/04/13/portable-interchangeable-jquery-based-tabs.html" title="简单、通用的JQuery Tab实现">简单、通用的JQuery Tab实现</a></li><li>2006-04-04 -- <a href="http://wukangrui.com/2006/04/04/dynamic-mouse-event-of-image-transparency.html" title="动态实现指定图片半透明及鼠标事件">动态实现指定图片半透明及鼠标事件</a></li><li>2009-04-16 -- <a href="http://wukangrui.com/2009/04/16/best-practices-of-css-dropdown-menu.html" title="来自微软站点的纯CSS下拉菜单">来自微软站点的纯CSS下拉菜单</a></li><li>2009-04-09 -- <a href="http://wukangrui.com/2009/04/09/aspnetmvc-hands-on-labs-create-application.html" title="[翻译]ASP.NET MVC动手实验1-2：创建ASP.NET MVC应用">[翻译]ASP.NET MVC动手实验1-2：创建ASP.NET MVC应用</a></li><li>2006-03-28 -- <a href="http://wukangrui.com/2006/03/28/simulate-window-in-center-with-css.html" title="CSS:模拟Windows窗口及DIV居中">CSS:模拟Windows窗口及DIV居中</a></li><li>2005-12-12 -- <a href="http://wukangrui.com/2005/12/12/action-of-refactor-page-with-css.html" title="实践：用Div+CSS重构网页">实践：用Div+CSS重构网页</a></li><li>2005-11-29 -- <a href="http://wukangrui.com/2005/11/29/css-learn-in-action.html" title="CSS学习之综合运用">CSS学习之综合运用</a></li></ul>]]></content:encoded>
			<wfw:commentRss>http://wukangrui.com/2009/06/22/whatever-hover-pseudo-class-without-javascript.html/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Dreamweaver中的正则表达式</title>
		<link>http://wukangrui.com/2009/06/17/regular-expression-in-dreamweaver.html</link>
		<comments>http://wukangrui.com/2009/06/17/regular-expression-in-dreamweaver.html#comments</comments>
		<pubDate>Tue, 16 Jun 2009 16:20:12 +0000</pubDate>
		<dc:creator>小李刀刀</dc:creator>
				<category><![CDATA[所谓技术]]></category>
		<category><![CDATA[Dreamweaver]]></category>
		<category><![CDATA[技巧]]></category>
		<category><![CDATA[软件]]></category>

		<guid isPermaLink="false">http://wukangrui.net/2009/06/17/dreamweaver%e4%b8%ad%e7%9a%84%e6%ad%a3%e5%88%99%e8%a1%a8%e8%be%be%e5%bc%8f.html</guid>
		<description><![CDATA[编辑源代码的时候，经常会用到正则表达式（特别是清理别人的代码的时候）来搜索替换。但是在我用做网页设计的主工具的 Dreamweaver&#160; 里，我却一直用不好它的正则表达式，不管是查找还是替换，经常都是折腾半天把我搞郁闷了。
 
今天在 百度知道 上给人回答问题的时候，遇到一个要做复杂替换的问题，而且提问者明确说是在 Dreamweaver 里面做。我终于不懒了一次，上 adobe 的网站上查了一下。把 Dreamweaver 里面的正则表达式部分好好看了一遍。全部内容如下：
下表列出了在正则表达式中使用的特殊字符、其含义和用法示例。若要搜索包含该表中某一特殊字符的文本，请在特殊字符前面附加一个反斜杠，令其转义。例如，若要在 some conditions apply* 短语中搜索实际的星号，您的搜索模式应类似于：apply\*。如果您没有令星号转义，您将找到“apply”的所有匹配项（以及“appl”、“applyy”和“applyyy”的所有匹配项），而不只是后面跟有星号的那些匹配项。





字符


匹配


示例






^


输入或行的起始部分。


^T 与“This good earth”中的“T”匹配，但是与“Uncle Tom’s Cabin”无匹配内容




$


输入或行的结尾部分。


h$ 与“teach”中的“h”匹配，但是与“teacher”无匹配内容




*


0 个或多个前置字符。


um* 与“rum”中的“um”、“yummy”中的“umm”和“huge”中的“u”匹配




+


1 个或多个前置字符。


um+ 与“rum”中的“um”和“yummy”中的“umm”匹配，但是和“huge”无匹配内容




?


前置字符最多出现一次（即，指示前置字符是可选的）。


st?on 与“Johnson”中的“son”和“Johnston”中的“ston”匹配，但是与“Appleton”或“tension”无匹配内容




.


除换行符外的任何单字符。


.an 与“bran muffins can be tasty”短语中的“ran”和“can”匹配




x&#124;y


x 或 y。


FF0000&#124;0000FF 与 bgcolor=&#34;#FF0000&#34; 中的“FF0000”和 font color=&#34;#0000FF&#34; 中的“0000FF”匹配




{n}


恰好 n 个前置字符。


o{2} 与“loom”中的“oo”和“mooooo”中的前两个字母 o 匹配，但是与“money”无匹配内容




{n,m}


至少 n 个、至多 m 个前置字符。


F{2,4} 与“#FF0000”中的“FF”和“#FFFFFF”中的前四个字母 F 匹配




[abc]


用括号括起来的字符中的任何一个字符。用连字符指定某一范围的字符（例如，[a-f] 等效于 [abcdef]）。 


[e-g] [...]]]></description>
			<content:encoded><![CDATA[<p>编辑源代码的时候，经常会用到正则表达式（特别是清理别人的代码的时候）来搜索替换。但是在我用做网页设计的主工具的 <a title="Dreamweaver 产品主页" href="http://www.adobe.com/products/dreamweaver/" rel="nofollow" target="_blank">Dreamweaver</a>&#160; 里，我却一直用不好它的正则表达式，不管是查找还是替换，经常都是折腾半天把我搞郁闷了。</p>
<p> <span id="more-680"></span>
<p>今天在 <a title="百度一下，你就知道" href="http://zhidao.baidu.com/" rel="nofollow" target="_blank">百度知道</a> 上给人回答问题的时候，遇到一个要做复杂替换的问题，而且提问者明确说是在 <a title="Dreamweaver 产品主页" href="http://www.adobe.com/products/dreamweaver/" rel="nofollow" target="_blank">Dreamweaver</a> 里面做。我终于不懒了一次，上 <a title="Adobe主页" href="http://www.adobe.com/" rel="nofollow" target="_blank">adobe</a> 的网站上查了一下。把 <a title="Dreamweaver 产品主页" href="http://www.adobe.com/products/dreamweaver/" rel="nofollow" target="_blank">Dreamweaver</a> 里面的正则表达式部分好好看了一遍。全部内容如下：</p>
<p>下表列出了在正则表达式中使用的特殊字符、其含义和用法示例。若要搜索包含该表中某一特殊字符的文本，请在特殊字符前面附加一个反斜杠，令其转义。例如，若要在 <samp class="codeph">some conditions apply*</samp> 短语中搜索实际的星号，您的搜索模式应类似于：<dfn class="term">apply\*</dfn>。如果您没有令星号转义，您将找到“apply”的所有匹配项（以及“appl”、“applyy”和“applyyy”的所有匹配项），而不只是后面跟有星号的那些匹配项。</p>
<div class="tablenoborder">
<table border="1" cellspacing="0" cellpadding="4">
<thead align="left">
<tr>
<th id="d17e26803" valign="top">
<p>字符</p>
</th>
<th id="d17e26806" valign="top">
<p>匹配</p>
</th>
<th id="d17e26809" valign="top">
<p>示例</p>
</th>
</tr>
</thead>
<tbody>
<tr>
<td valign="top" headers="d17e26803 ">
<p>^</p>
</td>
<td valign="top" headers="d17e26806 ">
<p>输入或行的起始部分。</p>
</td>
<td valign="top" headers="d17e26809 ">
<p><samp class="codeph">^T</samp> 与“This good earth”中的“T”匹配，但是与“Uncle Tom’s Cabin”无匹配内容</p>
</td>
</tr>
<tr>
<td valign="top" headers="d17e26803 ">
<p>$</p>
</td>
<td valign="top" headers="d17e26806 ">
<p>输入或行的结尾部分。</p>
</td>
<td valign="top" headers="d17e26809 ">
<p><samp class="codeph">h$</samp> 与“teach”中的“h”匹配，但是与“teacher”无匹配内容</p>
</td>
</tr>
<tr>
<td valign="top" headers="d17e26803 ">
<p>*</p>
</td>
<td valign="top" headers="d17e26806 ">
<p>0 个或多个前置字符。</p>
</td>
<td valign="top" headers="d17e26809 ">
<p><samp class="codeph">um*</samp> 与“rum”中的“um”、“yummy”中的“umm”和“huge”中的“u”匹配</p>
</td>
</tr>
<tr>
<td valign="top" headers="d17e26803 ">
<p>+</p>
</td>
<td valign="top" headers="d17e26806 ">
<p>1 个或多个前置字符。</p>
</td>
<td valign="top" headers="d17e26809 ">
<p><samp class="codeph">um+</samp> 与“rum”中的“um”和“yummy”中的“umm”匹配，但是和“huge”无匹配内容</p>
</td>
</tr>
<tr>
<td valign="top" headers="d17e26803 ">
<p>?</p>
</td>
<td valign="top" headers="d17e26806 ">
<p>前置字符最多出现一次（即，指示前置字符是可选的）。</p>
</td>
<td valign="top" headers="d17e26809 ">
<p><samp class="codeph">st?on</samp> 与“Johnson”中的“son”和“Johnston”中的“ston”匹配，但是与“Appleton”或“tension”无匹配内容</p>
</td>
</tr>
<tr>
<td valign="top" headers="d17e26803 ">
<p>.</p>
</td>
<td valign="top" headers="d17e26806 ">
<p>除换行符外的任何单字符。</p>
</td>
<td valign="top" headers="d17e26809 ">
<p><samp class="codeph">.an</samp> 与“bran muffins can be tasty”短语中的“ran”和“can”匹配</p>
</td>
</tr>
<tr>
<td valign="top" headers="d17e26803 ">
<p>x|y</p>
</td>
<td valign="top" headers="d17e26806 ">
<p>x 或 y。</p>
</td>
<td valign="top" headers="d17e26809 ">
<p><samp class="codeph">FF0000|0000FF</samp> 与 <samp class="codeph">bgcolor=&quot;#FF0000&quot;</samp> 中的“FF0000”和 <samp class="codeph">font color=&quot;#0000FF&quot;</samp> 中的“0000FF”匹配</p>
</td>
</tr>
<tr>
<td valign="top" headers="d17e26803 ">
<p>{n}</p>
</td>
<td valign="top" headers="d17e26806 ">
<p>恰好 n 个前置字符。</p>
</td>
<td valign="top" headers="d17e26809 ">
<p><samp class="codeph">o{2}</samp> 与“loom”中的“oo”和“mooooo”中的前两个字母 o 匹配，但是与“money”无匹配内容</p>
</td>
</tr>
<tr>
<td valign="top" headers="d17e26803 ">
<p>{n,m}</p>
</td>
<td valign="top" headers="d17e26806 ">
<p>至少 n 个、至多 m 个前置字符。</p>
</td>
<td valign="top" headers="d17e26809 ">
<p><samp class="codeph">F{2,4}</samp> 与“#FF0000”中的“FF”和“#FFFFFF”中的前四个字母 F 匹配</p>
</td>
</tr>
<tr>
<td valign="top" headers="d17e26803 ">
<p>[abc]</p>
</td>
<td valign="top" headers="d17e26806 ">
<p>用括号括起来的字符中的任何一个字符。用连字符指定某一范围的字符（例如，[a-f] 等效于 [abcdef]）。 </p>
</td>
<td valign="top" headers="d17e26809 ">
<p><samp class="codeph">[e-g]</samp> 与“bed”中的“e”、“folly”中的“f”和“guard”中的“g”匹配</p>
</td>
</tr>
<tr>
<td valign="top" headers="d17e26803 ">
<p>[^abc]</p>
</td>
<td valign="top" headers="d17e26806 ">
<p>未在括号中括起来的任何字符。用连字符指定某一范围的字符（例如，[^a-f] 等效于[^abcdef]）。</p>
</td>
<td valign="top" headers="d17e26809 ">
<p><samp class="codeph">[^aeiou]</samp> 最初与“orange”中的“r”、“book”中的“b”和“eek!”中的“k”匹配</p>
</td>
</tr>
<tr>
<td valign="top" headers="d17e26803 ">
<p>\b</p>
</td>
<td valign="top" headers="d17e26806 ">
<p>词边界（例如空格或回车符）。</p>
</td>
<td valign="top" headers="d17e26809 ">
<p><samp class="codeph">\bb</samp> 与“book”中的“b”匹配，但是与“goober”或“snob”无匹配内容</p>
</td>
</tr>
<tr>
<td valign="top" headers="d17e26803 ">
<p>\B</p>
</td>
<td valign="top" headers="d17e26806 ">
<p>词边界之外的任何内容。</p>
</td>
<td valign="top" headers="d17e26809 ">
<p><samp class="codeph">\Bb</samp> 与“goober”中的“b”匹配，但是与“book”无匹配内容</p>
</td>
</tr>
<tr>
<td valign="top" headers="d17e26803 ">
<p>\d</p>
</td>
<td valign="top" headers="d17e26806 ">
<p>任何数字字符。等效于 [0-9]。</p>
</td>
<td valign="top" headers="d17e26809 ">
<p><samp class="codeph">\d</samp> 与“C3PO”中的“3”和“apartment 2G”中的“2”匹配</p>
</td>
</tr>
<tr>
<td valign="top" headers="d17e26803 ">
<p>\D</p>
</td>
<td valign="top" headers="d17e26806 ">
<p>任何非数字字符。等效于 [^0-9]。</p>
</td>
<td valign="top" headers="d17e26809 ">
<p><samp class="codeph">\D</samp> 与“900S”中的“S”和“Q45”中的“Q”匹配</p>
</td>
</tr>
<tr>
<td valign="top" headers="d17e26803 ">
<p>\f</p>
</td>
<td valign="top" headers="d17e26806 ">
<p>换页符。</p>
</td>
<td valign="top" headers="d17e26809 ">&#160;</td>
</tr>
<tr>
<td valign="top" headers="d17e26803 ">
<p>\n</p>
</td>
<td valign="top" headers="d17e26806 ">
<p>换行符。</p>
</td>
<td valign="top" headers="d17e26809 ">&#160;</td>
</tr>
<tr>
<td valign="top" headers="d17e26803 ">
<p>\r</p>
</td>
<td valign="top" headers="d17e26806 ">
<p>回车符。</p>
</td>
<td valign="top" headers="d17e26809 ">&#160;</td>
</tr>
<tr>
<td valign="top" headers="d17e26803 ">
<p>\s</p>
</td>
<td valign="top" headers="d17e26806 ">
<p>任何单个空白字符，包括空格、制表符、换页符或换行符。</p>
</td>
<td valign="top" headers="d17e26809 ">
<p><samp class="codeph">\sbook</samp> 与“blue book”中的“book”匹配，但是与“notebook”无匹配内容</p>
</td>
</tr>
<tr>
<td valign="top" headers="d17e26803 ">
<p>\S</p>
</td>
<td valign="top" headers="d17e26806 ">
<p>任何单个非空白字符。</p>
</td>
<td valign="top" headers="d17e26809 ">
<p><samp class="codeph">\Sbook</samp> 与“notebook”中的“book”匹配，但是与“blue book”无匹配内容</p>
</td>
</tr>
<tr>
<td valign="top" headers="d17e26803 ">
<p>\t</p>
</td>
<td valign="top" headers="d17e26806 ">
<p>制表符。</p>
</td>
<td valign="top" headers="d17e26809 ">&#160;</td>
</tr>
<tr>
<td valign="top" headers="d17e26803 ">
<p>\w</p>
</td>
<td valign="top" headers="d17e26806 ">
<p>任何字母数字字符，包括下划线。等效于 [A-Za-z0-9_]。</p>
</td>
<td valign="top" headers="d17e26809 ">
<p>b\w* 与“the barking dog”中的“barking”以及“the big black dog”中的“big”和“black”匹配</p>
</td>
</tr>
<tr>
<td valign="top" headers="d17e26803 ">
<p>\W</p>
</td>
<td valign="top" headers="d17e26806 ">
<p>任何非字母数字字符。等效于 [^A-Za-z0-9_]。</p>
</td>
<td valign="top" headers="d17e26809 ">
<p>\W 与“Jake&amp;Mattie”中的“&amp;”和“100%”中的“%”匹配</p>
</td>
</tr>
<tr>
<td valign="top" headers="d17e26803 ">
<p>Ctrl+Enter 或 Shift+Enter (Windows)、或者 Ctrl+Return 或 Shift+Return 或 Command+ Return (Macintosh)</p>
</td>
<td valign="top" headers="d17e26806 ">
<p>回车符。确保如果没有使用正则表达式，则在搜索时取消对“忽略空白差别”的选择。请注意，该字符是特定字符，而不是一般意义上的换行符；例如，它并不是 <samp class="codeph">&lt;br&gt;</samp> 标签或 <samp class="codeph">&lt;p&gt;</samp> 标签。回车符在“设计”视图中显示为空格而不是换行符。</p>
</td>
<td valign="top" headers="d17e26809 ">&#160;</td>
</tr>
</tbody>
</table></div>
<p>使用括号在正则表达式内分隔出以后要引用的分组。然后在“替换”域中使用 $1、$2、$3 等来引用第一个、第二个、第三个和更后面的括号分组。</p>
<div class="note"><span class="notetitle">注： </span>在“查找内容”框中使用 \1、\2、\3 等（而不是 $1、$2、$3）来引用正则表达式中更早的括号分组。</div>
<p>例如，通过搜索 (\d+)\/(\d+)\/(\d+) 并用 $2/$1/$3 替换它，可以在由斜杠分隔的日期中交换日和月（因此可以在美国样式日期和欧洲样式日期之间进行转换）。</p>
<h3  class="related_post_title">相关日志</h3><ul class="related_post"><li>2009-06-20 -- <a href="http://wukangrui.com/2009/06/20/icbc-u-key-in-windows-7-x64.html" title="工行U盾在Windows 7 x64版下的使用">工行U盾在Windows 7 x64版下的使用</a></li><li>2009-04-16 -- <a href="http://wukangrui.com/2009/04/16/tencent-qq-2009-rtm-released.html" title="QQ2009正式版发布">QQ2009正式版发布</a></li><li>2008-06-09 -- <a href="http://wukangrui.com/2008/06/09/download-firefox3-to-make-world-record.html" title="参加火狐3下载日，帮助Firefox创造世界记录！">参加火狐3下载日，帮助Firefox创造世界记录！</a></li><li>2005-12-03 -- <a href="http://wukangrui.com/2005/12/03/visual-studio-2005-trial.html" title="Visual Studio 2005体验感受">Visual Studio 2005体验感受</a></li><li>2005-06-13 -- <a href="http://wukangrui.com/2005/06/13/the-9th-china-international-sofware-expro.html" title="第九届中国国际软件博览会">第九届中国国际软件博览会</a></li></ul>]]></content:encoded>
			<wfw:commentRss>http://wukangrui.com/2009/06/17/regular-expression-in-dreamweaver.html/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
	</channel>
</rss>
<!-- WP Super Cache is installed but broken. The path to wp-cache-phase1.php in wp-content/advanced-cache.php must be fixed! -->