<?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>张鑫旭-鑫空间-鑫生活</title>
	<atom:link href="http://www.zhangxinxu.com/wordpress/feed/" rel="self" type="application/rss+xml" />
	<link>http://www.zhangxinxu.com/wordpress</link>
	<description>it&#039;s my whole life!</description>
	<lastBuildDate>Mon, 14 May 2012 12:04:19 +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>W3C DOM异常对象DOMException介绍</title>
		<link>http://www.zhangxinxu.com/wordpress/2012/05/w3c-dom-domexception-object/</link>
		<comments>http://www.zhangxinxu.com/wordpress/2012/05/w3c-dom-domexception-object/#comments</comments>
		<pubDate>Mon, 14 May 2012 12:00:24 +0000</pubDate>
		<dc:creator>张 鑫旭</dc:creator>
				<category><![CDATA[js相关]]></category>
		<category><![CDATA[dom]]></category>
		<category><![CDATA[DOMException]]></category>
		<category><![CDATA[兼容性]]></category>
		<category><![CDATA[报错]]></category>

		<guid isPermaLink="false">http://www.zhangxinxu.com/wordpress/?p=2396</guid>
		<description><![CDATA[最近用jqmobi折腾个小项目，由于框架本身一起其他使用原因，连续遇到DOMException 12以及DOMException 7错误。查阅各个资料，发现国内几乎没有相关比较系统的文章。为方便他人以及自己查找匹对，故这里整理一篇小文。希望可以对以后遇到DOMException错误的同行们提供一些帮助。]]></description>
			<content:encoded><![CDATA[<p>by <a href="http://www.zhangxinxu.com/">zhangxinxu</a> from <a href="http://www.zhangxinxu.com/">http://www.zhangxinxu.com</a><br />
本文地址：<a href="http://www.zhangxinxu.com/wordpress/?p=2396">http://www.zhangxinxu.com/wordpress/?p=2396</a></p>
<p>最近用jqmobi折腾个小项目，由于框架本身一起其他使用原因，连续遇到DOMException 12以及DOMException 7错误。查阅各个资料，发现国内几乎没有相关比较系统的文章。为方便他人以及自己查找匹对，故这里整理一篇小文。</p>
<p>本文内容整理参考自：<a rel="nofollow" href="http://www.sitepoint.com/">SitePoint</a> &gt; <a href="http://reference.sitepoint.com/" rel="nofollow">Reference</a> &gt; <a href="http://reference.sitepoint.com/javascript" rel="nofollow">JAVASCRIPT</a> &gt; <a href="http://reference.sitepoint.com/javascript/domcore" rel="nofollow">DOM Core</a> &gt; DOMException</p>
<h3>一、DOMException是？</h3>
<p><code>DOMException</code>是W3C DOM核心对象。<code>DOMException</code>接口表示一个处理的错误，当一个操作不可能执行的时候，会抛出一个异常。例如试图创建一个无效的DOM, 或通过一个不存在的节点作为参数节点操作方法。</p>
<div>举个板栗，如下代码：</div>
<div class="zxx_code">
<pre>var node = document.getElementsByTagName('h1').item(0);
var refnode = node.nextSibling;
var newnode = document.createTextNode('这就是为何你挂了！');
node.insertBefore(newnode, refnode);</pre>
</div>
<p>上面代码演示了一个会嗝屁的<code>insertBefore</code>操作，因为<code>refnode</code>不是一个子节点。在Opera浏览器下，上面的操作就会导致下面显示的异常错误：</p>
<div class="zxx_code">
<pre>Inline script thread
Error:
Unhandled Exception: [Object DOMException]
code: 8
message: NOT_FOUND_ERR</pre>
</div>
<p>DOM并不对每个可能发生的错误定义一个异常，例如参数、语法错误就不在其中，这种情况有其自己的一套错误报告机制来处理。</p>
<p>实际上，大多数浏览器已经把DOM异常作为本地机制。除了显示异常代码和信息外，还显示了浏览器可以提供的其他信息（如行数或堆栈轨迹）</p>
<h3>二、DOM Exceptions兼容性</h3>
<p>兼容性见下表：</p>
<table cellspacing="1" cellpadding="0" border="1" summary="该表格有三栏, 显示当前主要浏览器及其各个版本,以及各个版本支持的属性" class="params_table" width="500">
<thead>
<tr>
<th colspan="3" id="full-ie">Internet Explorer</th>
<th colspan="3" id="full-ff">Firefox</th>
<th colspan="3" id="full-sa">Safari</th>
<th colspan="2" id="full-op">Opera</th>
</tr>
<tr>
<th headers="full-ie" id="full-ie5.5"><abbr title="Internet Explorer 5.5">5.5</abbr></th>
<th headers="full-ie" id="full-ie6.0"><abbr title="Internet Explorer 6.0">6.0</abbr></th>
<th headers="full-ie" id="full-ie7.0"><abbr title="Internet Explorer 7.0">7.0</abbr></th>
<th headers="full-ff" id="full-ff1.5"><abbr title="Firefox 1.5">1.5</abbr></th>
<th headers="full-ff" id="full-ff2.0"><abbr title="Firefox 2.0">2.0</abbr></th>
<th headers="full-ff" id="full-ff3.0"><abbr title="Firefox 3.0">3.0</abbr></th>
<th headers="full-sa" id="full-sa1.3"><abbr title="Safari 1.3">1.3</abbr></th>
<th headers="full-sa" id="full-sa2.0"><abbr title="Safari 2.0">2.0</abbr></th>
<th headers="full-sa" id="full-sa3.0"><abbr title="Safari 3.0">3.0</abbr></th>
<th headers="full-op" id="full-op9.0"><abbr title="Opera 9.0">9.0</abbr></th>
<th headers="full-op" id="full-op9.5"><abbr title="Opera 9.5">9.5</abbr></th>
</tr>
</thead>
<tbody>
<tr>
<td headers="full-ie full-ie5.5" class="none"><img src="http://www.zhangxinxu.com/study/image/error.gif" /></td>
<td headers="full-ie full-ie6.0" class="none"><img src="http://www.zhangxinxu.com/study/image/error.gif" /></td>
<td headers="full-ie full-ie7.0" class="none"><img src="http://www.zhangxinxu.com/study/image/error.gif" /></td>
<td headers="full-ff full-ff1.5" class="full"><img src="http://www.zhangxinxu.com/study/image/ok.gif" /></td>
<td headers="full-ff full-ff2.0" class="full"><img src="http://www.zhangxinxu.com/study/image/ok.gif" /></td>
<td headers="full-ff full-ff3.0" class="full"><img src="http://www.zhangxinxu.com/study/image/ok.gif" /></td>
<td headers="full-sa full-sa1.3" class="full"><img src="http://www.zhangxinxu.com/study/image/ok.gif" /></td>
<td headers="full-sa full-sa2.0" class="full"><img src="http://www.zhangxinxu.com/study/image/ok.gif" /></td>
<td headers="full-sa full-sa3.0" class="full"><img src="http://www.zhangxinxu.com/study/image/ok.gif" /></td>
<td headers="full-op full-op9.0" class="full"><img src="http://www.zhangxinxu.com/study/image/ok.gif" /></td>
<td headers="full-op full-op9.5" class="full"><img src="http://www.zhangxinxu.com/study/image/ok.gif" /></td>
</tr>
</tbody>
</table>
<p>上表的兼容性数据还是比较老的，按照常规，IE9也应该支持的，最新的Chrome浏览器一定支持。</p>
<p>考古价值的IE浏览器不支持该接口，他们使用本地错误（解析错误之类）。例如，上面插入节点的例子，在老IE下抛出的就是：<code>Invalid argument</code>. 在XML中，会给出更多的信息：<code>Insert position Node must be a Child of the Node to insert under</code>.</p>
<h3>三、常量列表</h3>
<p>该接口定义了<code>ExceptionCode</code>整数值——向外暴露<code>code</code>属性——指向每种类型的错误；这些定义参考下面些常量：</p>
<style>.varname{font-weight:bold;}.dlterm{margin-top:.8em;}.entry dd{color:#444;}</style>
<dl>
<dt class="dlterm"><a id="DOMException__INDEX_SIZE_ERR" name="DOMException__INDEX_SIZE_ERR"><!-- --></a><var class="varname">INDEX_SIZE_ERR</var> <code>code 1</code></dt>
<dd>如果索引是负值，或是超过了允许值。例如<a href="http://reference.sitepoint.com/javascript/Text/splitText">splitText</a>的offset参数比字符串长度还要长。</dd>
<dt class="dlterm"><a id="DOMException__DOMSTRING_SIZE_ERR" name="DOMException__DOMSTRING_SIZE_ERR"><!-- --></a><var class="varname">DOMSTRING_SIZE_ERR</var> <code>code 2</code></dt>
<dd><a href="http://reference.sitepoint.com/javascript/domcore#domcore__DOMString">DOMString</a>的特定字符数据太大。其大小显示是依赖实现的，未被DOM定义（每个浏览器的限制细节参见<a href="http://reference.sitepoint.com/javascript/domcore">DOM Core</a>）。</dd>
<dt class="dlterm"><a id="DOMException__HIERARCHY_REQUEST_ERR" name="DOMException__HIERARCHY_REQUEST_ERR"><!-- --></a><var class="varname">HIERARCHY_REQUEST_ERR</var> <code>code 3</code></dt>
<dd>节点不允许有新的子节点，或者新节点已经是其该节点的祖先节点。例如，尝试将<a href="http://reference.sitepoint.com/javascript/Element">Element</a>节点塞入<a href="http://reference.sitepoint.com/javascript/Text">Text</a>节点。</dd>
<dt class="dlterm"><a id="DOMException__WRONG_DOCUMENT_ERR" name="DOMException__WRONG_DOCUMENT_ERR"><!-- --></a><var class="varname">WRONG_DOCUMENT_ERR</var> <code>code 4</code></dt>
<dd>试图使用跨文档的节点操作。例如，<a href="http://reference.sitepoint.com/javascript/Node/appendChild">appendChild</a>的子节点来自其他<a href="http://reference.sitepoint.com/javascript/Document">文档</a>。而不是先输出(使用<a href="http://reference.sitepoint.com/javascript/Document/importNode">importNode</a>)。 </dd>
<dt class="dlterm"><a id="DOMException__INVALID_CHARACTER_ERR" name="DOMException__INVALID_CHARACTER_ERR"><!-- --></a><var class="varname">INVALID_CHARACTER_ERR</var> <code>code 5</code></dt>
<dd>一个非法的或无效的字符指定一个有限制的字符串，例如元素的<code>name</code>.</dd>
<dt class="dlterm"><a id="DOMException__NO_DATA_ALLOWED_ERR" name="DOMException__NO_DATA_ALLOWED_ERR"><!-- --></a><var class="varname">NO_DATA_ALLOWED_ERR</var> <code>code 6</code></dt>
<dd>为不支持数据的节点指定数据。如<a href="http://reference.sitepoint.com/javascript/Element">Element</a>节点本身不包含数据，其子节点包含。</dd>
<dt class="dlterm"><a id="DOMException__NO_MODIFICATION_ALLOWED_ERR" name="DOMException__NO_MODIFICATION_ALLOWED_ERR"><!-- --></a><var class="varname">NO_MODIFICATION_ALLOWED_ERR</var> <code>code 7</code></dt>
<dd>试图修改一个不能被修改的节点。例如，装载一个只读的节点。</dd>
<dt class="dlterm"><a id="DOMException__NOT_FOUND_ERR" name="DOMException__NOT_FOUND_ERR"><!-- --></a><var class="varname">NOT_FOUND_ERR</var> <code>code 8</code></dt>
<dd>引用的节点不存在。例如，<a href="Node/insertBefore"><code class="jsmethod">insertBefore</code></a>相关子节点不是引用的子节点。</dd>
<dt class="dlterm"><a id="DOMException__NOT_SUPPORTED_ERR" name="DOMException__NOT_SUPPORTED_ERR"><!-- --></a><var class="varname">NOT_SUPPORTED_ERR</var> <code>code 9</code></dt>
<dd>实现不支持的特定操作。例如使用一个节点的方法，但是此方法并没有实现，就是抛出此错误。</dd>
<dt class="dlterm"><a id="DOMException__INUSE_ATTRIBUTE_ERR" name="DOMException__INUSE_ATTRIBUTE_ERR"><!-- --></a><var class="varname">INUSE_ATTRIBUTE_ERR</var> <code>code 10</code></dt>
<dd>试图添加一个正在使用的属性。例如使用<a href="http://reference.sitepoint.com/javascript/Element/setAttributeNode">setAttributeNode</a>引用一个已经在另一个元素使用的<a href="http://reference.sitepoint.com/javascript/Attr">Attr</a>, 而不是克隆它首先(使用<a href="http://reference.sitepoint.com/javascript/Node/cloneNode">cloneNode</a>)。</dd>
<dt class="dlterm"><a id="DOMException__INVALID_STATE_ERR" name="DOMException__INVALID_STATE_ERR"><!-- --></a><var class="varname">INVALID_STATE_ERR</var> <code>code 11</code></dt>
<dd>试图使用一个不可用的对象。这种错误的抛出通常是因为某些内部原因，方法无法实现特定的操作。</dd>
<dt class="dlterm"><a id="DOMException__SYNTAX_ERR" name="DOMException__SYNTAX_ERR"><!-- --></a><var class="varname">SYNTAX_ERR</var> <code>code 12</code></dt>
<dd>无效或非法的字符串被指定。例如，用无效的CSS值设置<code>selectorText</code>属性的<code>CSSStyleRule</code>. <span class="s">//zxx: 我遇到该错误是因为在特定情况下，对<code>&lt;title></code>标签使用了<code>innerHTML</code>方法。</span></dd>
<dt class="dlterm"><a id="DOMException__INVALID_MODIFICATION_ERR" name="DOMException__INVALID_MODIFICATION_ERR"><!-- --></a><var class="varname">INVALID_MODIFICATION_ERR</var> <code>code 13</code></dt>
<dd>尝试修改一个节点的类型。例如，使用不匹配最初规则类型的值设置<code>cssText</code>属性的<code>CSSRule</code>.(如，为at-rule设置style-rule values值).</dd>
<dt class="dlterm"><a id="DOMException__NAMESPACE_ERR" name="DOMException__NAMESPACE_ERR"><!-- --></a><var class="varname">NAMESPACE_ERR</var> <code>code 14</code></dt>
<dd>操作与命名空间冲突。例如<a href="http://reference.sitepoint.com/javascript/Document/createElementNS">createElementNS</a>使用的名称歪瓜裂枣。</dd>
<dt class="dlterm"><a id="DOMException__INVALID_ACCESS_ERR" name="DOMException__INVALID_ACCESS_ERR"><!-- --></a><var class="varname">INVALID_ACCESS_ERR</var> <code>code 15</code></dt>
<dd>一个属性或操作不支持指定的节点。例如，尝试在一个不含float值的CSS属性上使用<code>getFloatValue</code>的<code>CSSPrimitiveValue</code>方法。</dd>
</dl>
<p><strong>关于code:</strong>ExceptionCode(也就是上面列表中一而再再而三的code)的整数值表示DOMException的类型。</p>
<h3>四、最后的说明</h3>
<p><img src="http://image.zhangxinxu.com/image/emtion/smile.png" style="float:left;" />本文内容没什么看头。重要的记住这里有篇关于<code>DOMException</code>的文章即可，回头可以迅速找到就OK啦！上面展示的列表中对ExceptionCode不同值的解释太泛太笼统了，后面的举例感觉是要故意展示一些方法，属性等。因此，离自己所希望的人人进来，人人都有启发的愿景还是有一定差距的。DOMException的各个错误也是不容易碰到的，但是，一旦碰到是很头疼的，整个页面的JS基本上就会报废，而且，错误不易查找。例如，使用数字作为元素<code>id</code>，在某些特定情况下，某些浏览器下，就会报DOMException的错误。</p>
<p>我现在比以前懒的，要是过去，刚毕业那会，激情无限的时候，估计会废寝忘食把每个错误都呈现一遍。现在嘛，唉，搞不动了，而且，错误呈现实在不易。因此，抱歉，大家只能将就上面一些笼统泛泛的解释了吧。</p>
<p>不过嘛，团结才是力量，本文可以无限评论的。因此，您要是遇到DOMException错误，并因为这里或那里解决了，记得一定要把您遇到的错误code、具体情境以及解决方法。以评论或邮件(zhangxinxu@zhangxinxu.com)的形式告知，我一定会整理出现，放在正文中的。这样，集思广益，细流成海，以后，一旦遇到浏览器报DOMException的错误，来这里就可以搞定，岂不很好。</p>
<p>因此，希望本文可以成为一个解决DOMException错误的一个平台，收集各个同行的经验，造福自己以及其他同行；而不仅仅是个普通文章。想法是美好的，具体就要看您的贡献与支持了！一起努力吧！</p>
<p>原创文章，转载请注明来自<a href="http://www.zhangxinxu.com/">张鑫旭-鑫空间-鑫生活</a>[<a href="http://www.zhangxinxu.com/">http://www.zhangxinxu.com</a>]<br />
本文地址：<a href="http://www.zhangxinxu.com/wordpress/?p=2396">http://www.zhangxinxu.com/wordpress/?p=2396</a></p>
<p>（本篇完）</p>
<div class="hidden">有话要说，点击<a href="http://www.zhangxinxu.com/wordpress/2012/05/w3c-dom-domexception-object/#response">这里</a>发表评论。</div>]]></content:encoded>
			<wfw:commentRss>http://www.zhangxinxu.com/wordpress/2012/05/w3c-dom-domexception-object/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>伪类+js实现CSS3 media queries跨界准确判断</title>
		<link>http://www.zhangxinxu.com/wordpress/2012/05/after-js-content-css3-media-queries/</link>
		<comments>http://www.zhangxinxu.com/wordpress/2012/05/after-js-content-css3-media-queries/#comments</comments>
		<pubDate>Fri, 11 May 2012 14:32:05 +0000</pubDate>
		<dc:creator>张 鑫旭</dc:creator>
				<category><![CDATA[js实例]]></category>
		<category><![CDATA[after]]></category>
		<category><![CDATA[content]]></category>
		<category><![CDATA[CSS伪类]]></category>
		<category><![CDATA[em]]></category>
		<category><![CDATA[getComputedStyle]]></category>
		<category><![CDATA[media queries]]></category>
		<category><![CDATA[transition]]></category>
		<category><![CDATA[响应布局]]></category>

		<guid isPermaLink="false">http://www.zhangxinxu.com/wordpress/?p=2387</guid>
		<description><![CDATA[我们都知道，CSS3 media queries是响应布局实现之利器。国外很多著名的前端站点，如css-tricks, smashingmagazinegazine等都采用了响应布局。
虽然国内此技术应用就像是打不着的打火机，没法跟如火如荼的欧美相比。但是，毕竟趋势是向前发展的，总会迎来遍地开花的时候，只是时间的长短而已。
media queries可以让设备在不同尺寸下应用不同的CSS样式、布局等。以适应手持设备、普屏显示器、宽屏显示器，以及未来冰箱上的联网显示器，汽车上的数码设备等。然后，仅仅通过CSS做布局可能无法应对所有的交互请求。
……
如何让JS的修改与CSS布局改变同步呢？]]></description>
			<content:encoded><![CDATA[<p>by <a href="http://www.zhangxinxu.com/">zhangxinxu</a> from <a href="http://www.zhangxinxu.com/">http://www.zhangxinxu.com</a><br />
本文地址：<a href="http://www.zhangxinxu.com/wordpress/?p=2387">http://www.zhangxinxu.com/wordpress/?p=2387</a></p>
<h3>一、容我唠叨</h3>
<p>我们都知道，CSS3 <code>media queries</code>是<a href="http://www.zhangxinxu.com/wordpress/?p=1937">响应布局</a>实现之利器。国外很多著名的前端站点，如<a href="http://css-tricks.com/">css-tricks</a>, <a href="http://www.smashingmagazine.com/">smashingmagazinegazine</a>等都采用了响应布局。</p>
<p>虽然国内此技术应用就像是打不着的打火机，没法跟如火如荼的欧美相比。但是，毕竟趋势是向前发展的，总会迎来遍地开花的时候，只是时间的长短而已。</p>
<p>本文所涉及的三个关键技术点，伪类(IE8+), js(getComputedStyle, IE9+)以及media queries(IE9+)都需要现代浏览器的支持。因此，如果您不是做HTML5开发，或是从事的是面向大众的普通web页面，本文内容没有任何实用价值。有帮助的，估计就是拓宽思路，增长眼界了。因此，本文内容很快就会归于沉寂，或许5年之后，某君阴差阳错进入此处，发现此文，会不由得惊叹——原来很多年前就有人介绍这个技术啦！但是，历史的发展与推动少不了那些湮没在历史中的开拓者。</p>
<p><code>media queries</code>可以让设备在不同尺寸下应用不同的CSS样式、布局等。以适应手持设备、普屏显示器、宽屏显示器，以及未来冰箱上的联网显示器，汽车上的数码设备等。然后，仅仅通过CSS做布局可能无法应对所有的交互请求。</p>
<p>举个简单例子，我们打开浏览器可能处于非最大化状态，此时，如果作为普屏处理，加载的图片可能就是128*128的小尺寸图片。但是，当我们最大化以获得更好阅读体验的时候，需要使用更大尺寸的图片256*256, 使用<code>media queries</code>? 拜托，CSS只能改变外在的尺寸，你难道要2倍尺寸拉伸？显然，更合理的做法是加载256*256尺寸的中等尺寸图片。以目前的技术而言，估计除了使用JS修改图片<code>src</code>外，很难有其他更可用的方法了。</p>
<p>OK, 现在问题来了，如何让JS的修改与CSS布局改变同步呢？</p>
<h3>二、CSS交互与JS交互同步问题</h3>
<p>如何让CSS样式、布局改变的时候，同时准确触发JS的交互呢？</p>
<p><strong>方法一、直接宽度/高度值匹配</strong><br />
何意？CSS3 <code>media queries</code>跨界触发一般都有一个宽度或高度值，或是color(很少使用)。例如，普屏图片宽度128*128，可能就是如下CSS：</p>
<div class="zxx_code">
<pre>@media screen and (max-width: 1024px) {
    img {
        width: 128px;
        height: 128px;
    }
} </pre>
</div>
<p>意思就是screen(屏幕)宽度不超过1024像素(<code>max-width:1024px</code>)的时候，图片宽度是128像素，高度也是128像素。</p>
<p>因此，我们可能通过浏览器窗口尺寸改变的resize事件中捕获浏览器窗口尺寸，与1024对比，如果小于则触发对应的普屏事件处理，大于，则宽屏处理。</p>
<div class="zxx_code">
<pre>window.addEventListener("resize", function() {
    <span style="color:gray;">// window.innerWidth IE9+浏览器支持</span>
    if (window.innerWidth <= 1024) {
        <span style="color:green;">// 普屏处理</span>
    } else {
        <span style="color:green;">//宽屏处理</span>
    }
});</pre>
</div>
<p>确实是简单高效的方法。但是，也是有不足的。</p>
<p><strong>① 可维护性</strong><br />
一个载体所对应的数值是会经常变的。例如，小胖今天体重148斤，明天喝碧生源厕所来回几个小时，可能就只有145斤了。同样的，对于1024这个值，变动的几率是很大的。变动其实没什么，麻烦的是下面的JS中的判断的数值与CSS中的限制是要一致的。也就是CSS宽度阈值改变，JS也要跟着变。显然，这种高耦合增加了后期的维护成本。</p>
<p><strong>② 宽度的计算与不确定性</strong><br />
<code>window.innerWidth</code>返回的是窗口内部宽度（不包括浏览器的框框），单位是像素。但是，<code>width</code>属性的单位并不固定。有些站点，可能使用<code>em</code>, <code>%</code>或最新的<code>vw</code>, <code>rem</code>, <code>in</code>等（完整单位参见之前“<a href="http://www.zhangxinxu.com/wordpress/?p=1494">CSS长度值及时间、频率、角度单位</a>”一文）。</p>
<p>而这些单位的宽度转换成<code>px</code>就需要计算，而这些单位很多是相对的，例如<code>em</code>是与字体大小相关的，如果网页的字体大小被用户手动改变（视力不佳用户，或是“Ctrl + 加号”的误操作），可能你之前按照12像素比例的宽度计算就会不准确。这就是宽度计算的不确定性。</p>
<p>可见，我们有必要寻求更佳的同步方法。什么呢，就通过CSS本身！</p>
<p><strong>通过CSS本身？</strong><br />
比方说吧（虽然这个例子实用性不佳），我们通过<code>media queries</code>让图片宽度变成128像素，就可以通过检测图片应用的宽度判断当前设备状态。</p>
<p>当然，这里只是举例，其实这比上面1024px方法更搓，因为，牵扯到实际样式的CSS是会经常变动的，JS显然不能与之高耦合。</p>
<p>那该如何应用呢？很简单，应用在不会使用的元素，不会产生额外影响的CSS属性。例如在<code>&lt;head&gt;</code>标签上使用<code>z-index</code>属性（from <a href="http://stephaniehobson.ca/">Stephanie</a>）。</p>
<div class="zxx_code">
<pre>@media screen and (min-width: 45em) {
    head {
        z-index: 2;
    }
}</pre>
</div>
<p><img alt="难过 张鑫旭-鑫空间-鑫生活" src="http://image.zhangxinxu.com/image/emtion/sad.png" title="难过" class="alignnone" width="150" height="150" style="float:left;" />不过，根据<a href="http://adactio.com/">Jeremy Keith</a>的测试，Webkit浏览器貌似不支持，其返回的<code>z-index</code>值是<code>auto</code>, 不是数值<code>2</code>. 我那热乎乎的小心脏，瞬间冰冻，啊~~</p>
<p>应用在<code>&lt;body&gt;</code>标签上到是可以的，不过，由于body标签暴露在外，参与CSS布局，如何其设置了定位属性（relative, absolute等），<code>z-index</code>立马勃起，如果里面在层级复杂点，哦呵呵，兄弟你把妹的时间估计要陪代码咯！</p>
<p>不过，对于一般的页面（不是类似游戏页面，幻灯片页面的页面），只有某些艺高人才敢在body上增加定位属性（违背<a href="http://www.zhangxinxu.com/wordpress/?p=1834">最小化影响原则</a> &#8211; part 7），因此，在<code>body</code>上设置<code>z-index</code>属性一般问题不大，但是，从可理解性上讲，<code>z-index</code>弱了点。因为，<code>z-index</code>值一般是数值。你说：</p>
<pre>800~1024     z-index:1;
1024~1280     z-index:2;
1280~1440     z-index:3;
1440~1680     z-index:4; </pre>
<p>两个月后，你在看JS中，<code>zIndex</code>的<code>1</code>, <code>2</code>, <code>3</code>, <code>4</code>，你还记得对应的数值范围吗？别人经手你的代码，知道各个数值对应的含义吗？（别跟我扯注释~~）</p>
<p>因此，我们需要寻求更佳的方案。</p>
<p><strong>方法二、body标签+伪类+content内容生成</strong><br />
因为每个页面都有<code>body</code>标签，在该标签上打标记便于整站通用。</p>
<p>这里的伪类指<code>:after</code>, <code>:before</code>亦可，因为，使用该CSS属性与实际用途冲突概率要比<code>z-index</code>属性小多了，更加安全。</p>
<p>content内容生成我专门写过一篇文章：“<a href="http://www.zhangxinxu.com/wordpress/?p=739">CSS content内容生成技术以及应用</a>”，后来又结果伪类属性写了篇：“<a href="http://www.zhangxinxu.com/wordpress/?p=1136">:after伪类+content内容生成经典应用</a>”。您有兴趣可以看看。而这里，则是一个新的应用典型了。</p>
<p>使用content内容生成的最大好处在于，我们可以随意定义里面的内容（z-index只能数值），例如：</p>
<div class="zxx_code">
<pre>{ content: "普屏"; }</pre>
</div>
<p>显然，这个描述性的文字是很泛的，概括性强，不会因为<code>1024px</code>变成<code>980px</code>而跟着变动，而且，含义明显，一目了然。</p>
<p>因此，上面的一番分析总结，<code>body:after + content</code>是相当好的一个方法。</p>
<p>我们唯一剩下的技术难点就是如何使用JS获取<code>content</code>的内容。当当当当，前几天的写的“<a href="http://www.zhangxinxu.com/wordpress/?p=2378">获取元素CSS值之getComputedStyle方法熟悉</a>”一文内容就派上用场了。</p>
<p>使用方法就是标题中的<code>getComputedStyle</code>:</p>
<div class="zxx_code">
<pre>var content = window.getComputedStyle(document.body, ":after").getPropertyValue("content");</pre>
</div>
<p>然后，我们就可以根据<code>content</code>的具体内容，准确捕获media queries越界的瞬间，并作出相关的JS交互了！</p>
<div class="zxx_code">
<pre>if (content === "窄屏") {
    <span style="color:green;">// ……</span>
} else if (content === "普屏") {
    <span style="color:green;">// ……</span>
} else if (content === "宽屏") {
    <span style="color:green;">// ……</span>
}
</pre>
</div>
<h3>三、百闻不如一见</h3>
<p>您可以狠狠地点击这里：<a class="a_link" target="_blank" href="http://www.zhangxinxu.com/study/201205/media-queries-pseudo-classes-detect.html">伪类+js与media queries跨界demo</a></p>
<p>下图为宽屏(<code>1680px</code>)下等比缩放的效果图：<br />
<img alt="宽屏下图片的显示" src="http://image.zhangxinxu.com/image/blog/201205/2012-05-11_220922.png" title="宽屏下图片的显示" class="alignnone" width="414" height="293" /></p>
<p>我们修在宽度改成<code>1024px</code>，则图片不仅尺寸变小了，src地址也应用了小图的地址：<br />
<img alt="" src="http://image.zhangxinxu.com/image/blog/201205/2012-05-11_221257.png" title="修改浏览器宽度为1024px" class="alignnone" width="317" height="224" /><br />
<img alt="" src="http://image.zhangxinxu.com/image/blog/201205/2012-05-11_221419.png" title="普屏下的效果截图" class="alignnone" width="413" height="284" /></p>
<p>相关CSS代码如下：</p>
<div class="zxx_code">
<pre>.demo img {
    width: 512px;
}
@media screen and (max-width: 1024px) {
    body:after {
        display: none;
        content: 'normalscreen';
    }
    .demo img {
        width: 256px;
    }
}</pre>
</div>
<p>JS代码比较长，这里就不完整展示了，不过有个东西很重要，需要<strong>提醒</strong>下：<br />
<code>getComputedStyle</code>返回的<code>content</code>值在某些浏览器下是带有引号的，因此，你不能使用<code>===</code>直接匹配，可以使用简单正则<code>test</code>方法（demo页面的方法），或是索引查找<code>indexOf</code>方法，或是字符分隔<code>split</code>方法等。</p>
<div class="zxx_code">
<pre>
<del datetime="2012-05-11T07:27:11+00:00">if (content === "normalscreen") {}</del>

if (/normalscreen/.test(content)) {}
</pre>
</div>
<h3>四、我肚子很饿</h3>
<p>上午驾驶员考试，考桩考和小路，请假了，下午才回来。于是，晚上忙着赶活，完成本文，晚饭也懒得吃，因此，现在还饿着。本来想补一个<code>media queries</code>与<code>transition</code>动画配合，使用JS做响应延迟的例子（跨界的时候，应用了<code>transition</code>的元素动画，此时，即时响应的JS交互可能就会出问题，如定位等）。</p>
<p>不过，肚子饿饿，就懒得搞了。好，我要赶快撤了，去吃西北口味的“茄子牛肉盖浇饭”，我口水下来咯~~<br />
<img alt="口水 鑫卡通" src="http://image.zhangxinxu.com/image/emtion/mouth-water.png" title="口水" class="alignnone" width="150" height="150" /></p>
<p>原创文章，转载请注明来自<a href="http://www.zhangxinxu.com/">张鑫旭-鑫空间-鑫生活</a>[<a href="http://www.zhangxinxu.com/">http://www.zhangxinxu.com</a>]<br />
本文地址：<a href="http://www.zhangxinxu.com/wordpress/?p=2387">http://www.zhangxinxu.com/wordpress/?p=2387</a></p>
<p>（本篇完）</p>
<div class="hidden">有话要说，点击<a href="http://www.zhangxinxu.com/wordpress/2012/05/after-js-content-css3-media-queries/#response">这里</a>发表评论。</div>]]></content:encoded>
			<wfw:commentRss>http://www.zhangxinxu.com/wordpress/2012/05/after-js-content-css3-media-queries/feed/</wfw:commentRss>
		<slash:comments>6</slash:comments>
		</item>
		<item>
		<title>获取元素CSS值之getComputedStyle方法熟悉</title>
		<link>http://www.zhangxinxu.com/wordpress/2012/05/getcomputedstyle-js-getpropertyvalue-currentstyle/</link>
		<comments>http://www.zhangxinxu.com/wordpress/2012/05/getcomputedstyle-js-getpropertyvalue-currentstyle/#comments</comments>
		<pubDate>Tue, 08 May 2012 15:31:32 +0000</pubDate>
		<dc:creator>张 鑫旭</dc:creator>
				<category><![CDATA[js实例]]></category>
		<category><![CDATA[CSS伪类]]></category>
		<category><![CDATA[currentStyle]]></category>
		<category><![CDATA[getAttribute]]></category>
		<category><![CDATA[getComputedStyle]]></category>
		<category><![CDATA[getPropertyValue]]></category>
		<category><![CDATA[ie9]]></category>
		<category><![CDATA[style]]></category>
		<category><![CDATA[兼容性]]></category>

		<guid isPermaLink="false">http://www.zhangxinxu.com/wordpress/?p=2378</guid>
		<description><![CDATA[我们都用过jQuery的CSS()方法，其底层运作就应用了getComputedStyle以及getPropertyValue方法。
对于那些只想混口饭吃的人来讲，晓得CSS()如何使用就足够了。对于希望在JS道路上越走越远的来人说，简单了解一些JS库底层实现对自己的学习很有帮助。可能谈不上信手拈来的使用，至少对创造一些创意新颖的新技术拓宽了思路。
jQuery为何受欢迎，其中原因之一就是方法名称比……]]></description>
			<content:encoded><![CDATA[<p>by <a href="http://www.zhangxinxu.com/">zhangxinxu</a> from <a href="http://www.zhangxinxu.com/">http://www.zhangxinxu.com</a><br />
本文地址：<a href="http://www.zhangxinxu.com/wordpress/?p=2378">http://www.zhangxinxu.com/wordpress/?p=2378</a></p>
<h3>一、碎碎念~前言</h3>
<p>我们都用过jQuery的<code>CSS()</code>方法，其底层运作就应用了getComputedStyle以及getPropertyValue方法。</p>
<p>对于那些只想混口饭吃的人来讲，晓得<code>CSS()</code>如何使用就足够了。对于希望在JS道路上越走越远的来人说，简单了解一些JS库底层实现对自己的学习很有帮助。可能谈不上信手拈来的使用，至少对创造一些创意新颖的新技术拓宽了思路。</p>
<p>jQuery为何受欢迎，其中原因之一就是方法名称比较短。好比打架一样，块头大的潜意识认为厉害，就不由得心生畏惧，退避三舍；小个子（或村妇，小孩）嘛，自然以为是软豆腐，愿意接受作为对手。<br />
<img alt="功夫剧照 周星驰被村妇K 张鑫旭-鑫空间-鑫生活" src="http://image.zhangxinxu.com/image/blog/201205/2012-05-08_194924.jpg" title="功夫剧照 周星驰被村妇K" class="alignnone" width="407" height="306" /> <img alt="功夫剧照 周星驰找小孩单挑 结果…… 张鑫旭-鑫空间-鑫生活" src="http://image.zhangxinxu.com/image/blog/201205/2012-05-08_195035.jpg" title="功夫剧照 周星驰找小孩单挑 结果……" class="alignnone" width="369" height="286" /></p>
<p>因此，当看到类似<code>getComputedStyle</code>这么长的方法名的时候，我们身体里那个懒惰小人突然就醒了：哎哟哟，这东西，就跟放心食品一样，几年才见一回。看上去又蛮复杂，想到晚上还要跟妹子聊天。这东西，就让它从旁边过吧，反正不会掉块肉的。</p>
<p>网上不是有这么个段子嘛：<strong>可怕的是，比你聪明的人比你更勤奋</strong>。那么，这里的“勤奋”的差异体现在什么地方呢？就拿这个<code>getComputedStyle</code>举例：懒惰青年是看一下，立马像看见凤姐一样视线离开；普通青年是看一下，发现自己不了解，百一下或谷一下，熟悉了解之；勤奋青年是不仅了解，还抽出时间实践之（如做个简单demo测试），熟悉方法的特异性，验证一些观点正确性。</p>
<p>您可以按照你现在的心理状态看看你是哪类青年：如果此时，您已经对本文的内容没有兴趣了（当然，您的工作与JS关系亲密），您是……（你懂的）；如果您看完本文内容，发现，还是有不少收获，心中回味下，然后ctrl+w去其他地方觅食，不再回来，那您是普通青年；如果您看完本文，然后对所说的一些内容作了额外的测试，例如IE9浏览器是否支持测试等，并通过评论形式指出可能的错误，不得不说您是勤奋青年，假以时日，必有一番技术作为。从我文章的些评论来看，有不少同行就是这样的勤奋人儿。</p>
<p> の, 好久没写文章，话又多了，打住，进入正题。</p>
<h3>二、getComputedStyle是？</h3>
<p><code>getComputedStyle</code>是一个可以获取当前元素所有最终使用的CSS属性值。返回的是一个CSS样式声明对象([object CSSStyleDeclaration])，只读。</p>
<blockquote><p><code>getComputedStyle()</code> gives the final used values of all the CSS properties of an element.</p></blockquote>
<p><strong>语法</strong>如下：</p>
<div class="zxx_code">
<pre>var style = window.getComputedStyle("元素", "伪类");</pre>
</div>
<p>例如：</p>
<div class="zxx_code">
<pre>var dom = document.getElementById("test"),
    style = window.getComputedStyle(dom , ":after");</pre>
</div>
<p>就两个参数，大家都懂中文的，没什么好说的。只是额外提示下：Gecko 2.0 (Firefox 4 / Thunderbird 3.3 / SeaMonkey 2.1) 之前，第二个参数“伪类”是必需的（如果不是伪类，设置为<code>null</code>），不过现在嘛，不是必需参数了。</p>
<h3>三、getComputedStyle与style的区别</h3>
<p>我们使用<code>element.style</code>也可以获取元素的CSS样式声明对象，但是其与<code>getComputedStyle</code>方法还有有一些差异的。</p>
<ol>
<li><strong>只读与可写</strong><br />
正如上面提到的<code>getComputedStyle</code>方法是只读的，只能获取样式，不能设置；而<code>element.style</code>能读能写，能屈能伸。</li>
<li><strong>获取的对象范围</strong><br />
<code>getComputedStyle</code>方法获取的是最终应用在元素上的所有CSS属性对象（即使没有CSS代码，也会把默认的祖宗八代都显示出来）；而<code>element.style</code>只能获取元素<code>style</code>属性中的CSS样式。因此对于一个光秃秃的元素<code>&lt;p></code>，<code>getComputedStyle</code>方法返回对象中<code>length</code>属性值（如果有）就是<code>190+</code>(据我测试FF:192, IE9:195, Chrome:253, 不同环境结果可能有差异), 而<code>element.style</code>就是<code>0</code>。</li>
</ol>
<h3>四、getComputedStyle与defaultView</h3>
<p>如果我们查看jQuery源代码，会发现，其<code>css()</code>方法实现不是使用的<code>window.getComputedStyle</code>而是<code>document.defaultView.getComputedStyle</code>，唷？这是怎么一回事？<br />
<img alt="jQuery源码使用document.defaultView.getComputedStyle截图证明" src="http://image.zhangxinxu.com/image/blog/201205/2012-05-08_211408.png" title="jQuery源码使用document.defaultView.getComputedStyle截图证明" class="alignnone" width="594" height="166" /></p>
<p>实际上，使用<code>defaultView</code>基本上是没有必要的，<code>getComputedStyle</code>本身就存在<code>window</code>对象之中。根据<a href="https://developer.mozilla.org/User:DennisHall">DennisHall</a>的说法，使用<code>defaultView</code>可能一是人们不太乐意在window上专门写个东西，二是让API在Java中也可用（这我不懂，忘指点~~）。</p>
<p>不过有个特殊情况，在FireFox3.6上不使用<code>defaultView</code>方法就搞不定的，就是<a href="https://github.com/jquery/jquery/pull/524">访问框架(frame)的样式</a>.</p>
<div class="hidden"><em>如果您看到下面的文字，可能是由于在其他网站或是RSS中阅读本文，本文原地址：<a href="http://www.zhangxinxu.com/wordpress/?p=2378">http://www.zhangxinxu.com/wordpress/?p=2378</a>，本文作者：<a href="http://www.zhangxinxu.com/">张鑫旭</a>，来自张鑫旭-鑫空间-鑫生活，访问原出处阅读体验更佳。</em></div>
<h3>五、getComputedStyle兼容性</h3>
<p>对于桌面设备：</p>
<table class="params_table">
<tbody>
<tr>
<th>&nbsp;</th>
<th>Chrome</th>
<th>Firefox (Gecko)</th>
<th>Internet Explorer</th>
<th>Opera</th>
<th>Safari</th>
</tr>
<tr>
<td>基本支持</td>
<td><span title="升级到最近的版本"><img src="http://www.zhangxinxu.com/study/image/ok.gif" alt="支持" /></span></td>
<td><span title="升级到最近的版本"><img src="http://www.zhangxinxu.com/study/image/ok.gif" alt="支持" /></span></td>
<td>9</td>
<td><span title="升级到最近的版本"><img src="http://www.zhangxinxu.com/study/image/ok.gif" alt="支持" /></span></td>
<td><span title="升级到最近的版本"><img src="http://www.zhangxinxu.com/study/image/ok.gif" alt="支持" /></span></td>
</tr>
<tr>
<td>伪类元素支持</td>
<td><span title="升级到最近的版本"><img src="http://www.zhangxinxu.com/study/image/ok.gif" alt="支持" /></span></td>
<td><span title="升级到最近的版本"><img src="http://www.zhangxinxu.com/study/image/ok.gif" alt="支持" /></span></td>
<td><span title="不支持"><img src="http://www.zhangxinxu.com/study/image/error.gif" alt="不支持" /></span></td>
<td><span title="不支持"><img src="http://www.zhangxinxu.com/study/image/error.gif" alt="不支持" /></span> </td>
<td><span title="升级到最近的版本"><img src="http://www.zhangxinxu.com/study/image/ok.gif" alt="支持" /></span> </td>
</tr>
</tbody>
</table>
<p>对于手机设备：</p>
<table class="params_table">
<tbody>
<tr>
<th>&nbsp;</th>
<th>Android</th>
<th>Firefox Mobile (Gecko)</th>
<th>IE Mobile</th>
<th>Opera Mobile</th>
<th>Safari Mobile</th>
</tr>
<tr>
<td>基本支持</td>
<td><span title="最新版本支持"><img src="http://www.zhangxinxu.com/study/image/ok.gif" alt="支持" /></span></td>
<td><span title="最新版本支持"><img src="http://www.zhangxinxu.com/study/image/ok.gif" alt="支持" /></span></td>
<td>WP7 Mango</td>
<td><span title="最新版本支持"><img src="http://www.zhangxinxu.com/study/image/ok.gif" alt="支持" /></span></td>
<td><span title="最新版本支持"><img src="http://www.zhangxinxu.com/study/image/ok.gif" alt="支持" /></span></td>
</tr>
<tr>
<td>伪元素支持</td>
<td><span style="color: rgb(255, 153, 0);" title="兼容性未知，有劳更新">?</span></td>
<td><span style="color: rgb(255, 153, 0);" title="兼容性未知，有劳更新">?</span></td>
<td><span title="Not supported." style="color: rgb(255, 0, 0);"><img src="http://www.zhangxinxu.com/study/image/error.gif" alt="不支持" /></span></td>
<td><span style="color: rgb(255, 153, 0);" title="兼容性未知，有劳更新">?</span></td>
<td><span style="color: rgb(255, 153, 0);" title="兼容性未知，有劳更新">?</span></td>
</tr>
</tbody>
</table>
<p>上面打问号的表示没有测试，是否兼容不知。如果您方便测试，欢迎将测试结果告知，这里将及时更新，并附上您的姓名，以谢您做的贡献。</p>
<p>我们先把注意力放在桌面设备上，可以看到，<code>getComputedStyle</code>方法IE6~8是不支持的，得，背了半天的媳妇，发现是孙悟空变的——郁闷了。不急，IE自有自己的一套东西。</p>
<h3>六、getComputedStyle与currentStyle</h3>
<p><code>currentStyle</code>是IE浏览器自娱自乐的一个属性，其与<code>element.style</code>可以说是近亲，至少在使用形式上类似，<code>element.currentStyle</code>，差别在于<code>element.currentStyle</code>返回的是元素当前应用的最终CSS属性值（包括外链CSS文件，页面中嵌入的<code>&lt;style&gt;</code>属性等）。</p>
<p>因此，从作用上将，<code>getComputedStyle</code>方法与<code>currentStyle</code>属性走的很近，形式上则<code>style</code>与<code>currentStyle</code>走的近。不过，<code>currentStyle</code>属性貌似不支持伪类样式获取，这是与<code>getComputedStyle</code>方法的差异，也是jQuery <code>css()</code>方法无法体现的一点。</p>
<p><span class="s">//zxx: 如果你只知jQuery css()方法，你是不会知道伪类样式也是可以获取的，虽然部分浏览器不支持。</span></p>
<p>例如，我们要获取一个元素的高度，可以类似下面的代码：</p>
<div class="zxx_code">
<pre>alert((element.currentStyle? element.currentStyle : window.getComputedStyle(element, null)).height);</pre>
</div>
<p>您可以狠狠地点击这里：<a class="a_link" target="_blank" href="http://www.zhangxinxu.com/study/201205/currentstyle-getcomputedstyle-element-height.html">使用getComputedStyle和currentStyle 获取元素高度demo</a></p>
<p>结果FireFox下显示<code>24px</code>(经过计算了), 而IE浏览器下则是CSS中的<code>2em</code>属性值：<br />
<img alt="Firefox下显示的计算后的24px值 张鑫旭-鑫空间-鑫生活" src="http://image.zhangxinxu.com/image/blog/201205/2012-05-08_220826.png" title="Firefox下显示的计算后的24px值" class="alignnone" width="315" height="211" /> <img alt="IE9下显示的CSS中的2em值 张鑫旭-鑫空间-鑫生活" src="http://image.zhangxinxu.com/image/blog/201205/2012-05-08_220905.png" title="IE9下显示的CSS中的2em值 " class="alignnone" width="307" height="226" /></p>
<p><code>getComputedStyle</code>方法与<code>currentStyle</code>属性其他具体差异还有很多，我以一个普通按钮做元素，遍历了其中靠谱的属性名和属性值，您可以狠狠地点击这里：<a class="a_link" target="_blank" href="http://www.zhangxinxu.com/study/201205/currentstyle-getcomputedstyle-test.html">getComputedStyle和currentStyle属性展示demo</a></p>
<p>仔细对比查看，我们可以看到不少差异，例如浮动属性，FireFox浏览器下是这个(<code>cssFloat</code>)：<br />
<img alt="FireFox下的浮动属性名 " src="http://image.zhangxinxu.com/image/blog/201205/2012-05-08_221607.png" title="FireFox下的浮动属性名" class="alignnone" width="227" height="107" /></p>
<p>IE7浏览器下则是<code>styleFloat</code> ：<br />
<img alt="IE7浏览器下的styleFloat属性 张鑫旭-鑫空间-鑫生活" src="http://image.zhangxinxu.com/image/blog/201205/2012-05-08_221737.png" title="IE7浏览器下的styleFloat属性" class="alignnone" width="263" height="136" /></p>
<p>而IE9浏览器下则是<code>cssFloat</code>和<code>styleFloat</code>都有。</p>
<p>等其他N多差异。</p>
<h3>七、getPropertyValue方法</h3>
<p><code>getPropertyValue</code>方法可以获取CSS样式申明对象上的属性值（直接属性名称），例如：</p>
<div class="zxx_code">
<pre>window.getComputedStyle(element, null).getPropertyValue("float");</pre>
</div>
<p>如果我们不使用<code>getPropertyValue</code>方法，直接使用键值访问，其实也是可以的。但是，比如这里的的<code>float</code>，如果使用键值访问，则不能直接使用<code>getComputedStyle(element, null).float</code>，而应该是<code>cssFloat</code>与<code>styleFloat</code>，自然需要浏览器判断了，比较折腾！</p>
<p>使用<code>getPropertyValue</code>方法不必可以驼峰书写形式（不支持驼峰写法），例如：<code>style.getPropertyValue("border-top-left-radius")</code>;</p>
<p><strong>兼容性</strong><br />
<code>getPropertyValue</code>方法IE9+以及其他现代浏览器都支持，见下表：</p>
<table class="params_table">
<tbody>
<tr>
<th>&nbsp;</th>
<th>Chrome</th>
<th>Firefox (Gecko)</th>
<th>Internet Explorer</th>
<th>Opera</th>
<th>Safari</th>
</tr>
<tr>
<td>基本支持</td>
<td><span title="升级到最近的版本"><img src="http://www.zhangxinxu.com/study/image/ok.gif" alt="支持" /></span></td>
<td><span title="升级到最近的版本"><img src="http://www.zhangxinxu.com/study/image/ok.gif" alt="支持" /></span></td>
<td>9</td>
<td><span title="升级到最近的版本"><img src="http://www.zhangxinxu.com/study/image/ok.gif" alt="支持" /></span></td>
<td><span title="升级到最近的版本"><img src="http://www.zhangxinxu.com/study/image/ok.gif" alt="支持" /></span></td>
</tr>
</tbody>
</table>
<p>OK，一涉及到兼容性问题(IE6-8肿么办)，感觉头开始微微作痛了~~，不急，IE自由一套自己的套路，就是<code>getAttribute</code>方法。</p>
<h3>八、getPropertyValue和getAttribute</h3>
<p>在老的IE浏览器（包括最新的），<code>getAttribute</code>方法提供了与<code>getPropertyValue</code>方法类似的功能，可以访问CSS样式对象的属性。用法与<code>getPropertyValue</code>类似：</p>
<div class="zxx_code">
<pre>style.getAttribute("float");</pre>
</div>
<p>注意到没，使用<code>getAttribute</code>方法也不需要<code>cssFloat</code>与<code>styleFloat</code>的怪异写法与兼容性处理。不过，还是有一点差异的，就是属性名需要驼峰写法，如下：</p>
<div class="zxx_code">
<pre>style.getAttribute("backgroundColor");</pre>
</div>
<p>如果不考虑IE6浏览器，貌似也是可以这么写：</p>
<div class="zxx_code">
<pre>style.getAttribute("background-color");</pre>
</div>
<p>实例才是王道，您可以狠狠地点击这里：<a class="a_link" target="_blank" href="http://www.zhangxinxu.com/study/201205/getpropertyvalue-getAttribute-background-color.html">getPropertyValue和getAttribute获取背景色demo</a></p>
<p>结果FireFox下一如既往的rgb颜色返回(Chrome也是返回rgb颜色)：<br />
<img alt="FireFox浏览器下一如既往的RGB颜色返回 张鑫旭-鑫空间-鑫生活" src="http://image.zhangxinxu.com/image/blog/201205/2012-05-08_230119.png" title="FireFox浏览器下一如既往的RGB颜色返回" class="alignnone" width="355" height="211" /></p>
<p>对于IE9浏览器，虽然应用的是<code>currentStyle</code>, 但是从结果上来讲，<code>currentStyle</code>返回的对象是完全支持<code>getPropertyValue</code>方法的。<br />
<img alt="" src="http://image.zhangxinxu.com/image/blog/201205/2012-05-08_230242.png" title="IE9下截图" class="alignnone" width="421" height="253" /></p>
<h3>九、getPropertyValue和getPropertyCSSValue</h3>
<p>从长相上看<code>getPropertyCSSValue</code>与<code>getPropertyValue</code>是近亲，但实际上，<code>getPropertyCSSValue</code>要顽劣的多。</p>
<p><code>getPropertyCSSValue</code>方法返回一个CSS最初值(CSSPrimitiveValue)对象(width, height, left, &#8230;)或CSS值列表(CSSValueList)对象(backgroundColor, fontSize, &#8230;)，这取决于<code>style</code>属性值的类型。在某些特别的style属性下，其返回的是自定义对象。该自定义对象继承于CSSValue对象（就是上面所说的<code>getComputedStyle</code>以及<code>currentStyle</code>返回对象）。</p>
<p><code>getPropertyCSSValue</code>方法兼容性不好，IE9浏览器不支持，Opera浏览器也不支持（实际支持，只是老是抛出异常）。而且，虽然FireFox中，<code>style</code>对象支持<code>getPropertyCSSValue</code>方法，但总是返回<code>null</code>. 因此，目前来讲，<code>getPropertyCSSValue</code>方法可以先不闻不问。</p>
<h3>十、补充~结语</h3>
<p>有了jQuery等优秀库，我们有熟悉底层的<code>getComputedStyle</code>方法的必要吗？</p>
<p>实际上，本文一直没有深入展开<code>getComputedStyle</code>方法一个很重要的，类似<code>css()</code>方法没有的功能——获取伪类元素样式。但从这一点上将，熟悉<code>getComputedStyle</code>方法有必要。</p>
<p>下一篇文章，我就将介绍如何实现<code>getComputedStyle</code>方法在伪类元素上的特异功能，实现CSS3 media queries下一些JS交互，及实际应用。</p>
<p>well, 开篇已经啰哩吧嗦不少内容了，这里就不再讲废话了。行文匆忙，文中难免有表述不准确之处，欢迎指正。欢迎补充，感谢阅读，希望本文的内容能够对您的学习有所帮助。</p>
<p>原创文章，转载请注明来自<a href="http://www.zhangxinxu.com/">张鑫旭-鑫空间-鑫生活</a>[<a href="http://www.zhangxinxu.com/">http://www.zhangxinxu.com</a>]<br />
本文地址：<a href="http://www.zhangxinxu.com/wordpress/?p=2378">http://www.zhangxinxu.com/wordpress/?p=2378</a></p>
<div class="hidden">
<p>觉得这里的文章不错，希望他一直走下去？您可以：<a target="_blank" href="https://me.alipay.com/zhangxinxu" title="小小赞助大大帮助"><img src="/wordpress/wp-content/themes/default/images/pay_encourage.png" width="159" height="37" alt="支付鼓励" align="absmiddle" /></a></p>
</div>
<p>（本篇完）</p>
<div class="hidden">有话要说，点击<a href="http://www.zhangxinxu.com/wordpress/2012/05/getcomputedstyle-js-getpropertyvalue-currentstyle/#response">这里</a>发表评论。</div>]]></content:encoded>
			<wfw:commentRss>http://www.zhangxinxu.com/wordpress/2012/05/getcomputedstyle-js-getpropertyvalue-currentstyle/feed/</wfw:commentRss>
		<slash:comments>3</slash:comments>
		</item>
		<item>
		<title>近期折腾：使用JS以及HTML5实现鑫情动画</title>
		<link>http://www.zhangxinxu.com/wordpress/2012/05/js-html5-zxx-carton-%e9%91%ab%e6%83%85%e5%8a%a8%e7%94%bb/</link>
		<comments>http://www.zhangxinxu.com/wordpress/2012/05/js-html5-zxx-carton-%e9%91%ab%e6%83%85%e5%8a%a8%e7%94%bb/#comments</comments>
		<pubDate>Wed, 02 May 2012 14:36:33 +0000</pubDate>
		<dc:creator>张 鑫旭</dc:creator>
				<category><![CDATA[js实例]]></category>
		<category><![CDATA[flash动画]]></category>
		<category><![CDATA[HTML5]]></category>
		<category><![CDATA[SVG]]></category>
		<category><![CDATA[transition]]></category>
		<category><![CDATA[动画效果]]></category>

		<guid isPermaLink="false">http://www.zhangxinxu.com/wordpress/?p=2367</guid>
		<description><![CDATA[大学时期，因为兴趣，花了不少时间学习flash动画制作以及AS脚本。后来开发个人网站时候，一方面想自娱自乐，另一方面由于这份无法割舍的情愫，开辟了个“阳光鑫情”的频道。要知道，这玩意很耗精力的。后来，工作忙了，任务重了，还要博客这块的压力，我只是个普通凡人，无法同时专注于几个事情，因此，“阳光鑫情”就让它去海南晒太阳去了。上周五一节前的几天，基本上没有什么活，各种x, y, z因素参杂在一起，让我突然脑中灯泡一亮——我是不是可以用HTML5实现“鑫情动画”？……

本文就将展示如何使用HTML5以及简单的JavaScript代码实现类似Flash的动画效果。]]></description>
			<content:encoded><![CDATA[<p>by <a href="http://www.zhangxinxu.com/">zhangxinxu</a> from <a href="http://www.zhangxinxu.com/">http://www.zhangxinxu.com</a><br />
本文地址：<a href="http://www.zhangxinxu.com/wordpress/?p=2367">http://www.zhangxinxu.com/wordpress/?p=2367</a></p>
<p>本文小动漫demo访问点击后面：<a class="a_link" target="_blank" href="http://www.zhangxinxu.com/study/201204/zxx-carton-test%28svg%29.html">zxx-carton-test(svg).html</a></p>
<h3>一、关于鑫情动画</h3>
<p>大学时期，因为兴趣，花了不少时间学习flash动画制作以及AS脚本。后来开发个人网站时候，一方面想自娱自乐，另一方面由于这份无法割舍的情愫，开辟了个“阳光鑫情”<br />
的频道（目前<a href="http://www.zhangxinxu.com/">首页</a>即可见）。<br />
<img alt="首页的阳光鑫情栏目导航 张鑫旭-鑫空间-鑫生活" src="http://image.zhangxinxu.com/image/blog/201205/2012-05-02_164919.png" title="首页的阳光鑫情栏目导航" class="alignnone" width="225" height="100" /></p>
<p>就是类似下面截图的，自己开发（播放器），自己配音，自己手绘人物、场景的轻松小动漫。<br />
<img alt="鑫情动画播放器截图 张鑫旭-鑫空间-鑫生活" src="http://image.zhangxinxu.com/image/blog/201205/2012-05-02_164934.png" title="鑫情动画播放器截图" class="alignnone" width="380" height="237" /></p>
<p>要知道，这玩意很耗精力的。<br />
首先录音：表情啊，语调啊什么的要一气呵成，所以经常因为一些瑕疵不能重来；而后音频处理：主要包括降噪，静音，长度精简等；接着手绘：要根据音频内容在flash软件上绘制合适的人物以及场景，虽然都是傻傻简单的人物造型，真正绘制起来，也要一顿饭的功夫；然后动画呈现：根据音频语句关键时间点添加合适的关键帧，制作动画，还要手动更改同步字幕。最后发布：要导出flash，在photoshop中处理截图（尺寸限制，大小优化），然后后台上传。</p>
<p>Adobe Audition → Adobe Flash → Adobe Photoshop</p>
<p>后来，工作忙了，任务重了，还要博客这块的压力，我只是个普通凡人，无法同时专注于几个事情，因此，“阳光鑫情”就让它去海南晒太阳去了。</p>
<p>就像男女朋友一样，即使已经分手很久了，也可能对EX念念不忘。</p>
<p>上周五一节前的几天，基本上没有什么活，各种x, y, z因素参杂在一起，让我突然脑中灯泡一亮——我是不是可以用HTML5实现“鑫情动画”？跑马灯式地过了遍各个环节的技术实现，发现可行。Have an idea, just do it!</p>
<p>花了几天时间折腾了下，还真像模像样的。</p>
<p>作总结有助于自我提高，同时本身具有实际应用价值，因此，分享下，顺便介绍一些HTML5小知识。</p>
<h3>二、你也可以得瑟几个搞笑小动漫</h3>
<p>我们做前端的心中也是有文艺情怀的，只是犹如醇厚的美酒，平时都窖藏的很深而已。</p>
<p>你只要略通点JS，完全可以做几个搞笑动漫，自娱自乐，一抒自己的搞笑气质和文艺情怀，哇咔咔<img alt="大笑" src="http://a.xnimg.cn/imgpro/icons/statusface/16.gif?ver=1" />。</p>
<p>您可以狠狠地点击这里（请使用FireFox, Chrome, Opera等浏览器访问，IE10应该也可以）：<a class="a_link" target="_blank" href="http://www.zhangxinxu.com/study/201204/zxx-carton-test%28svg%29.html">HTML5搞笑小动漫demo</a><br />
<img alt="html5鑫情动漫demo页面截图 张鑫旭-鑫空间-鑫生活" src="http://image.zhangxinxu.com/image/blog/201205/2012-05-02_192658.png" title="html5鑫情动漫demo页面截图 " class="alignnone" width="498" height="369" /></p>
<p><strong>如何使用？</strong><br />
首先，调用如下CSS：</p>
<div class="zxx_code">
<pre>&lt;link rel="stylesheet" href="http://www.zhangxinxu.com/study/css/zxxCarton.css" type="text/css" /></pre>
</div>
<p>然后，调用如下JS（不依赖于任何库的原生JS）：</p>
<div class="zxx_code">
<pre>&lt;script src="http://www.zhangxinxu.com/study/js/zxxCarton.js">&lt;/script></pre>
</div>
<p>最后，调用类似下面的一行脚本就可以了：</p>
<div class="zxx_code">
<pre>zxxCarton({ <span style="color:green;">/* 动画相关数据 */<span> });</pre>
</div>
<p>很简单吧！</p>
<h3>三、兴奋吧！其实你被忽悠了~~</h3>
<p>就像魔术一样，说穿了很简单，但是，一旦自己操作起来，就不是那么回事了。</p>
<p>说个最简单的，<strong>音频文件</strong>如何获取？自己录制，编辑可不是很轻松的活。除非你做无声动画（抱歉，本动画JS脚本是基于音频文件运行的），或者从网上download。即使你轻松搞到声音资源，但是考虑到不同浏览器对音频文件的支持不同，您还需要对文件做格式转换，例如从mp3格式转成ogg格式。</p>
<p>虽然芙蓉姐长得有点抽象，但是跟凤姐站一块，那活脱脱写实派了。同样的，虽然这里的音频处理要折腾点，但是，比起传统flash实现，要节约N多脑细胞和N多把妹时间。</p>
<p>拿本文演示demo举例：<br />
我是从搜狗音乐中下载了一个“笑话”音频，然后使用Adobe Audition做了简单编辑和格式转换（直接文件另存为）。一回生两回熟，有了经验后，音频部分分分钟就可以搞定了。剩下的就是填数据了。</p>
<p>对了，忘说了，还有一个可能要花点时间的就是<strong>动画元件</strong>（如场景，人物，道具等）处理了。与音频文件一样，你可以自己制作，或是从网上download；或者直接使用文字作为元件。</p>
<p>拿本文演示demo举例：<br />
里面的人物（包括baby）都自己用鼠标+画笔工具搞出来的，以SVG背景形式载入的。具体相关，后面介绍脚本数据的时候会介绍。</p>
<p>本段更多的是下点调料，重点在下一段，关于动画数据的介绍。</p>
<h3>四、将行为以数据形式呈现</h3>
<p>下面是难点也是重点，关于动画呈现的数据介绍。</p>
<p><strong>主体参数以及结构</strong>：</p>
<div class="zxx_code">
<pre>{
    <span style="color:green;">// 动画的舞台，如果使用默认的document.body, zxCarton.js会自动创建一个id为carton_container的新舞台</span>
    container: document.body,
    <span style="color:green;">// 动画默认等待播放时候显示的主标题</span>
    title: "标题",
    <span style="color:green;">// 动画默认等待播放时显示的副标题，如果不想显示副标题，可以使用空字符串</span>
    subtitle: "副标题",
    <span style="color:green;">// 必须数据，动画音频文件</span>
    audio: {
        <span style="color:green;">// IE浏览器, Chrome</span>
        urlMp3: "xxx.mp3",
        <span style="color:green;">// Opera, FireFox</span>
        urlOgg: "xxx.ogg"
    },
    <span style="color:green;">// 舞台元件显示以及运动的数据，基于时间轴</span>
    data: []
}</pre>
</div>
<p>云里雾里？下面是demo页面使用数据，一看就知庐山面目了：</p>
<div class="zxx_code">
<pre>{
    title: "测试动画",
    subtitle: "by zhangxinxu 2012-04-26",
    audio: {
        urlMp3: "baby-marry.mp3",
        urlOgg: "baby-marry.ogg"
    },
    data: []
}</pre>
</div>
<p><strong>时间轴参数</strong><br />
下面要介绍的就是上面的<code>data</code>属性，其为一个基于关键时间点的对象数组（类似于时间轴）。</p>
<p>所谓“关键时间点”，就是一段话结束的那个时间点，或是一个镜头切换的那个时间点。一个时间点上的完整数据示例如下（绿色的注释很重要）：</p>
<div class="zxx_code">
<pre>{
    <span style="color:green;">// 当前关键时间点的时间，单位是秒，如果是0，默认播放开始时候舞台呈现的一切</span>
    time: 0,
    <span style="color:green;">// 关键字text, 表示舞台上需要呈现/隐藏(值为null)某文本元件</span>
    text: {
        <span style="color:green;">// customTextId表示文本元件的唯一id, 可随意定义，用来准确匹配舞台元素</span>
        "customTextId": {
            <span style="color:green;">// 文本元件中显示的文字（支持HTML字符）</span>
            html: "文本文件中显示的文字",
            <span style="color:green;">// 文本元件的样式控制，例如这里就是文字大小100px（数值默认单位px，下同）</span>
            styles: {  fontSize: 100 }
        }
    },
    <span style="color:green;">// 关键字shape, 表示舞台上需要呈现的图形元件（背景图片形式）</span>
    shape: {
        <span style="color:green;">// 图形元件的唯一id，只能是当前元件的背景图片地址，如果同一背景图用做多个元件，可以使用customBgUrl.svg?v=1, 2, 3, ...</span>
        "customBgUrl.svg": {
            <span style="color:green;">// 图形元件的样式控制，一般只关心高宽以及位置（动画效果）</span>
            styles: {
                width: 300,
                height: 300
            },
            <span style="color:green;">// 图形元件中的对话框内容，一般用在人物对话以及物件说明上</span>
            dialog: {
                <span style="color:green;">// direction指当前对象物体（一般为说话者）的面部朝向</span>
                direction: "right",
                <span style="color:green;">// 对话框相对于当前图片元件内部的偏移位置</span>
                offsets: { x: 100, y: -10 },
                <span style="color:green;">// 对话框中的文字内容</span>
                word: "对话框中的文字内容"
            }
        }
    },
    <span style="color:green;">// 关键时间点上的字幕</span>
    title: "舞台下方呈现的字幕"
}</pre>
</div>
<p><strong>说明：</strong>无论是文字元件，或是图形元件，在下一个关键时间点（flash中的关键帧）上的时候，如果需要隐藏，则设为<code>null</code>；如果样式一样，可以设置对应的<code>styles</code>属性值为<code>null</code>, <code>{}</code>或可读性更好的<code>"same"</code>；如果有位置和尺寸的变化，仅需要设置要变化的样式即可。</p>
<p>所有的元件都是绝对定位的，因此，你无需再styles中设置position属性，更多注意力放在尺寸以及位置上。</p>
<p>对照下面demo的实际代码再次具体分析：<br />
先看看<strong>0秒</strong>时候：</p>
<div class="zxx_code">
<pre>{
    time: 0,
    text: {
        "customTextId_1": {
            html: "5个月",
            styles: {
                fontSize: 100,
                fontWeight: "bold",
                left: "50%",
                marginLeft: -125,
                top: "30%"
            }
        }
    },
    title: "结婚才5个月"
}</pre>
</div>
<p><code>time: 0</code>表示动画开始播放的第一秒舞台的呈现。只有<code>text</code>，表示舞台只有文本元件。<code>"customTextId_1"</code>表示这个文本元件的<code>id</code>为<code>customTextId_1</code>.  <code>html: "5个月"</code>表示文本元件里面显示的文字是“5个月”。<code>styles</code>就是文字的大小，位置什么的。<code>title</code>就是舞台同步字幕咯！<br />
该时间点上舞台截图如下：<br />
<img alt="0秒时候的舞台呈现状态 张鑫旭-鑫空间-鑫生活" src="http://image.zhangxinxu.com/image/blog/201205/2012-05-02_205737.png" title="0秒时候的舞台呈现状态 " class="alignnone" width="499" height="384" /></p>
<p>然后就是<strong>2.5秒</strong>的时候：</p>
<div class="zxx_code">
<pre>{
    time: 2.5,
    shape: {
        "zxx_baby_1.svg": {
            styles: {
                width: 300,
                height: 300,
                left: "30%",
                top: "25%"
            },
            dialog: null
        }
    },
    text: {
        "customTextId_1": null
    },
    title: "妻子就生下了一个白白胖胖的小男孩"
}</pre>
</div>
<p><code>time: 2.5</code>表示第<code>2.5秒</code>的时候，舞台发生一些变化。<code>text: { "customTextId_1": null }</code>表示在这个时间点上，<code>id</code>为<code>customTextId_1</code>的文本元件从舞台上移除。而新增的<code>shape</code>表示舞台添加背景图片地址为<code>zxx_baby_1.svg</code>，高宽<code>300</code>像素，左<code>30%</code>, 上<code>25%</code>的图形元件，没有对话框内容(<code>dialog: null</code>)。舞台字幕变成了“妻子……小男孩”。如下图：<br />
<img alt="2.5秒时候的舞台场景截图 张鑫旭-鑫空间-鑫生活" src="http://image.zhangxinxu.com/image/blog/201205/2012-05-02_223354.png" title="2.5秒时候的舞台场景截图" class="alignnone" width="500" height="373" /></p>
<p>下面就是第<code>7秒</code>，demo中，2.5秒→7秒是有动画的，如何实现的，如下：</p>
<div class="zxx_code">
<pre>{
    time: 7,
    shape: {
        "zxx_baby_1.svg": {
            styles: {
                width: 400,
                height: 400,
                left: "26%",
                top: "20%"
            }
        }
    },
    title: "丈夫非常地怀疑"
}</pre>
</div>
<p>前后时间点上，同一元件同时存在，且样式有差异，即默认以动画形式呈现（动画时长为前后两个时间点的时差）。因此，你只需要关心关键时间点上：各个元件存在与否，位置如何即可。例如这里，小baby图形元件尺寸变成了400 * 400,  位置也发生了移动。</p>
<p>基本上，这几个时间点将80%~90%属性以及值含义介绍了，其他一些细节等对照后面几个时间点的源代码（右键demo页面→查看页面源代码）和效果应该就明白了。为了节约篇幅，后面几个时间点就不一一详述了。</p>
<h3>五、应用到的CSS3/HTML5技术</h3>
<p>要说HTML5的应用，这里最最重要的就是<strong>audio音频</strong>使用。应用的HTML5代码类似下面：</p>
<div class="zxx_code">
<pre>&lt;audio preload="auto">
    &lt;source src="baby-marry.mp3">&lt;/source>
    &lt;source src="baby-marry.ogg">&lt;/source>
    &lt;p>您的浏览器不支持&lt;code>audio&lt;/code>元素！&lt;/p>
&lt;/audio></pre>
</div>
<p>多个source时候，浏览器会从上往下应用，例如FireFox浏览器，先玩玩<code>mp3</code>格式，发现不支持，得，继续下面一个，<code>ogg</code>格式，可以，就播放之~~</p>
<p>为了声音的播放与动画呈现同步，需要音频可以一次性播放完毕的时候在可以执行动画。因此，动画的播放控制如下(<code>audio</code>为标签为<code>&lt;audio&gt;</code>的音频元素)：</p>
<div class="zxx_code">
<pre>audio.addEventListener("<span style="color:#cd0000;">canplaythrough</span>", function() {
    <span style="color:green;">// 声音播放</span>
    this.play();

    <span style="color:green;">// 动画播放</span>
    play();
});</pre>
</div>
<p>而声音播放完毕的重新播放是调用的<code>ended</code>事件：</p>
<div class="zxx_code">
<pre>audio.addEventListener("ended", function () { }, false);</pre>
</div>
<p>在本demo中，还使用了<strong>HTML5 SVG背景技术</strong>。使用SVG背景的好处在于图形元件尺寸拉伸的时候，没有位图那样的模糊或是锯齿等。本demo的SVG背景图我是在<a href="http://www.zhangxinxu.com/sp/svg/">这个页面</a>上使用画笔画下来的。关于何为SVG, SVG如何创建，如何使用等推荐参考我之前的文章：“<a href="http://www.zhangxinxu.com/wordpress/?p=1957">使用SVG实现gradient背景渐变</a>”。这里就不详细介绍了。</p>
<p>当然，你也可以使用普通的jpg图片作为背景图。</p>
<p>您可以狠狠地点击这里：<a class="a_link" target="_blank" href="http://www.zhangxinxu.com/study/201204/zxx-carton-test%28jpg%29.html">jpg背景图作为图形元件动画demo</a><br />
<img alt="使用jpg作为图形元件背景demo 张鑫旭-鑫空间-鑫生活" src="http://image.zhangxinxu.com/image/blog/201205/2012-05-02_220417.jpg" title="使用jpg作为图形元件背景demo截图" class="alignnone" width="479" height="373" /></p>
<p>最后，动画效果是使用的CSS3的transition属性，这个讲得够多的了，不多说，有兴趣可以参考我之前的“<a href="http://www.zhangxinxu.com/wordpress/?p=1268">CSS3 Transitions, Transforms和Animation使用简介与应用展示</a>”一文，讲得很详细。</p>
<h3>六、局限、以及未来</h3>
<p>局限很明显，就是浏览器兼容性。不过，目前看来，在手机上应用是无障碍的。</p>
<p>虽然这里的HTML5实现比Flash实现省了一定的功夫，但是，从实际操作的角度讲，还是麻烦了点；而且受众也小，使用者需要懂一点JS，要懂一点音频处理等。</p>
<p>我大胆设想了下，如果浏览器可以支持音频输入录制的话，加上科大讯飞的语言识别技术和一些其他音频分析技术。对应的时间点可以自动呈现出现，对应的字幕也直接通过语言识别呈现。然后，呈现出的是可视化的操作界面，我们所要做的就是在关键时间点上创建以及移动元件，会自动生成动画数据，一旦保存到数据库，直接就可以在线生成一个网页动漫了。按照这种设想，其实就是把Flash部分动画制作功能搬到了浏览器上，集制作，发布一体。而且，学习成本低很多。</p>
<p>如果这样，可以使从事艺术的，或是医学的，或是建筑的，各行各业人都能做个简单的搞笑动漫。声音录入，简单操作，保存发布！ 妈妈再也不用担心我的动漫了，so easy! 你说，这种情景出现会不会加速我国动漫事业的发展呢？</p>
<p>呵呵，貌似有点想多了。不过，如果技术允许，这个idea做成产品还是可行的。至少目前在手机上就是可以的，手机支持声音录入，语音识别；现在不是流行你猜我画吗？再多画几张，录个音就变成搞笑动漫/文艺动漫/言情动漫/等，说不定还真会火呢？我对产品不懂，想法傻b了点，希望不要见笑。</p>
<p>原创文章，转载请注明来自<a href="http://www.zhangxinxu.com/">张鑫旭-鑫空间-鑫生活</a>[<a href="http://www.zhangxinxu.com/">http://www.zhangxinxu.com</a>]<br />
本文地址：<a href="http://www.zhangxinxu.com/wordpress/?p=2367">http://www.zhangxinxu.com/wordpress/?p=2367</a></p>
<p>（本篇完）</p>
<div class="hidden">有话要说，点击<a href="http://www.zhangxinxu.com/wordpress/2012/05/js-html5-zxx-carton-%e9%91%ab%e6%83%85%e5%8a%a8%e7%94%bb/#response">这里</a>发表评论。</div>]]></content:encoded>
			<wfw:commentRss>http://www.zhangxinxu.com/wordpress/2012/05/js-html5-zxx-carton-%e9%91%ab%e6%83%85%e5%8a%a8%e7%94%bb/feed/</wfw:commentRss>
		<slash:comments>10</slash:comments>
		</item>
		<item>
		<title>去除inline-block元素间间距的N种方法</title>
		<link>http://www.zhangxinxu.com/wordpress/2012/04/inline-block-space-remove-%e5%8e%bb%e9%99%a4%e9%97%b4%e8%b7%9d/</link>
		<comments>http://www.zhangxinxu.com/wordpress/2012/04/inline-block-space-remove-%e5%8e%bb%e9%99%a4%e9%97%b4%e8%b7%9d/#comments</comments>
		<pubDate>Tue, 24 Apr 2012 14:38:14 +0000</pubDate>
		<dc:creator>张 鑫旭</dc:creator>
				<category><![CDATA[css相关]]></category>
		<category><![CDATA[display:inline-block]]></category>
		<category><![CDATA[display:inline-table]]></category>
		<category><![CDATA[display:table]]></category>
		<category><![CDATA[font-size]]></category>
		<category><![CDATA[HTML5]]></category>
		<category><![CDATA[letter-spacing]]></category>
		<category><![CDATA[margin负值]]></category>
		<category><![CDATA[word-spacing]]></category>
		<category><![CDATA[字体]]></category>

		<guid isPermaLink="false">http://www.zhangxinxu.com/wordpress/?p=2357</guid>
		<description><![CDATA[真正意义上的inline-block水平呈现的元素间，换行显示或空格分隔的情况下会有间距。
我们使用CSS更改非inline-block水平元素为inline-block水平，也会有该问题。
这类间距有时会对我们布局，或是兼容性处理产生影响，需要去掉它，该怎么办呢？
本文的内容就是详尽展示各种去除这类元素间距的方法。一如既往，有必要的截图、demo页面以及源代码展示等。总之，希望本文的内容能够对您的学习有所帮助。]]></description>
			<content:encoded><![CDATA[<p>by <a href="http://www.zhangxinxu.com/">zhangxinxu</a> from <a href="http://www.zhangxinxu.com/">http://www.zhangxinxu.com</a><br />
本文地址：<a href="http://www.zhangxinxu.com/wordpress/?p=2357">http://www.zhangxinxu.com/wordpress/?p=2357</a></p>
<h3>一、现象描述</h3>
<p>真正意义上的inline-block水平呈现的元素间，换行显示或空格分隔的情况下会有间距，很简单的个例子：</p>
<div class="zxx_code">
<pre>&lt;input /> &lt;input type="submit" /></pre>
</div>
<p>间距就来了~~<br />
<img alt="表单控件之间的间距例子" src="http://image.zhangxinxu.com/image/blog/201204/2012-04-24_162919.png" title="表单控件之间的间距例子" class="alignnone" width="285" height="121" /></p>
<p>我们使用CSS更改非inline-block水平元素为inline-block水平，也会有该问题：</p>
<div class="zxx_code">
<pre>.space a {
    display: inline-block;
    padding: .5em 1em;
    background-color: #cad5eb;
}</pre>
</div>
<div class="zxx_code">
<pre>&lt;div class="space">
    &lt;a href="##">惆怅&lt;/a>
    &lt;a href="##">淡定&lt;/a>
    &lt;a href="##">热血&lt;/a>
&lt;/div></pre>
</div>
<p><img alt="inline-block水平元素间的间距示意 张鑫旭-鑫空间-鑫生活" src="http://image.zhangxinxu.com/image/blog/201204/2012-04-24_163352.png" title="inline-block水平元素间的间距示意" class="alignnone" width="221" height="139" /></p>
<p>您可以狠狠地点击这里：<a class="a_link" target="_blank" href="http://www.zhangxinxu.com/study/201204/inline-block-space-example.html">inline-block元素间间距demo</a></p>
<p>这种表现是符合规范的应该有的表现（如果有人认为是bug就太()ay ()oy 了）。</p>
<p>不过，这类间距有时会对我们布局，或是兼容性处理产生影响，需要去掉它，该怎么办呢？以下展示N种方法（欢迎补充）！</p>
<h3>二、方法之移除空格</h3>
<p>元素间留白间距出现的原因就是标签段之间的空格，因此，去掉HTML中的空格，自然间距就木有了。考虑到代码可读性，显然连成一行的写法是不可取的，我们可以：</p>
<div class="zxx_code">
<pre>&lt;div class="space">
    &lt;a href="##">
    惆怅&lt;/a>&lt;a href="##">
    淡定&lt;/a>&lt;a href="##">
    热血&lt;/a>
&lt;/div></pre>
</div>
<p>或者是：</p>
<div class="zxx_code">
<pre>&lt;div class="space">
    &lt;a href="##">惆怅&lt;/a
    >&lt;a href="##">淡定&lt;/a
    >&lt;a href="##">热血&lt;/a>
&lt;/div></pre>
</div>
<p>或者是借助HTML注释：</p>
<div class="zxx_code">
<pre>&lt;div class="space">
    &lt;a href="##">惆怅&lt;/a><span style="color:green;">&lt;!--
    --&gt;</span>&lt;a href="##">淡定&lt;/a><span style="color:green;">&lt;!--
    --&gt;</span>&lt;a href="##">热血&lt;/a>
&lt;/div></pre>
</div>
<p>等。</p>
<h3>三、使用margin负值</h3>
<div class="zxx_code">
<pre>.space a {
    display: inline-block;
    margin-right: -3px;
}</pre>
</div>
<p>margin负值的大小与上下文的字体和文字大小相关，其中，间距对应大小值可以参见我之前“<a href="http://www.zhangxinxu.com/wordpress/?p=1194">基于display:inline-block的列表布局</a>”一文part 6的统计表格：<br />
<img alt="inline-block元素间间隔大小与字体和文字大小之前的关系表截图" src="http://image.zhangxinxu.com/image/blog/201204/2012-04-24_205406.png" title="inline-block元素间间隔大小与字体和文字大小之前的关系表截图" class="alignnone" width="462" height="257" /></p>
<p>例如，对于12像素大小的上下文，Arial字体的<code>margin</code>负值为<code>-3</code>像素，Tahoma和Verdana就是<code>-4</code>像素，而Geneva为<code>-6</code>像素。</p>
<p>由于外部环境的不确定性，以及最后一个元素多出的父margin值等问题，这个方法不适合大规模使用。</p>
<h3>四、让闭合标签吃胶囊</h3>
<p>如下处理：</p>
<div class="zxx_code">
<pre>&lt;div class="space">
    &lt;a href="##">惆怅
    &lt;a href="##">淡定
    &lt;a href="##">热血<span style="color:#cd0000;">&lt;/a></span>
&lt;/div></pre>
</div>
<p>注意，为了向下兼容IE6/IE7等喝蒙牛长大的浏览器，最后一个列表的标签的结束（闭合）标签不能丢。</p>
<p>在HTML5中，我们直接：</p>
<div class="zxx_code">
<pre>&lt;div class="space">
    &lt;a href="##">惆怅
    &lt;a href="##">淡定
    &lt;a href="##">热血
&lt;/div></pre>
</div>
<p>好吧，虽然感觉上有点怪怪的，但是，这是OK的。</p>
<p>您可以狠狠地点击这里：<a class="a_link" target="_blank" href="http://www.zhangxinxu.com/study/201204/inline-block-space-skip-close-tag.html">无闭合标签去除inline-block元素间距demo</a></p>
<p><img alt="无闭合标签与inline-block水平元素间距的去除 张鑫旭-鑫空间-鑫生活" src="http://image.zhangxinxu.com/image/blog/201204/2012-04-24_211852.png" title="无闭合标签与inline-block水平元素间距的去除" class="alignnone" width="390" height="189" /></p>
<h3>五、使用font-size:0</h3>
<p>类似下面的代码：</p>
<div class="zxx_code">
<pre>.space {
    font-size: 0;
}
.space a {
    font-size: 12px;
}</pre>
</div>
<p>这个方法，基本上可以解决大部分浏览器下inline-block元素之间的间距(IE7等浏览器有时候会有1像素的间距)。不过有个浏览器，就是Chrome, 其默认有最小字体大小限制，因为，考虑到兼容性，我们还需要添加：<br />
类似下面的代码：</p>
<div class="zxx_code">
<pre>.space {
    font-size: 0;
    <span style="color:#cd0000;">-webkit-text-size-adjust:none;</span>
}</pre>
</div>
<p>您可以狠狠地点击这里（去年制作的一个简单demo）：<a href="http://www.zhangxinxu.com/study/201011/img-font-size-clear-blank.html" target="_blank" class="a_link">font-size:0清除换行符间隙demo</a></p>
<p><strong>补充：</strong>根据小杜在评论中中的说法，目前Chrome浏览器已经取消了最小字体限制。因此，上面的<code>-webkit-text-size-adjust:none;</code>代码估计时日不多了。</p>
<h3>六、使用letter-spacing</h3>
<p>类似下面的代码：</p>
<div class="zxx_code">
<pre>.space {
    letter-spacing: -3px;
}
.space a {
    letter-spacing: 0;
}</pre>
</div>
<p>根据我去年的测试，该方法可以搞定基本上所有浏览器，包括吃“东鞋”、“西毒(胶囊)”、“南地(沟油)”、“北钙(三鹿)”的IE6/IE7浏览器，不过Opera浏览器下有蛋疼的问题：最小间距1像素，然后，<code>letter-spacing</code>再小就还原了。</p>
<h3>七、使用word-spacing</h3>
<p>类似下面代码：</p>
<div class="zxx_code">
<pre>.space {
    word-spacing: -6px;
}
.space a {
    word-spacing: 0;
}</pre>
</div>
<p>一个是字符间距(<code>letter-spacing</code>)一个是单词间距(<code>word-spacing</code>)，大同小异。据我测试，<code>word-spacing</code>的负值只要大到一定程度，其兼容性上的差异就可以被忽略。因为，貌似，<code>word-spacing</code>即使负值很大，也不会发生重叠。</p>
<p>您可以狠狠地点击这里：<a class="a_link" target="_blank" href="http://www.zhangxinxu.com/study/201204/inline-block-space-word-spacing.html">word-spacing与元素间距去除demo</a></p>
<p>与上面demo一样的效果，这里就不截图展示了。如果您使用Chrome浏览器，可能看到的是间距依旧存在。确实是有该问题，原因我是不清楚，不过我知道，可以添加<code>display: table;</code>或<code>display:inline-table;</code>让Chrome浏览器也变得乖巧。</p>
<div class="zxx_code">
<pre>.space {
    <span style="color:#cd0000;">display: inline-table;</span>
    word-spacing: -6px;
}</pre>
</div>
<h3>八、其他成品方法</h3>
<p>下面展示的是<a href="http://yuilibrary.com/yui/docs/cssgrids/">YUI 3 CSS Grids </a>使用<code>letter-spacing</code>和<code>word-spacing</code>去除格栅单元见间隔方法（注意，其针对的是block水平的元素，因此对IE8-浏览器做了hack处理）：</p>
<div class="zxx_code">
<pre>.yui3-g {
    letter-spacing: -0.31em; <span style="color:green;">/* webkit */</span>
    *letter-spacing: normal; <span style="color:green;">/* IE < 8 重置 */</span>
    word-spacing: -0.43em; <span style="color:green;">/* IE < 8 &#038;&#038; gecko */</span>
}

.yui3-u {
    display: inline-block;
    zoom: 1; *display: inline; <span style="color:green;">/* IE < 8: 伪造 inline-block */</span>
    letter-spacing: normal;
    word-spacing: normal;
    vertical-align: top;
}</pre>
</div>
<p>以下是一个名叫<a href="http://raym31.home.comcast.net/">RayM</a>的人提供的方法：</p>
<div class="zxx_code">
<pre>li {
    display:inline-block;
    background: orange;
    padding:10px;
    word-spacing:0;
    }
ul {
    width:100%;
    display:table;  <span style="color:green;">/* 调教webkit*/</span>
    word-spacing:-1em;
}

.nav li { *display:inline;}</pre>
</div>
<p>也就是上面一系列CSS方法的组组合合。</p>
<h3>九、结语</h3>
<p>其他去除间距的方法肯定还有，欢迎大家通过<a href="#comment">评论</a>方式进行补充。上文部分方法可能有测试不周全之处，因此，部分细节上可能会有纰漏，欢迎指正。</p>
<p>参考文章：<a href="http://css-tricks.com/fighting-the-space-between-inline-block-elements/">Fighting the Space Between Inline Block Elements</a></p>
<p>原创文章，转载请注明来自<a href="http://www.zhangxinxu.com/">张鑫旭-鑫空间-鑫生活</a>[<a href="http://www.zhangxinxu.com/">http://www.zhangxinxu.com</a>]<br />
本文地址：<a href="http://www.zhangxinxu.com/wordpress/?p=2357">http://www.zhangxinxu.com/wordpress/?p=2357</a></p>
<p>（本篇完）</p>
<div class="hidden">有话要说，点击<a href="http://www.zhangxinxu.com/wordpress/2012/04/inline-block-space-remove-%e5%8e%bb%e9%99%a4%e9%97%b4%e8%b7%9d/#response">这里</a>发表评论。</div>]]></content:encoded>
			<wfw:commentRss>http://www.zhangxinxu.com/wordpress/2012/04/inline-block-space-remove-%e5%8e%bb%e9%99%a4%e9%97%b4%e8%b7%9d/feed/</wfw:commentRss>
		<slash:comments>17</slash:comments>
		</item>
		<item>
		<title>小tip: base64:URL背景图片与web页面性能优化</title>
		<link>http://www.zhangxinxu.com/wordpress/2012/04/base64-url-image-%e5%9b%be%e7%89%87-%e9%a1%b5%e9%9d%a2%e6%80%a7%e8%83%bd%e4%bc%98%e5%8c%96/</link>
		<comments>http://www.zhangxinxu.com/wordpress/2012/04/base64-url-image-%e5%9b%be%e7%89%87-%e9%a1%b5%e9%9d%a2%e6%80%a7%e8%83%bd%e4%bc%98%e5%8c%96/#comments</comments>
		<pubDate>Fri, 13 Apr 2012 11:21:03 +0000</pubDate>
		<dc:creator>张 鑫旭</dc:creator>
				<category><![CDATA[css相关]]></category>
		<category><![CDATA[base64]]></category>
		<category><![CDATA[HTTP请求]]></category>
		<category><![CDATA[readAsDataURL]]></category>
		<category><![CDATA[URL]]></category>
		<category><![CDATA[优化]]></category>
		<category><![CDATA[前端性能]]></category>
		<category><![CDATA[背景图片]]></category>
		<category><![CDATA[页面重构]]></category>

		<guid isPermaLink="false">http://www.zhangxinxu.com/wordpress/?p=2341</guid>
		<description><![CDATA[正如标题所示，本文内容就是介绍如何使用base64编码的CSS背景图片对web页面做性能优化。先介绍何为base64编码，如何base64编码，以及为何需要base64编码，最后付诸实际进行演示。
一如既往，有详尽的源代码展示，必要的截图以及demo演示页面。总之，希望本文的内容能够对你的学习有所帮助。]]></description>
			<content:encoded><![CDATA[<p>by <a href="http://www.zhangxinxu.com/">zhangxinxu</a> from <a href="http://www.zhangxinxu.com/">http://www.zhangxinxu.com</a><br />
本文地址：<a href="http://www.zhangxinxu.com/wordpress/?p=2341">http://www.zhangxinxu.com/wordpress/?p=2341</a></p>
<h3>一、base64百科</h3>
<p><a href="http://baike.baidu.com/view/469071.htm">Base64</a>是网络上最常见的用于传输8Bit字节代码的编码方式之一，可用于在HTTP环境下传递较长的标识信息。</p>
<p style="font-size:14px; padding:5px; border:1px solid #ccc; font-family:'微软雅黑'; "><strong>某人</strong>：<img src="http://img.t.sinajs.cn/t35/style/images/common/face/ext/normal/43/lxhbeicui_thumb.gif" /> 唉，我彻底废柴了，为何上面明明是中文，洒家却看不懂嘞，为什么？~~</p>
<p>好吧，我也不喜欢专业术语的解释。你只要知道，base64编码就是长得像下面这样子的代码：<br />
<code style="background-color:#f5f5f5;"><span style="color:#666;">thunder://</span>QUFodHRwOi8vd3d3LmJhaWR1LmNvbS9pbWcvc3NsbTFfbG9nby5naWZaWg==</code> </p>
<p>上面代码大家都熟悉吧，迅雷下载链接哦（咳咳，该地址很纯洁），就是base64编码后的地址，所以以后看到这种：一堆连续字母，最后有1~2个<code>"="</code>的代码就是base64。</p>
<p>base64:URL就是URL地址是base64编码的。</p>
<p>例如下面这个：</p>
<div class="zxx_code">
<pre>&lt;img src="data:image/gif;base64,<code>R0lGODlhAwADAIABAL6+vv///yH5BAEAAAEALAAAAAADAAMAAAIDjA9WADs=</code>" /></pre>
</div>
<h3>二、base64与文件数据编码</h3>
<p>在网络中，通过HTTP传输的文件还可以通过base64对数据进行编码进行传输。就如上面的这个base64的gif格式图片。当然，可以base64编码的文件不仅仅是图片，也可以是字体文件，例如(中间有缺省)：</p>
<div class="zxx_code">
<pre>@font-face{
    font-family: forTest;
    src: url(data:font/woff;charset=utf-8;base64,d09GRgABAAAAAAh4 ... RFERuENEGADl7JlY=) format('woff');
}</pre>
</div>
<p>自然，对于<code>background-image</code>图片，我们也可以使用base64编码进行传输，例如：</p>
<div class="zxx_code">
<pre>background-image:url(data:image/gif;base64,<code>R0lGODlhBAABAIABAMLBwfLx8SH5BAEAAAEALAAAAAAEAAEAAAICRF4AOw==</code>);</pre>
</div>
<p>而使用base64编码作为<code>background-image</code>图片就是本文要着重阐述的。</p>
<h3>三、如何获得图片的base64编码</h3>
<p>其实在我之前“<a href="http://www.zhangxinxu.com/wordpress/?p=1923">基于HTML5的可预览多图片Ajax上传</a>”以及“<a href="http://www.zhangxinxu.com/wordpress/?p=2136">zSlide-基于CSS3/HTML5演示文档jQuery插件</a>”实际上就与图片的base64编码的获取打过交道了。如下本地图片转换成可预览的base64编码的核心脚本：</p>
<div class="zxx_code">
<pre>var reader = new FileReader(), htmlImage;
reader.onload = function(e) {
    htmlImage = '&lt;img src="'+ e.target.result +'" /&gt;';    <span style="color:green;">// 这里<code>e.target.result</code>就是base64编码</span>
}
reader.readAsDataURL(file);</pre>
</div>
<p>上面说的你只需要了解，实际上，目前base64编码工具不少，对于我们前端制作，下面这个本地图片 base64编码获取页面是值得推荐的：<a target="_blank" href="http://www.pjhome.net/web/html5/encodeDataUrl.htm">Encode Data URL By PuterJam</a></p>
<p>直接将桌面图片拖到条条里就有了响应的<code>background-image</code> <code>url</code>属性可用的base64地址了：<br />
<img alt="在线获取本地图片base64编码使用示例  张鑫旭-鑫空间-鑫生活" src="http://image.zhangxinxu.com/image/blog/201204/2012-04-13_181415.png" title="在线获取本地图片base64编码使用示例 " class="alignnone" width="531" height="203" /></p>
<p>该转换页面的原理就是上面所说的HTML5 文件本地预览原理，具体可以自己查阅资料。</p>
<h3>四、使用base64:URL的优缺点</h3>
<p>个人觉得base64:URL传输图片文件的好处在于：</p>
<ol>
<li>减少了HTTP请求</li>
<li>某些文件可以避免跨域的问题</li>
<li>没有图片更新要重新上传，还要清理缓存的问题</li>
</ol>
<p>不足在于：</p>
<ol>
<li><strong>浏览器支持</strong><br />
使用base64编码图片作为背景图片的这种技术IE6/IE7浏览器是不支持的（IE9浏览器IE7模式下支持，这里被<a href="http://weibo.com/n/%E5%89%8D%E7%AB%AF%E7%9A%84%E9%82%A3%E7%82%B9%E7%A0%B4%E4%BA%8B">@前端的那点破事</a>鄙视了 <img src="http://a.xnimg.cn/imgpro/emotions/tie/6.gif?ver=1" />）。对于目前PC页面，兼容性问题使没有文件上传以及无需更新缓存的优点不存在了。</li>
<li><strong>增加了CSS文件的尺寸</strong><br />
base64编码图片本质上是将图片的二进制大小以一些字母的形式展示，例如一个1024字节的图片，base64编码后至少1024个字符，这个大小会被完全嵌入到CSS文件中（不过幸运的是也可以被gzip了，而图片文件被gzip效果不明显）。</li>
<li><strong>编码成本</strong><br />
图片完成后还需要base64编码，目前估计手工完成的多，因此，增加了一定的工作量，虽然不多。</li>
</ol>
<h3>五、优缺点权衡下的实际应用价值</h3>
<p>权衡上面所展示的优缺点，貌似base64:URL图片没有什么用武之地啊，实际上非也，有一种情况时有base64编码作为<code>background-image</code>背景图片利要远大于弊的。何种情况呢？</p>
<p>在web页面制作的时候，由于某些现实原因，我们可以会用到下面这一类图片：</p>
<ul id="ul">
<li>这类图片不能与其他图片以CSS Sprite的形式存在，只能独行</li>
<li>这类图片从诞生之日起，基本上很少被更新</li>
<li>这类图片的实际尺寸很小</li>
<li>这类图片在网站中大规模使用</li>
</ul>
<p>想想看，你的网站中有没有同时满足上面四条的背景图片呢？</p>
<p><span class="s">//zxx: 假设已经过去了今天朝鲜火箭勃起的时间</span></p>
<p>怎样，想到了没？提点下，例如下面这个企鹅微博中的loading gif图片(537字节，勉强算是)：</p>
<p><img src="http://mat1.gtimg.com/www/mb/images/loading.gif" width="16" height="16" alt="加载中" /></p>
<p>537字节的大小实际上还是偏大了点，让我们看个更better的例子，大家可以去<a href="http://www.douban.com/">豆瓣首页</a>，可以看到下图所示的垂直线：<br />
<img alt="" src="http://image.zhangxinxu.com/image/blog/201204/2012-04-13_173514.png" title="豆瓣首页的分隔垂线" class="alignnone" width="219" height="222" /></p>
<p>为<code>background-image</code>图片（for 等高布局）：<br />
<img alt="" src="http://image.zhangxinxu.com/image/blog/201204/2012-04-13_174042.png" title="背景图片使用证据" class="alignnone" width="450" height="122" /></p>
<p>从<code>bg_line.png</code>这样的命名可以预知（不是：<code>home_bg_line.png</code>），该背景图片会在（可以在）网站中多处使用。</p>
<p>图示平铺图片地址为：<a href="http://img3.douban.com/pics/bg_line.png">http://img3.douban.com/pics/bg_line.png</a></p>
<p>大小1 * 1 像素，png格式，大小88字节。<span class="s">//zxx: 当图片颜色简单到一定程度的时候，gif格式图片大小要小于png8, 所以，这个点如果保存成gif格式，只需要43字节，为png一半大小</span></p>
<p>像这种图片大小极小，但又占据了一次HTTP请求，同时不能与其他背景图片Sprite，而网站很多地方都使用。因此，没有什么背景图片比这个更适合使用本文的“base64:URL图片”技术进行优化了！</p>
<p>为了比对优化的好处，我们来看个实际的demo.</p>
<h3>六、base64:URL图片的实际应用</h3>
<p>我<a href="http://www.zhangxinxu.com/wordpress/">博客首页</a>的个人信息介绍处的虚点是使用背景图片实现的（考虑到IE6 dot边框跟dashed搞基，不同浏览器虚点间距差异等）。<br />
<img alt="" src="http://image.zhangxinxu.com/image/blog/201204/2012-04-13_191327.png" title="博客页面的虚点使用截图" class="alignnone" width="271" height="129" /></p>
<p>现在，demo就要展示如何使用base64:URL图片实现该虚点效果。</p>
<p>您可以狠狠地点击这里：<a class="a_link" target="_blank" href="http://www.zhangxinxu.com/study/201204/base64-url-image-data-dot.html">base64 URL虚点背景demo</a><br />
<img alt="" src="http://image.zhangxinxu.com/image/blog/201204/2012-04-13_175733.png" title="demo页面截图" class="alignnone" width="296" height="130" /></p>
<p>相关CSS代码如下：</p>
<div class="zxx_code">
<pre>.dot {
    background-image: url(data:image/gif;base64,R0lGODlhBAABAIABAMLBwfLx8SH5BAEAAAEALAAAAAAEAAEAAAICRF4AOw==);
   *background-image: url(http://www.zhangxinxu.com/wordpress/wp-content/themes/default/images/zxx_dotted.gif);    <span style="color:green;">// IE6~IE7</span>
    background-repeat: repeat-x;
    background-position: left bottom;
}</pre>
</div>
<p>可以看到，使用base64的CSS代码量基本上跟下面使用完整地址差不多，因此，对于一些级小尺寸图片，所谓增加CSS文件大小的不足可以忽略（再考虑到gzip），同时减少了1个HTTP请求，加上这个图片网站很多地方使用，因此，累积节约的HTTP请求就很惊人了。</p>
<p>当然，唯一美中不足的是，对于IE6~IE7浏览器不能享受到这种“百利仅一害”的优化技术，我们还需要专门为它们擦屁股。不过，权衡来看，还是很值得的，毕竟目前，在中国IE8浏览器是大头（就在最近），IE6, IE7 就乖乖地泻下去吧~~</p>
<p>最后，展示下demo页面YSLOW分析图吧，可以看到，没有任何CSS <code>background-image</code>请求~~<br />
<img alt="没有CSS 背景图片的请求 张鑫旭-鑫空间-鑫生活" src="http://image.zhangxinxu.com/image/blog/201204/2012-04-13_183207.png" title="没有CSS 背景图片的请求" class="alignnone" width="309" height="259" /></p>
<h3>七、虽是一篇小短文，结尾也要干爹疼</h3>
<p><img src="http://image.zhangxinxu.com/image/emtion/hum.png" width="150" height="150" style="float:left;" />IE6/IE7又一次暴露了自己的屌丝形象，对其，我已无力再次吐槽，不过，毕竟历史长河中的有功之人，就等其静静退出历史舞台吧。</p>
<p>再次提醒下，使用base64编码代替CSS背景图片是有局限性的，并不是所有图片都适合使用base64编码这种技术的。例如：<br />
1. CSS Sprite图片后期维护会死人，只能是独立图片<br />
2. 图片尺寸过大，CSS文件就会变成了臃肿的大棒子，反而不利于加载<br />
3. CSS文件的优点就是重用，因此，如果背景图片就一个地方使用，减少的请求数有限，考虑到其他成本，还不如直接使用普通url图片地址<br />
4. 如果图片经常改动，好吧，哥们，苦逼的前端加班仔中就多了一个你</p>
<p>因此，技术本身虽好，需天时地利人和方可使用。</p>
<p>在微博上，<a href="http://weibo.com/n/%E6%9C%B4%E7%81%B5">@朴灵</a>提过MHTML这个东东，好像与base64编码相关的，对此我几乎一无所知，希望有相关了解的人可以补充下。</p>
<p>另外，周末时节，想着明早可以睡到自然醒，文笔过于仓促，出现错误在所难免，文中有表述不准确的地方欢迎指正，感谢阅读，祝大家周末快乐！</p>
<p>原创文章，转载请注明来自<a href="http://www.zhangxinxu.com/">张鑫旭-鑫空间-鑫生活</a>[<a href="http://www.zhangxinxu.com/">http://www.zhangxinxu.com</a>]<br />
本文地址：<a href="http://www.zhangxinxu.com/wordpress/?p=2341">http://www.zhangxinxu.com/wordpress/?p=2341</a></p>
<p>（本篇完）</p>
<div class="hidden">有话要说，点击<a href="http://www.zhangxinxu.com/wordpress/2012/04/base64-url-image-%e5%9b%be%e7%89%87-%e9%a1%b5%e9%9d%a2%e6%80%a7%e8%83%bd%e4%bc%98%e5%8c%96/#response">这里</a>发表评论。</div>]]></content:encoded>
			<wfw:commentRss>http://www.zhangxinxu.com/wordpress/2012/04/base64-url-image-%e5%9b%be%e7%89%87-%e9%a1%b5%e9%9d%a2%e6%80%a7%e8%83%bd%e4%bc%98%e5%8c%96/feed/</wfw:commentRss>
		<slash:comments>8</slash:comments>
		</item>
		<item>
		<title>翻译：关于表单每个设计师都必须知道的10件事</title>
		<link>http://www.zhangxinxu.com/wordpress/2012/04/%e8%a1%a8%e5%8d%95%e8%ae%be%e8%ae%a1%e5%8d%81%e4%ba%8b%e9%9c%80%e7%9f%a5-10-things-every-designer-needs-know-about-forms/</link>
		<comments>http://www.zhangxinxu.com/wordpress/2012/04/%e8%a1%a8%e5%8d%95%e8%ae%be%e8%ae%a1%e5%8d%81%e4%ba%8b%e9%9c%80%e7%9f%a5-10-things-every-designer-needs-know-about-forms/#comments</comments>
		<pubDate>Wed, 11 Apr 2012 10:40:26 +0000</pubDate>
		<dc:creator>张 鑫旭</dc:creator>
				<category><![CDATA[ps相关]]></category>
		<category><![CDATA[外文翻译]]></category>
		<category><![CDATA[HTML5]]></category>
		<category><![CDATA[交互]]></category>
		<category><![CDATA[用户体验]]></category>
		<category><![CDATA[表单]]></category>
		<category><![CDATA[设计]]></category>
		<category><![CDATA[设计师]]></category>

		<guid isPermaLink="false">http://www.zhangxinxu.com/wordpress/?p=2336</guid>
		<description><![CDATA[估计没有什么比表单更让设计师出气了。表单不一定可以让（设计师）表现创意，还是可以？我们可能需要从做基本的层面，重新审视表单，理解表单——表单是用户和软件之间的对话。

忘掉切换啊，点击什么的，表单是我们数字设计师（我想应该是依赖计算机进行设计的设计人员）将面临的最富有的交互。下一次，你要对付一个表单的时候，不要认为就是要应用好看的CSS效果或是添加漂亮的jQuery特效。表单设计的水是很深的。

我已经做过上百个表单用户测试，为保险公司、假期预订交互设计过一些非常复杂的表单，以及其他很多。可能你最近使用的某个表单就是我设计的……]]></description>
			<content:encoded><![CDATA[<p>by <a href="http://www.zhangxinxu.com/">zhangxinxu</a> from <a href="http://www.zhangxinxu.com/">http://www.zhangxinxu.com</a><br />
本文地址：<a href="http://www.zhangxinxu.com/wordpress/?p=2336">http://www.zhangxinxu.com/wordpress/?p=2336</a></p>
<div id="link">
原文作者：<a href="http://www.cxpartners.co.uk/who-we-are/joe-leech/">Joe Leech</a> &#8211; 2012-04-04<br />
原文链接：<a href="http://www.netmagazine.com/features/10-things-every-designer-needs-know-about-forms">10 things every designer needs to know about forms</a><br />
翻译编辑：<a href="http://www.zhangxinxu.com/">张鑫旭</a>
</div>
<style>.css3_tucao{margin-top:.5em; border-radius:.5em; box-shadow:inset 1px 1px 1px rgba(0,0,0,.25); text-shadow:1px 1px white;}</style>
<p>为避免无用功，翻译之前先要百一下，看看是否有人已经翻译了，结果发现10年的时候有篇名字类似的译文，叫做：“<a href="http://article.yeeyan.org/view/184220/159550">每位网页设计师新手都应知道的10件事</a>”，还是不错的译文，有兴趣的可以看下。不过本文内容只是单纯针对表单设计，名字虽然匹配率高，但是内容却迥然不同。好了，节约口水，直接进入译文主体~~</p>
<p style="color:#999;"><span class="s">&#8212;&#8212;&#8212;&#8212;&#8212;- 以下为翻译全文 &#8212;&#8212;&#8212;&#8212;&#8212;&#8211;</span></p>
<p><strong>有很多设计糟糕的表单，不管你是否喜欢他们，表单都是必不可少的。Joe Leech（cxpartners负责用户体验的）将介绍其在表单设计上的一些经验。</strong></p>
<p>估计没有什么比表单更让设计师出气了。表单不一定可以让（设计师）表现创意，还是可以？我们可能需要从做基本的层面，重新审视表单，理解表单——表单是用户和软件之间的对话。</p>
<p>忘掉切换啊，点击什么的，表单是我们数字设计师（我想应该是依赖计算机进行设计的设计人员）将面临的最富有的交互。下一次，你要对付一个表单的时候，不要认为就是要应用好看的CSS效果或是添加漂亮的jQuery特效。表单设计的水是很深的。</p>
<p>我已经做过上百个表单用户测试，为保险公司、假期预订交互设计过一些非常复杂的表单，以及其他很多。可能你最近使用的某个表单就是我设计的。<span class="s">//zxx: 可有可无的牛皮糖</span></p>
<p>下面这些经验教训，我希望在我开始设计表单事前先学会之。</p>
<h3>1. 不要标记必填字段</h3>
<p>你知道小星号(*)就表示必填字段？我已经见过很多次因为这个用户测试失败。作为概念来讲，必填字段没有多大意义，等同离线（这个概念）。对于开发者，这个是很好的，他们提供了一个很好的黑白方式去完成。星号以及必填字段（导致表单完成）失败是因为他是个需要学习的行为。在用户测试中我看到的典型行为是用户在（表单）上面填写表单，结束于某个东西阻止他们时候或者他们碰了某个按钮。</p>
<p>解决方法很简单，可选字段标记，优质用户需要驻足思考是否要填写的字段处标记。</p>
<div style="padding:.5em; background-color:#eee;" class="css3_tucao">
<p><strong>散华礼弥</strong>：从原文评论来看，这一段是争议很大的一个地方：是必填字段标记呢还是非必填字段标记？</p>
<p>本文作者语法以及用词上有些怪怪的，加上缺少必要的示例，所以这段译文（虽然中文）理解起来并不顺溜，我个人觉得作者的结论应该是正确与合理的（毕竟做过大量实际用户使用的测试，比设计师或开发者的冥想要靠谱多），但是，在原因的阐述上显得单薄了点，也可能是因为自己（指译者）这方面了解不深。按照作者的解释，单纯使用（红色的*）星号标注必填字段有一定的学习成本，会让用户有学习负担，反而增加出错几率。</p>
<p>“必填选项的概念类似于离线概念”，我想可能意思指：我们平时访问网页，基本上都是处于在线状态（虽然HTML5有离线访问）（我们没有必要专门在页面上弄个符号(eg. ※)表示当前页面在线），因此，对于网页而言，离线这个概念就意义不大；同样的，表单选项基本上都是需要填写的，特意的使用某个符号标示这个必填的也是多此一举没有多大意义的概念。</p>
<p>我们或许过多地站在开发者以及软件测试人员的角度去看待表单设计了，如上面提到的“开发者的黑白方式”，因为我自己也是开发者，所以对于“星号是必填，没有星号选填”很容易理解，但是，实际用户是这种思维习惯，是这样想的吗？软件测试人员也是作为极端作恶用户（非上面提到的优质用户）去使用表单，一些站在自身角度的认知确实会让我们对表单有经久的错误认识。</p>
<p>至于最后的用户表单完成终止我想可能只指：对于大部分正常使用用户，其表单填写行为终止为被动阻止或主动点击按钮。所谓被动阻止，可能包括即时的错误提交；主动点击按钮可能包括点击按钮提交等。为寻找案例，我去了企鹅微博绑定注册页面，发现，其表单所以选项都没有必填字段的提示，所有的必填提示均出现在表单提交之时（即“用户触碰了某个按钮”“某些事件的阻止”），这些都是我比较赞同的——相对比于有些落后（指注册交互）的携程、点评之类，例如<a href="https://accounts.ctrip.com/member/emailregist.aspx">携程注册</a>每项都必填，红色星号显然多余；为空必填即时提醒容易中断用户操作，实际是稍稍落后于趋势可以进一步优化的体验。</p>
</div>
<p>下面两张截图以腾讯微博注册页面为例分别演示：阻止用户填写表单的事情，以及“不标记必填字段”。</p>
<p><img src="http://image.zhangxinxu.com/image/blog/201204/2012-04-10_223600.png" title="即时提醒中断表单完成" /></p>
<p><strong style="display:inline-block; margin-bottom:-50px; margin-left:120px; position:relative; border:3px solid red; background-color:#fff; padding:2px 5px; font-size:14px; box-shadow:2px 2px 4px rgba(0,0,0,.75);">这里所有字段都是必填的</strong>
<p><img src="http://image.zhangxinxu.com/image/blog/201204/2012-04-10_225738.png" width="472" height="331" title="不标记必填字段" style="vertical-align:top;" /></p>
<h3>2. 不要使用微调</h3>
<p>HTML5近来春风得意，其提供了很多足以亮瞎双眼的工具用来把玩。我们需要好好思考我们的新玩具是否得当。现在的数字字段（指类似<code>type="number"</code>的<code>input</code>框）都提供了小小的上下小尖角运行用户来回调数值。</p>
<p><img src="http://image.zhangxinxu.com/image/blog/201204/forms1.png" width="452" height="233" /></p>
<p>现在有两个问题。首先，浏览器默认显示的小三角真不是一般的小，点击很繁琐，你还可以想象加菲猫般的手指在iPhone上挣扎的情景。这就是所谓的费茨法则 <span style="color:#888;">（<strong>Fitt&#8217;s Law</strong>, 人机交互重要法则，其最基本的观点就是任何时候，当一个人用鼠标来移动鼠标指针时，屏幕上的目标的某些特征会使得点击变得轻松或者困难。目标离的越远，到达就越是费劲。目标越小，就越难点中）</span>，越小的东西越难点中。</p>
<p>我好想听到你在叫嚣了：你可以直接在数字文本框中键入数值啊。是的，你可以，但是，让我们看看浏览器的显示，向上向下的微调箭头使得文本框长得很像我们信赖的朋友（下拉）选择框。首次使用微调交互的用户（因为长得像下拉框）认为他们不能键入（内容）。</p>
<p>我的建议是避开知道它们（指微调表单元素）变得更普遍，或者浏览器开发者整改默认设计。</p>
<h3>3. 只有一种按钮类型或最好每个表单就一个按钮</h3>
<p>还有一个鲜为人知的心理学原理，叫做“希克法则(Hick&#8217;s Law)”，基本观点是当选项增加时，人们下决定的时间就会增加。我知道，这不是rocket science（电影，是关于青春期焦虑的喜剧佳作），但仍是值得铭记于心的规则。</p>
<p>你可以通过帮助你的优质用户做选择来帮助他们。让所有的基本按钮都是一个颜色，每页都只有一个按钮（非基本按钮）来帮助他们做选择。哪个按钮是我应该点击的呢？哦，很简单嘛，那个大大的色色的按钮！</p>
<p><img src="http://image.zhangxinxu.com/image/blog/201204/forms2.png" width="471" height="205" /></p>
<h3>4. 大块区域</h3>
<p>我之前是学神经科学的，因此研究过心理学记忆——特别是短期和工作记忆。现在当面告诉你，不，短期记忆能力不是7+/-2, 4+/-1或是人说三五句话，作为人类的我们擅于处理视觉刺激，局限是数目越小我们做得越好。将表单块分成更小的组可以让评估更容易，往往促使用户进入表单（的东西）来自他们的记忆。</p>
<p>请确保你的字段组长度大约为4。</p>
<div style="padding:.5em; background-color:#eee;" class="css3_tucao">
<p><strong>散华礼弥</strong>：我是彻底相信作者就是学神经学的，人总是某方面有问题的时候就是学习这方面东西。语句前后不通，无图无示例，生涩难懂，只能认为是英文中的文言文了，又是坑爹的一段，折腾死我了！阿门阿门。</p>
<p>本着服务大众的精神，我根据自己的理解把这段详细解释下：首先要大致知道这里的“短期记忆(short-term memory, STM)”是什么东西，1974年，“短期记忆”概念被“<a href="http://baike.baidu.com/view/1009037.htm">工作记忆(working memory, WM)</a>”所代替。工作记忆指的是一个容量有限的系统，用来暂时保持和存储信息，是知觉、长时记忆和动作之间的接口，因此是思维过程的一个基础支撑结构。</p>
<p>Baddeley提出的工作记忆包括三个部分：</p>
<ol>
<li>基于语音的语音环。主要用于记住词的顺序。</li>
<li>视空图像处理器。重要用于加工视觉和空间信息。</li>
<li>类似于注意的中枢系统。主要用于分配注意资源，控制加工过程。</li>
</ol>
<p>因此，作者所说的“短期记忆能力不是7+/-2, 4+/-1或是人说三五句话”是指短期记忆不（只）是用来记住计算值（基于语音<sup>1</sup>，心中有声音），或是刚刚说过的几句话（基于语音<sup>1</sup>，嘴巴有声音），还包括人类擅长的视觉加工处理（视空图像处理<sup>2</sup>），但是不足在于数目有限制，下面这个例子有助于理解这里所说的限制：</p>
<p>拿回忆一个新的七位数的电话号码举例。对大多数人来说，它通常只有六到七个数字。换句话说，工作记忆的能力是有限的。某些脑损伤的病人除了他们听到的最后一个字母外，别的一概回忆不起来，但他们的意识却正常。</p>
<p>因此，作者才要求表单块状区域化（便于视觉记忆 &#8211; 短期记忆），同时控制数目在4个左右（多了会超出工作记忆的能力）。</p>
</div>
<h3>5. 想想你为何对某事抱有疑问，对于用户感觉又如何</h3>
<p>这可能是我给出的最直接的建议，但经常是利用率最低的。</p>
<p>见下图：<br /><img src="http://image.zhangxinxu.com/image/blog/201204/forms3.png" width="472" height="155" /></p>
<p>质疑你提出的每个问题。有必要吗？那是什么感觉要问这个？</p>
<p>很多业务需要问问题，作为设计师的我们可以争得面红耳赤（原文说的是争得脸都蓝了）。有必要提这样的问题，对于了解我们的业务需要这样可以让我们妥协的数据（译者：我想应该指问问题得到的数据）。</p>
<p>我们可以通过告诉我们的优质用户我们为何需要问那样的问题再帮助它们。放心的使用和数据共享通常都是好的。</p>
<p>再次示例：<br /><img src="http://image.zhangxinxu.com/image/blog/201204/forms4.png" /></p>
<p>仍是一个艰难的提问，但是希望我们尝到了药丸的甜头。</p>
<div style="padding:.5em; background-color:#eee;" class="css3_tucao">
<p><strong>散华礼弥</strong>：作者又在说些有的没的的，唉~~ 实际上作者意思应该是：我们要帮助用户（站在用户角度，自己作为用户）提问，同时，显示告知用户想知道的答案。</p>
</div>
<p>下图为译者的补充截图：<br /><img src="http://image.zhangxinxu.com/image/blog/201204/2012-04-11_161225.png" width="411" height="222" /></p>
<p><img src="http://image.zhangxinxu.com/image/blog/201204/2012-04-11_161912.png" width="558" height="106" alt="腾讯微博中的用户提问" /></p>
<p style="color:#888;">//zxx: 下面为广告~~注意不要勿点~~嘻嘻~~</p>
<div style="width:468px; padding:5px; background-color:#cad5eb;">
<script type="text/javascript">google_ad_client = "ca-pub-0090627341039040";google_ad_slot = "6836958449";google_ad_width = 468;google_ad_height = 60;</script><script type="text/javascript" src="http://pagead2.googlesyndication.com/pagead/show_ads.js"></script>
</div>
<h3>6. 日期是个不安分的家伙</h3>
<p>输入日期确实是个挑战，有些缺陷你可以避免。单一的最大问题是错误的处理。</p>
<p>最简单的方法是浮出日历。值得注意的是在英国一周开始于星期一，而在美国则是星期天。如果你的用户注意力不集中，他们可能选择星期天，而实际上他们本想选择星期一的。</p>
<p>同样需要注意的是国际日期的格式。在美国，最开始的是月份，而在日本，最前面的是年份。因此，日期<code>4/5/12</code>可以以三种方式解释。</p>
<p>这就是为什么最好使用选择框。<br /><img src="http://image.zhangxinxu.com/image/blog/201204/forms5.png" width="420" height="281" /></p>
<p>下图为译者补充截图（还是企鹅微博注册页）：<br /><img src="http://image.zhangxinxu.com/image/blog/201204/2012-04-11_165828.png" width="448" height="143" alt="腾讯微博日期使用下拉选择" title="腾讯微博日期使用下拉选择" /></p>
<h3>7. 表单是开发者的工艺品</h3>
<p>与设计师一样，表单也是开发人员的工艺品。了解输入数据可能出现的错误以及设计应付的后端代码是一项挑战（译者：算是对开发人员的赞许，有戴高帽子之嫌，哈哈）。</p>
<p>下面很简单例子。输入货币值。用户可能犯很严重的错误。迫使用户满足某种特定的格式会让用户沮丧，让我们来正视它，这是开发人员这边的偷懒（译者：作者应该认为，对于开发人员而言，匹配固定格式比各种形式都匹配要轻松些，因此，迫使用户满足特定格式是开发人员的一点懒惰）。<br /><img src="http://image.zhangxinxu.com/image/blog/201204/forms6.png" /></p>
<p>对于开发人员而言，没有什么挑战好过构建防弹表单（指防御能力很强的表单）了。</p>
<div style="padding:.5em; background-color:#eee;" class="css3_tucao">
<p><strong>散华礼弥</strong>：我想这部分应该是写给开发人员看的吧，意思是说，为了更好的用户体验，你们开发人员不要偷懒，要多辛苦点。然后再用“构建固若金汤的表单”是很有挑战很有成就感的事来激励开发人员~~</p>
</div>
<h3>8. 不要在表单中使用垂直分栏（列）</h3>
<p>在表单中使用列的最大问题是流动。表单开始于上面，结束语底部，而列的出现会打破这种流动。</p>
<p>不要假设用户通过标签访问表单，而因此以列的形式导航表单。在用户测试中，这种情况是罕见的。大部分情况下，我们看到的是：输入细节，使用鼠标/触控板/手指点击进入下一个字段，然后再输入内容，等~~</p>
<h3>9. 一个输入框可以搞定的时候就不要使用两个</h3>
<p>大部分用户不是盲打，在用户测试中，我们可以看到人在输入内容时候都要看键盘。</p>
<p>当要往表单中输入电话号码的时候，会要求添加区号和电话号码，哦，问题来了。用户看不到，或确实记不住这儿有两个输入框，结果第一个框输入了完整数字，如果这个文本框限制了一定数目的字符限制，问题就更糟了。</p>
<p>电话号码就使用一个字段，同样的，门牌号/街道什么的都是如此 &#8211; 只使用一个文本输入框。。</p>
<h3>10. 友善点</h3>
<p>你会惊讶到底有多少相当粗鲁的错误消息出现在这里或那里。</p>
<p>下面是我最近碰到的一个例子：<br /><img src="http://image.zhangxinxu.com/image/blog/201204/forms7.png" width="468" height="237" /></p>
<p>事实明摆着你可以选择一个未来时间，结果出现了滑稽的反应，恩，不太好。</p>
<p>你作为用户设身处地想一下，作为用户，看到这个错误提示会有什么反应。恼火？或许更糟糕。亲切友善是容易的。</p>
<p>我折腾了一个图片（如下，点击可以查看超大图），它包含有更多的最佳实践方法，以设计出更好的表单。</p>
<p><a target="_blank" href="http://image.zhangxinxu.com/image/blog/201204/v1-Form-design-crib-sheet1.png" title="点击查看大图"><img src="http://image.zhangxinxu.com/image/blog/201204/v1-Form-design-crib-sheet-small1.png" width="294" height="413" style="padding:5px; border:1px solid #bbb; background-color:#f0f3f9;" onmouseover="this.style.borderColor='#34538b';" onmouseout="this.style.borderColor='#bbb';" /></a></p>
<div style="padding:.5em; background-color:#eee;" class="css3_tucao">
<p><strong>散华礼弥</strong>：我眼泪都要飙出来了，作者大人你果然很腹黑，怎么只指出问题啊？如何解决完善，以及如何避免至少也要提一下嘛。</p>
</div>
<p style="color:#999;"><span class="s">&#8212;&#8212;&#8212;&#8212;&#8212;- 以上为翻译全文 &#8212;&#8212;&#8212;&#8212;&#8212;&#8211;</span></p>
<p>作者貌似是个英国佬，不循规蹈矩的语句以及一些不太懂的英式幽默可苦了我了。至此，完毕，感谢阅读。<img src="http://img.t.sinajs.cn/t35/style/images/common/face/ext/normal/3d/lxhlalalala_thumb.gif" align="absmiddle" /></p>
<p>原创文章，转载请注明来自<a href="http://www.zhangxinxu.com/">张鑫旭-鑫空间-鑫生活</a>[<a href="http://www.zhangxinxu.com/">http://www.zhangxinxu.com</a>]<br />
本文地址：<a href="http://www.zhangxinxu.com/wordpress/?p=2336">http://www.zhangxinxu.com/wordpress/?p=2336</a></p>
<div class="hidden">
<p>觉得这里的文章不错，希望他一直走下去？您可以：<a target="_blank" href="https://me.alipay.com/zhangxinxu" title="小小赞助大大帮助"><img src="/wordpress/wp-content/themes/default/images/pay_encourage.png" width="159" height="37" alt="支付鼓励" align="absmiddle" /></a></p>
</div>
<p>（本篇完）</p>
<div class="hidden">有话要说，点击<a href="http://www.zhangxinxu.com/wordpress/2012/04/%e8%a1%a8%e5%8d%95%e8%ae%be%e8%ae%a1%e5%8d%81%e4%ba%8b%e9%9c%80%e7%9f%a5-10-things-every-designer-needs-know-about-forms/#response">这里</a>发表评论。</div>]]></content:encoded>
			<wfw:commentRss>http://www.zhangxinxu.com/wordpress/2012/04/%e8%a1%a8%e5%8d%95%e8%ae%be%e8%ae%a1%e5%8d%81%e4%ba%8b%e9%9c%80%e7%9f%a5-10-things-every-designer-needs-know-about-forms/feed/</wfw:commentRss>
		<slash:comments>4</slash:comments>
		</item>
		<item>
		<title>漫谈js自定义事件、DOM/伪DOM自定义事件</title>
		<link>http://www.zhangxinxu.com/wordpress/2012/04/js-dom%e8%87%aa%e5%ae%9a%e4%b9%89%e4%ba%8b%e4%bb%b6/</link>
		<comments>http://www.zhangxinxu.com/wordpress/2012/04/js-dom%e8%87%aa%e5%ae%9a%e4%b9%89%e4%ba%8b%e4%bb%b6/#comments</comments>
		<pubDate>Sun, 01 Apr 2012 10:06:42 +0000</pubDate>
		<dc:creator>张 鑫旭</dc:creator>
				<category><![CDATA[js实例]]></category>
		<category><![CDATA[addEventListener]]></category>
		<category><![CDATA[attachEvent]]></category>
		<category><![CDATA[createEvent]]></category>
		<category><![CDATA[dispatchEvent]]></category>
		<category><![CDATA[dom]]></category>
		<category><![CDATA[javascript]]></category>
		<category><![CDATA[onpropertychange]]></category>
		<category><![CDATA[兼容性]]></category>
		<category><![CDATA[原型]]></category>
		<category><![CDATA[对象字面量]]></category>
		<category><![CDATA[继承]]></category>
		<category><![CDATA[自定义事件]]></category>

		<guid isPermaLink="false">http://www.zhangxinxu.com/wordpress/?p=2330</guid>
		<description><![CDATA[<a href="http://www.zhangxinxu.com/wordpress/?p=2330"><img src="http://image.zhangxinxu.com/image/blog/201204/js-custom-events.jpg" alt="js自定义事件、DOM自定义事件" title="点击查看本文" width="550" height="170" class="imgpad mb10" /></a>
最近文章产量虽多，但大多都是短篇。本文断断续续折腾了差不多有一周，现在终于出炉了。主要是介绍了JS的自定义事件以及如何在DOM元素上自定义事件。循序渐进，娓娓道来，纯粹JS知识与理论。详尽的代码展示，制作精良的demo测试页面，必要的截图示意，相信本文的内容会对您的学习有所帮助的（如果你对JS有兴趣的话），不信？读一读就知道了。
]]></description>
			<content:encoded><![CDATA[<p>by <a href="http://www.zhangxinxu.com/">zhangxinxu</a> from <a href="http://www.zhangxinxu.com/">http://www.zhangxinxu.com</a><br />
本文地址：<a href="http://www.zhangxinxu.com/wordpress/?p=2330">http://www.zhangxinxu.com/wordpress/?p=2330</a></p>
<h3>一、说明、引言</h3>
<p>我JS还是比较薄弱的，本文的内容属于边学边想边折腾的碎碎念，可能没什么条理，可能有表述不准确的地方，可能内容比较拗口生僻。如果您时间紧迫，或者JS造诣已深，至此您就可以点击右侧广告（木有？则RSS或盗版）然后撤了。</p>
<p>事件是个大课题，真要从断奶开始讲起的话，可以写个12期的连载。关于JS事件的文章（类似DOM/BOM事件模型，IE与其他浏览器事件差异，DOM1/DOM2事件定义等）落叶般随处可见。熟豆子反复炒一点意思都没有，因此，这里谈谈自己感兴趣的自定义事件以及周边。</p>
<p>所谓自定义事件，就是有别于有别于带有浏览器特定行为的事件(类似<code>click</code>, <code>mouseover</code>, <code>submit</code>, <code>keydown</code>等事件)，事件名称可以随意定义，可以通过特定的方法进行添加，触发以及删除。</p>
<h3>二、JS自定义事件</h3>
<p>循序渐进便于接收。慢慢来~~</p>
<p>先看个简单的事件添加的例子：</p>
<div class="zxx_code">
<pre>element.addEventListener("click", function() {
    <span style="color:green;">// 我是临时工</span>
});</pre>
</div>
<p>这是个简单的为DOM元素分配事件处理函数的方法(IE 不支持)，有别于：</p>
<div class="zxx_code">
<pre>element.onclick = function() {
   <span style="color:green;">// 我是临时工</span>
};</pre>
</div>
<p><code>addEventListener()</code>可以为元素分配多个处理函数（而非覆盖），因此，我们可以继续：</p>
<div class="zxx_code">
<pre>element.addEventListener("click", function() {
    <span style="color:green;">// 我是二代临时工</span>
});</pre>
</div>
<p>然后，当<code>element</code>被click(点击)的时候，就会连续触发“临时工”和“二代临时工”函数。</p>
<p><strong>抽象→具象→本质→数据层</strong><br />你有没有觉得这种行为表现有点类似于往长枪里面塞子弹(add)，（扣动扳手 &#8211; click）发射的时候按照塞进去的顺序依次出来。这种行为表现为我们实现自定义事件提供了思路：我们可以定义一个数组，当添加事件的时候，我们push进去这个事件处理函数；当我们执行的时候，从头遍历这个数组中的每个事件处理函数，并执行。</p>
<p>当多个事件以及对应数据处理函数添加后，我们最终会得到一个类似下面数据结构的对象：</p>
<div class="zxx_code">
<pre>
_listener = {
    "click": [func1, func2],
    "custom": [func3],
    "defined": [func4, func5, func6]
}
</pre>
</div>
<p>因此，如果我们脱离DOM, 纯碎在数据层面自定义事件的话，我们只要以构建、遍历和删除<code>_listener</code>对象为目的即可。</p>
<p><strong>函数式实现</strong><br />还是那句话，循序渐进，我们先看看函数式的实现（只展示骨干代码）：</p>
<div class="zxx_code">
<pre>
var _listener = {};
var addEvent = function(type, fn) {
    <span style="color:green;">// 添加</span>
};
var fireEvent = function(type) {
    <span style="color:green;">// 触发</span>
};
var removeEvent = function(type, fn) {
    <span style="color:green;">// 删除</span>
};
</pre>
</div>
<p>上面的代码虽然显得比较初级，但是目的亦可实现。例如：</p>
<div class="zxx_code">
<pre>addEvent("alert", function() {
    alert("弹出！");
});

<span style="color:green;">// 触发自定义alert事件</span>
fireEvent("alert");</pre>
</div>
<p>但是，函数式写法缺点显而易见，过多暴露在外的全局变量（全局变量是魔鬼），方法无级联等。这也是上面懒得显示完整代码的原因，略知即可。</p>
<p><strong>字面量实现</strong><br />众所周知，减少全局变量的方法之一就是使用全局变量（其他如闭包）。于是，我们稍作调整（代码较长，为限制篇幅，使用了滚动条，<a href="javascript:" id="togglePreBtn" title="点击进行展开与收起的JS交互">完整显示点击这里</a> &#8211; <span style="color:#999;">JS交互,  RSS中无效果</span>）：</p>
<div class="zxx_code">
<pre id="longPreCode" style="height:200px; padding:5px; overflow:auto; resize:both; background-color:#fff;">var Event = {
    _listeners: {},
    <span style="color:green;">// 添加</span>
    <span style="color:#cd0000;">addEvent</span>: function(type, fn) {
        if (typeof this._listeners[type] === "undefined") {
            this._listeners[type] = [];
        }
        if (typeof fn === "function") {
            this._listeners[type].push(fn);
        }
        return this;
    },
    <span style="color:green;">// 触发</span>
    <span style="color:#cd0000;">fireEvent</span>: function(type) {
        var arrayEvent = this._listeners[type];
        if (arrayEvent instanceof Array) {
            for (var i=0, length=arrayEvent.length; i&lt;length; i+=1) {
                if (typeof arrayEvent[i] === "function") {
                    arrayEvent[i]({ type: type });
                }
            }
        }
        return this;
    },
    <span style="color:green;">// 删除</span>
    <span style="color:#cd0000;">removeEvent</span>: function(type, fn) {
    	var arrayEvent = this._listeners[type];
        if (typeof type === "string" &#038;&#038; arrayEvent instanceof Array) {
            if (typeof fn === "function") {
                <span style="color:green;">// 清除当前type类型事件下对应fn方法</span>
                for (var i=0, length=arrayEvent.length; i&lt;length; i+=1){
                    if (arrayEvent[i] === fn){
                        this._listeners[type].splice(i, 1);
                        break;
                    }
                }
            } else {
                <span style="color:green;">// 如果仅仅参数type, 或参数fn邪魔外道，则所有type类型事件清除</span>
                delete this._listeners[type];
            }
        }
        return this;
    }
};</pre>
</div>
<p>使用类似下面：</p>
<div class="zxx_code">
<pre>Event.<span style="color:#cd0000;">addEvent</span>("alert", function() {
    alert("弹出！");
});

<span style="color:green;">// 触发自定义alert事件</span>
Event.<span style="color:#cd0000;">fireEvent</span>("alert");</pre>
</div>
<p>您可以狠狠地点击这里：<a class="a_link" target="_blank" href="http://www.zhangxinxu.com/study/201203/js-custom-events-literal.html">JS自定义事件字面量书写demo</a></p>
<p>默认页面<code>document</code>通过<code>Event.addEvent()</code>绑定了两个自定义的<code>alert</code>事件，因此，此时您点击页面的空白区域（非按钮与示例代码区域），就会有如下图所示的连续两个alert框：</p>
<p><img src="http://image.zhangxinxu.com/image/blog/201203/2012-03-30_212105.png" width="279" height="180" /> <img src="<br />
http://image.zhangxinxu.com/image/blog/201203/2012-03-30_212127.png" width="276" height="180" /></p>
<p>demo页面还有两个按钮，用来清除已经绑定的<code>alert</code>事件。第一个按钮清除所有<code>alert</code>事件，而点击第二个按钮清除第一个<code>alert</code>事件。例如我们点击第二个按钮：</p>
<p><img src="http://image.zhangxinxu.com/image/blog/201203/2012-03-30_212553.png" width="298" height="111" /></p>
<p>清除完毕后再点击页面的空白区域， 您会发现只会弹出“第二个弹出！”字样的弹出框了。这表明，第一个绑定自定义事件被remove掉了。</p>
<p>字面量实现虽然减少了全局变量，但是其属性方法等都是暴露而且都是唯一的，一旦某个关键属性(如<code>_listeners</code>)不小心在某事件处reset了下，则整个全局的自定义事件都会崩溃。因此，我们可以进一步改进，例如，使用原型链继承，让继承的属性(如<code>_listeners</code>)即使出问题也不会影响全局。</p>
<p><strong>原型模式实现</strong><br />代码如下（相比上面增加了<code>addEvents</code>, <code>fireEvents</code>, <code>removeEvents</code>多事件绑定、执行与删除方法，篇幅较长，增加滚动限高，<a href="javascript:" id="togglePreBtn2">点击这里完整展示</a> &#8211; <span style="color:#999;">JS交互,  RSS中无效果</span>）（一堆代码看得头大，建议直接跳过）：</p>
<div class="zxx_code">
<pre id="longPreCode2" style="height:200px; padding:5px; overflow:auto; resize:both; background-color:#fff;">var EventTarget = function() {
    this._listener = {};
};

EventTarget.prototype = {
    constructor: this,
    <span style="color:#cd0000;">addEvent</span>: function(type, fn) {
        if (typeof type === "string" &amp;&amp; typeof fn === "function") {
            if (typeof this._listener[type] === "undefined") {
                this._listener[type] = [fn];
            } else {
                this._listener[type].push(fn);
            }
        }
        return this;
    },
    <span style="color:#cd0000;">addEvents</span>: function(obj) {
        obj = typeof obj === "object"? obj : {};
        var type;
        for (type in obj) {
            if ( type &amp;&amp; typeof obj[type] === "function") {
                this.addEvent(type, obj[type]);
            }
        }
        return this;
    },
    <span style="color:#cd0000;">fireEvent</span>: function(type) {
        if (type &amp;&amp; this._listener[type]) {
            var events = {
                type: type,
                target: this
            };

            for (var length = this._listener[type].length, start=0; start&lt;length; start+=1) {
                this._listener[type][start].call(this, events);
            }
        }
        return this;
    },
    <span style="color:#cd0000;">fireEvents</span>: function(array) {
        if (array instanceof Array) {
            for (var i=0, length = array.length; i&lt;length; i+=1) {
                this.fireEvent(array[i]);
            }
        }
        return this;
    },
    <span style="color:#cd0000;">removeEvent</span>: function(type, key) {
        var listeners = this._listener[type];
        if (listeners instanceof Array) {
            if (typeof key === "function") {
                for (var i=0, length=listeners.length; i&lt;length; i+=1){
                    if (listeners[i] === listener){
                        listeners.splice(i, 1);
                        break;
                    }
                }
            } else if (key instanceof Array) {
                for (var lis=0, lenkey = key.length; lis&lt;lenkey; lis+=1) {
                    this.removeEvent(type, key[lenkey]);
                }
            } else {
                delete this._listener[type];
            }
        }
        return this;
    },
    <span style="color:#cd0000;">removeEvents</span>: function(params) {
        if (params instanceof Array) {
            for (var i=0, length = params.length; i&lt;length; i+=1) {
                this.removeEvent(params[i]);
            }
        } else if (typeof params === "object") {
            for (var type in params) {
                this.removeEvent(type, params[type]);
            }
        }
        return this;
    }
};</pre>
</div>
<p>啰哩吧嗦的代码直接跳过，其实上面代码跟字面量方法相比，就是增加了下面点东西：</p>
<div class="zxx_code">
<pre>var EventTarget = function() {
    this._listener = {};
};

EventTarget.prototype = {
    constructor: this,
    <span style="color:green;">// .. 完全就是字面量模式实现脚本</span>
};</pre>
</div>
<p>然后，需要实现自定义事件功能时候，先<code>new</code>构造下：</p>
<div class="zxx_code">
<pre>var myEvents = new EventTarget();
var yourEvents = new EventTarget();</pre>
</div>
<p>这样，即使<code>myEvents</code>的事件容器<code>_listener</code>跛掉，也不会污染<code>yourEvents</code>中的自定义事件(<code>_listener</code>安然无恙)。</p>
<p>您可以狠狠地点击这里：<a target="_blank" class="a_link" href="http://www.zhangxinxu.com/study/201203/js-custom-events-prototypal.html">原型模式下的JS自定义事件demo</a></p>
<p>从demo右半区域的源代码展示可以看出如何使用<code>addEvents</code>, <code>fireEvents</code>方法同时添加和触发多个自定义事件的。</p>
<p><img src="http://image.zhangxinxu.com/image/blog/201203/2012-03-31_165054.png" width="492" height="322" /></p>
<p style="color:#888;">//zxx: 下面为广告~~注意不要勿点~~嘻嘻~~</p>
<div style="width:468px; padding:5px; background-color:#cad5eb;">
<script type="text/javascript">google_ad_client = "ca-pub-0090627341039040";google_ad_slot = "6836958449";google_ad_width = 468;google_ad_height = 60;</script><script type="text/javascript" src="http://pagead2.googlesyndication.com/pagead/show_ads.js"></script>
</div>
<div class="hidden"><em>如果您看到下面的文字，可能是由于在其他网站或是RSS中阅读本文，本文原地址：<a href="http://www.zhangxinxu.com/wordpress/?p=2330">http://www.zhangxinxu.com/wordpress/?p=2330</a>，本文作者：<a href="http://www.zhangxinxu.com/">张鑫旭</a>，来自张鑫旭-鑫空间-鑫生活，访问原出处阅读体验更佳。</em></div>
<h3>三、DOM自定义事件</h3>
<p>我们平常所使用的事件基本都是与DOM元素相关的，例如点击按钮，文本输入等，这些为自带浏览器行为事件，而自定义事件与这些行为无关。例如：</p>
<div class="zxx_code">
<pre>element.addEventListener("alert", function() {
    alert("弹出！");
});</pre>
</div>
<p>这里的<code>alert</code>就属于自定义事件，后面的<code>function</code>就是自定义事件函数。而这个自定义事件是直接绑定在名为<code>element</code>的DOM元素上的，因此，这个称之为自定义DOM事件。</p>
<p>由于浏览器的差异，上面的<code>addEventListener</code>在IE浏览器下混不来(<code>attachEvent</code>代替)，因此，为了便于规模使用，我们需要新的添加事件方法名（合并<code>addEventListener</code>和<code>attachEvent</code>），例如<code>addEvent</code>, 并附带事件触发方法<code>fireEvent</code>, 删除事件方法<code>removeEvent</code>，(命名均参考自MooTools库)。</p>
<p>如何直接在DOM上扩展新的事件处理方法，以及执行自定义的事件呢？</p>
<p>如果不考虑IE6/7浏览器，我们可以直接在DOM上进行方法扩展。例如添加个<code>addEvent</code>方法：</p>
<div class="zxx_code">
<pre>
<span style="color:#909;">HTMLElement</span>.<span style="color:#069;">prototype</span>.<span style="color:#cd0000;">addEvent</span> = function(type, fn, capture) {
    var el = this;
    if (window.addEventListener) {
        el.addEventListener(type, function(e) {
            fn.call(el, e);
        }, capture);
    } else if (window.attachEvent) {
        el.attachEvent("on" + type, function(e) {
            fn.call(el, e);
        });
    }
};</pre>
</div>
<style>.s code{color:#666;}</style>
<p style="color:#888; font-family:simsun;"><span class="s">//zxx: 上面代码中的<code>HTMLElement</code>表示HTML元素。以一个<code>&lt;p&gt;</code>标签元素举例，其向上寻找原型对象用过会是这样：<code>HTMLParagraphElement.prototype</code> → <code>HTMLElement.prototype</code> → <code>Element.prototype</code> → <code>Node.prototype</code> → <code>Object.prototype</code> → <code>null</code>。这下您应该知道<code>HTMLElement</code>所处的位置了吧，上述代码<code>HTMLElement</code>直接换成<code>Element</code>也是可以的，但是会让其他元素（例如文本元素）也扩展<code>addEvent</code>方法，有些浪费了。</span></p>
<p>这样，我们就可以使用扩展的新方法给元素添加事件了，例如一个图片元素：</p>
<div class="zxx_code">
<pre>elImage.addEvent("click", function() {
    alert("我是点击图片之后的弹出！");
});</pre>
</div>
<p>由于IE6, IE7浏览器的DOM水平较低，无法直接进行扩展，因此，原型扩展的方法在这两个浏览器下是行不通的。要想让这两个浏览器也支持<code>addEvent</code>方法，只能是页面载入时候遍历所有DOM，然后每个都直接添加<code>addEvent</code>方法了。</p>
<div class="zxx_code">
<pre>var elAll = <span style="color:#069;">document.all</span>, lenAll = elAll.length;
for (var iAll=0; iAll&lt;lenAll; iAll+=1) {
    elAll[iAll].<span style="color:#cd0000;">addEvent</span> = function(type, fn) {
        var el = this;
        el.attachEvent("on" + type, function(e) {
            fn.call(el, e);
        });
    };
}</pre>
</div>
<p>您可以狠狠地点击这里：<a class="a_link" target="_blank" href="http://www.zhangxinxu.com/study/201203/js-dom-events-extend-by-prototype.html">基于DOM扩展自定义方法demo</a></p>
<p>点击demo页面张含韵小姐年轻时候相片，就会有该图片<code>alt</code>属性值。</p>
<p><img src="http://image.zhangxinxu.com/image/blog/201203/2012-03-31_232024.png" width="413" height="220" /></p>
<p>测试代码如下(demo页面有代码完整展示)：</p>
<div class="zxx_code">
<pre>&lt;img id="image" src="http://image.zhangxinxu.com/image/study/s/s256/mm1.jpg" alt="年轻的张含韵" />

document.getElementById("image").<span style="color:#cd0000;">addEvent</span>("click", function() {
    alert("这是：" + this.alt);
});</pre>
</div>
<p><strong>只能点到为止</strong><br />直接在DOM上进行事件方法扩展其实是个糟糕的做法，因此，这里我并没有对自定义事件做进一步深入探讨（这个下一部分会讲）。</p>
<p>基于DOM扩展缺点有：缺少标准无规律、提高冲突可能性、性能以及浏览器支持。<br />扩展名字任意命，很有可能就会与未来DOM浏览器本身支持的方法相互冲突；扩展无规律，很有可能出现A和B同名不同功能的扩展而造成冲突；IE6-7浏览器下所有扩展都要通过遍历支持，其性能开销可想而知；另外IE8对DOM扩展的支持并不完整，例如其支持<code>Element.prototype</code>，却没有<code>HTMLElement.prototype</code>.</p>
<p>虽然我从事的站点就是基于MooTools库的，但是，我对MooTools库基于DOM扩展方法的做法是不支持的。相反，我更亲近jQuery库的做法，也就是下面要讲的“伪DOM自定义事件”。</p>
<h3>四、伪DOM自定义事件</h3>
<p>这里的“伪DOM自定义事件”是自己定义的一个名词，用来区分DOM自定义事件的。例如jQuery库，其是基于包装器（一个包含DOM元素的中间层）扩展事件的，既与DOM相关，又不直接是DOM，因此，称之为“伪DOM自定义事件”。</p>
<p style="color:#888;"><span class="s">//zxx: 下面即将展示的代码目的在于学习与认识，要想实际应用可能还需要在细节上做些调整。例如，下面测试的包装器仅仅只是包裹DOM元素，并非选择器之类；<code>$</code>符号未增加冲突处理，且几个重要方法都暴露在全局环境中，没有闭包保护等。</span></p>
<p>原型以及<code>new</code>函数构造不是本文重点，因此，下面这个仅展示：</p>
<div class="zxx_code">
<pre>var $ = function(el) {
    return new _$(el);
};
var _$ = function(el) {
    this.el = el;
};
_$.prototype = {
    constructor: this,
    addEvent: function() {
        <span style="color:green;">// ...</span>
    },
    fireEvent: function() {
        <span style="color:green;">// ...</span>
    },
    removeEvent: function() {
        <span style="color:green;">// ...</span>
    }
}</pre>
</div>
<p>于是我们就可以使用类似<code>$(dom).addEvent()</code>的语法为元素添加事件了（包括不包含浏览器行为的自定义事件）。</p>
<p><strong>自定义事件的添加</strong><br />如果只考虑事件添加，我们的工作其实很简单，根据支持情况，<code>addEventListener</code>与<code>attachEvent</code>方法分别添加事件（<code>attachEvent</code>方法后添加事件先触发）即可：</p>
<div class="zxx_code">
<pre>addEvent: function(type, fn, capture) {
    var el = this.el;
    if (window.addEventListener) {
        el.addEventListener(type, fn, capture);
    } else if (window.attachEvent) {
        el.attachEvent("on" + type, fn);
    }
    return this;
}
</pre>
</div>
<p>显然，事情不会这么简单，有句古话叫做“上山容易下山难”，自定义事件添加容易，但是如何触发它们呢？——考虑到自定义事件与浏览器行为无关，同时浏览器没有直接的触发事件的方法。</p>
<p><strong>自定义事件的触发</strong><br />又是不可避免的，由于浏览器兼容性问题，我们要分开说了，针对标准浏览器和IE6/7等考古浏览器。</p>
<p><strong>1. 对于标准浏览器</strong>，其提供了可供元素触发的方法：<code>element.dispatchEvent()</code>. 不过，在使用该方法之前，我们还需要做其他两件事，及创建和初始化。因此，总结说来就是：</p>
<div class="zxx_code">
<pre>document.createEvent()
event.initEvent()
element.dispatchEvent()</pre>
</div>
<p>举个板栗：</p>
<div class="zxx_code">
<pre>$(dom).addEvent("alert", function() {
    alert("弹弹弹，弹走鱼尾纹~~");
});

<span style="color:green;">// 创建</span>
var evt = document.createEvent("HTMLEvents");
<span style="color:green;">// 初始化</span>
evt.initEvent("alert", false, false);

<span style="color:green;">// 触发, 即弹出文字</span>
dom.dispatchEvent(evt);
</pre>
</div>
<p><code>createEvent()</code>方法返回新创建的<code>Event</code>对象，支持一个参数，表示事件类型，具体见下表：</p>
<table width="400" border="0" cellspacing="1" cellpadding="0" class="params_table">
<tr>
<th scope="col">参数</th>
<th scope="col">事件接口</th>
<th scope="col">初始化方法</th>
</tr>
<tr>
<td>HTMLEvents</td>
<td>HTMLEvent</td>
<td>iniEvent()</td>
</tr>
<tr>
<td>MouseEvents</td>
<td>MouseEvent</td>
<td>iniMouseEvent()</td>
</tr>
<tr>
<td>UIEvents</td>
<td>UIEvent</td>
<td>iniUIEvent()</td>
</tr>
</table>
<p>关于<code>createEvent()</code>方法我自己了解也不是很深入，不想滥竽充数，误人子弟，所以您有疑问我可能作答不了，希望对熟知该方法的人可以做进一步的解释说明（例如事件接口与<code>document</code>关系，<code>UIEvent</code>是什么东西等）。</p>
<p><code>initEvent()</code>方法用于初始化通过<code>DocumentEvent</code>接口创建的<code>Event</code>的值。支持三个参数：<code>initEvent(eventName, canBubble, preventDefault)</code>. 分别表示事件名称，是否可以冒泡，是否阻止事件的默认操作。</p>
<p><code>dispatchEvent()</code>就是触发执行了，<code>dom.dispatchEvent(eventObject)</code>, 参数<code>eventObject</code>表示事件对象，是<code>createEvent()</code>方法返回的创建的<code>Event</code>对象。</p>
<p><strong>2. 对于IE浏览器</strong>，由于向下很多版本的浏览器都不支持<code>document.createEvent()</code>方法，因此我们需要另辟蹊径（据说IE有<code>document.createEventObject()</code>和<code>event.fireEvent()</code>方法，但是不支持自定义事件~~）。</p>
<p>IE浏览器有不少自给自足的东西，例如下面要说的这个<code>"propertychange"</code>事件，顾名思意，就是属性改变即触发的事件。例如文本框<code>value</code>值改变，或是元素<code>id</code>改变，或是绑定的事件改变等等。</p>
<p>我们可以利用这个IE私有的东西实现自定义事件的触发，大家可以先花几分钟想想……</p>
<p><span class="s" style="color:#999;">// zxx: 假设几分钟已经过去了……</span></p>
<p>大家现在有思路了没？其实说穿了很简单，当我们添加自定义事件的时候，顺便给元素添加一个自定义属性即可。例如，我们添加自定义名为<code>"alert"</code>的自定义事件，顺便我们可以对元素做点小手脚：</p>
<div class="zxx_code">
<pre>dom.evtAlert = "2012-04-01";</pre>
</div>
<p>再顺便把自定义事件<code>fn</code>塞到<code>"propertychange"</code>事件中：</p>
<div class="zxx_code">
<pre>dom.attachEvent("onpropertychange", function(e) {
    if (e.propertyName == "evtAlert") {
        fn.call(this);
    }
});</pre>
</div>
<p>这个，当我们需要触发自定义事件的时候，只要修改DOM上自定义的<code>evtAlert</code>属性的值即可：</p>
<div class="zxx_code">
<pre>dom.evtAlert = Math.random();	<span style="color:green;">// 值变成随机数</span></pre>
</div>
<p>此时就会触发<code>dom</code>上绑定的<code>onpropertychange</code>事件，又因为修改的属性名正好是<code>"evtAlert"</code>, 于是自定义的<code>fn</code>就会被执行。这就是IE浏览器下事件触发实现的完整机制，应该说讲得还是蛮细的。</p>
<p><strong>自定义事件的删除</strong><br />与触发事件不同，事件删除，各个浏览器都提供了对于的时间删除方法，如<code>removeEventListener</code>和<code>detachEvent</code>。不过呢，对于IE浏览器，还要多删除一个事件，就是为了实现触发功能额外增加的<code>onpropertychange</code>事件：</p>
<div class="zxx_code">
<pre>dom.detachEvent("onpropertychange", evt);</pre>
</div>
<p><strong>大综合</strong><br />结合上面所有论述与展示，我们可以得到类似下面的完整代码（为限制篇幅，滚动定高，想查看完整代码推荐去原demo，或是<a href="javascript:" id="togglePreBtn3">点击这里完整显示</a><span style="color:#999;">&#8211; js交互，RSS中无效果</span>。）：</p>
<div class="zxx_code">
<pre id="longPreCode3" style="height:200px; padding:5px; overflow:auto; resize:both; background-color:#fff;">var $ = function(el) {
    return new _$(el);
};
var _$ = function(el) {
    this.el = (el &#038;&#038; el.nodeType == 1)? el: document;
};
_$.prototype = {
    constructor: this,
    <span style="color:#cd0000;">addEvent</span>: function(type, fn, capture) {
        var el = this.el;
        if (window.addEventListener) {
            el.addEventListener(type, fn, capture);
            var ev = document.createEvent("HTMLEvents");
            ev.initEvent(type, capture || false, false);

            if (!el["ev" + type]) {
                el["ev" + type] = ev;
            }
        } else if (window.attachEvent) {
            el.attachEvent("on" + type, fn);
            if (isNaN(el["cu" + type])) {
                <span style="color:green;">// 自定义属性</span>
                el["cu" + type] = 0;
            }
            var fnEv = function(event) {
                if (event.propertyName == "cu" + type) { fn.call(el); }
            };
            el.attachEvent("onpropertychange", fnEv);
            if (!el["ev" + type]) {
                el["ev" + type] = [fnEv];
            } else {
                el["ev" + type].push(fnEv);
            }
        }
        return this;
    },
    <span style="color:#cd0000;">fireEvent</span>: function(type) {
        var el = this.el;
        if (typeof type === "string") {
            if (document.dispatchEvent) {
                if (el["ev" + type]) {
                    el.dispatchEvent(el["ev" + type]);
                }
            } else if (document.attachEvent) {
                el["cu" + type]++;
            }
        }
        return this;
    },
    <span style="color:#cd0000;">removeEvent</span>: function(type, fn, capture) {
        var el = this.el;
        if (window.removeEventListener) {
            el.removeEventListener(type, fn, capture || false);
        } else if (document.attachEvent) {
            el.detachEvent("on" + type, fn);
            var arrEv = el["ev" + type];
            if (arrEv instanceof Array) {
                for (var i=0; i&lt;arrEv.length; i+=1) {
                    el.detachEvent("onpropertychange", arrEv[i]);
                }
            }
        }
        return this;
    }
};</pre>
</div>
<p>您可以狠狠地点击这里：<a class="a_link" target="_blank" href="http://www.zhangxinxu.com/study/201203/js-custom-dom-events.html">JS DOM自定义事件demo</a></p>
<p>demo页面中的的张含韵小姐图片上通过级联形式联系添加了三个事件（一个是包含浏览器行为的<code>click</code>事件，还有两个是自定义不含行为的<code>alert</code>事件）：</p>
<div class="zxx_code">
<pre>$(elImage)
    .<span style="color:#cd0000;">addEvent</span>("click", funClick);
    .<span style="color:#cd0000;">addEvent</span>("alert", funAlert1)
    .<span style="color:#cd0000;">addEvent</span>("alert", funAlert2);</pre>
</div>
<p>而<code>funClick</code>方法中有等同下面脚本：</p>
<div class="zxx_code">
<pre>$(e.target).fireEvent("alert");</pre>
</div>
<p style="font-family:simsun;">因此，点击图片，才会出现三个弹出框：用户点击图片 → 执行<code>funClick</code> → 第一个弹框 → 执行<code>fireEvent</code> → 触发自定义<code>"alert"</code>事件 → 连续两个<code>"alert"</code>事件弹框</p>
<p>当点击图片下面的按钮清除掉自定义<code>"alert"</code>事件后，再点击图片就只有一个弹出咯（<code>funAlert1</code>和<code>funAlert2</code>提前回家扫墓去了）！</p>
<p><img src="http://image.zhangxinxu.com/image/blog/201204/2012-04-01_164657.png" width="262" height="130" /> <img src="http://image.zhangxinxu.com/image/blog/201204/2012-04-01_164737.png" width="378" height="206" /></p>
<p><script>var funPreHeightToggle = function(btn, pre) {btn.onclick = function() {	if (/200/.test(pre.style.height)) {		pre.style.height="auto";		this.innerHTML = this.innerHTML.replace("完整显示", "收起");	} else {		pre.style.height="200px";		this.innerHTML = this.innerHTML.replace("收起", "完整显示");	}	return false;};
};funPreHeightToggle(document.getElementById("togglePreBtn"), document.getElementById("longPreCode"));funPreHeightToggle(document.getElementById("togglePreBtn2"), document.getElementById("longPreCode2"));funPreHeightToggle(document.getElementById("togglePreBtn3"), document.getElementById("longPreCode3"));</script></p>
<h3>五、清明节前的结语</h3>
<p><img src="http://image.zhangxinxu.com/image/emtion/laugh.png" alt="鑫表情" width="150" height="150" style="float:left;" />
<p>明天回家，很显然，我要钓鱼钓死在河边上。</p>
<p>时间等客观原因，本文展示的些脚本并未做非常详尽严谨的测试，因此，不建议直接Copy到实际项目中应用，更多旨在相互交流与学习。例如在IE浏览器下，最后的“伪DOM自定义事件”，click事件通过点击触发时的事件类型(<code>event.type</code>)是<code>click</code>, 但是通过<code>fireEvent</code>触发的时候事件类型是<code>propertychange</code>, 这些细节在测试学习的时候都是可以忽略的，但是要是实际应用，这都是需要完善的。</p>
<p>本想以很通俗易懂的语言阐述我想表达的内容，但是，现在回过头看看，做得并不好，术语，啰嗦的话语还是显得多了点，这方面的功力还需要加强，或许是本身理解不透彻的缘故，无法驾驭自然无法语言通俗化。</p>
<p>虽说自己JS方面的学习比两年前要好多了（那个时候连<code>addEventListener</code>和<code>attachEvent</code>放在一起干嘛的都不清楚），但是心里清楚的很，JS还是很薄弱的，跟真正优秀的JS开发人员相比，要积累的还有很多。什么时候能够像看有色小说一样把《JavaScript语言精粹》一书读下来，恩，估计可以有脸得瑟得瑟了~~</p>
<p>本文涉及的一些知识点欢迎补充提点，有表述不准确的地方欢迎指正。</p>
<p>最后，祝大家清明节快乐！额？怎么这句话怪怪的——上坟一般快乐不起来吧~~那大家祝我清明回家钓鱼大丰收，大爆箱！！哈哈！！</p>
<p>原创文章，转载请注明来自<a href="http://www.zhangxinxu.com/">张鑫旭-鑫空间-鑫生活</a>[<a href="http://www.zhangxinxu.com/">http://www.zhangxinxu.com</a>]<br />
本文地址：<a href="http://www.zhangxinxu.com/wordpress/?p=2330">http://www.zhangxinxu.com/wordpress/?p=2330</a></p>
<div class="hidden">
<p>觉得这里的文章不错，希望他一直走下去？您可以：<a target="_blank" href="https://me.alipay.com/zhangxinxu" title="小小赞助大大帮助"><img src="/wordpress/wp-content/themes/default/images/pay_encourage.png" width="159" height="37" alt="支付鼓励" align="absmiddle" /></a></p>
</div>
<p>（本篇完）</p>
<div class="hidden">有话要说，点击<a href="http://www.zhangxinxu.com/wordpress/2012/04/js-dom%e8%87%aa%e5%ae%9a%e4%b9%89%e4%ba%8b%e4%bb%b6/#response">这里</a>发表评论。</div>]]></content:encoded>
			<wfw:commentRss>http://www.zhangxinxu.com/wordpress/2012/04/js-dom%e8%87%aa%e5%ae%9a%e4%b9%89%e4%ba%8b%e4%bb%b6/feed/</wfw:commentRss>
		<slash:comments>7</slash:comments>
		</item>
		<item>
		<title>观点：不要太依赖JavaScript库</title>
		<link>http://www.zhangxinxu.com/wordpress/2012/03/%e8%a7%82%e7%82%b9%ef%bc%9a%e4%b8%8d%e8%a6%81%e5%a4%aa%e4%be%9d%e8%b5%96javascript%e5%ba%93/</link>
		<comments>http://www.zhangxinxu.com/wordpress/2012/03/%e8%a7%82%e7%82%b9%ef%bc%9a%e4%b8%8d%e8%a6%81%e5%a4%aa%e4%be%9d%e8%b5%96javascript%e5%ba%93/#comments</comments>
		<pubDate>Thu, 29 Mar 2012 04:08:02 +0000</pubDate>
		<dc:creator>张 鑫旭</dc:creator>
				<category><![CDATA[外文翻译]]></category>
		<category><![CDATA[API]]></category>
		<category><![CDATA[HTML5]]></category>
		<category><![CDATA[javascript]]></category>
		<category><![CDATA[JavaScript库]]></category>
		<category><![CDATA[插件]]></category>

		<guid isPermaLink="false">http://www.zhangxinxu.com/wordpress/?p=2314</guid>
		<description><![CDATA[JavaScript库已经成为了一个web开发人员的工具包的重要组成部分，一个很好的理由（zxx: 应指指依赖理由）。库让每个浏览器的JavaScript实现无差异，使开发人员可以专注于编写代码，10次中有9次将只是工作 – 这是一个了不起的事情。
但你可曾停下来想过学习JavaScript，而不是一切都依靠库？尽管我不主张离开库，但我依然要给你些东西让你去思考……]]></description>
			<content:encoded><![CDATA[<p>by <a href="http://www.zhangxinxu.com/">zhangxinxu</a> from <a href="http://www.zhangxinxu.com/">http://www.zhangxinxu.com</a><br />
本文地址：<a href="http://www.zhangxinxu.com/wordpress/?p=2314">http://www.zhangxinxu.com/wordpress/?p=2314</a></p>
<style>h3{clear:both;}</style>
<div style="background-color:#f0f0f0; padding:0.5em 1em; font-size:12px; margin-bottom:1em;">本文翻译自Ross Bruniges 3月21号写的<a href="http://www.netmagazine.com/opinions/dont-rely-too-much-javascript-libraries">Don&#8217;t rely too much on JavaScript libraries</a>一文。</div>
<p>下面就来看看为何Ross Bruniges说不要过分依赖JavaScript库~~</p>
<blockquote><p><strong>库是很棒的东西，但千万不要因此让你JavaScript的学习打折扣。</strong> &#8211; by 开发者Ross Bruniges</p></blockquote>
<p>JavaScript库已经成为了一个web开发人员的工具包的重要组成部分，一个很好的理由（zxx: 应指指依赖理由）。库让每个浏览器的JavaScript实现无差异，使开发人员可以专注于编写代码，10次中有9次将只是工作 &#8211; 这是一个了不起的事情。</p>
<p>但你可曾停下来想过学习JavaScript，而不是一切都依靠库？尽管我不主张离开库，但我依然要给你些东西让你去思考，以及可能会让您更上一层楼的<em>JavaScript权威指南</em>。</p>
<h3>1. 库库也会尿裤裆，知识在手莫惊慌</h3>
<p><img alt="" src="http://image.zhangxinxu.com/image/emtion/litter-sad.png" title="鑫表情" class="" width="150" height="150" style="float:right;" />每个开发者都怕怕的事情之一就是一些你依赖的东西不顶用了（zxx: 应指冲突之类）。这可能是个核心的库函数或是插件，而这两个都是你迫切需要的（用来修复某些问题）。</p>
<p>库提供了很好的抽象层于浏览器的各种差异之上，但是，“引擎盖”下面，它们仅仅就是JavaScript, 因此，一点点的基础知识就可以让你开始明白大致哪里出了问题。即使你无法自己修正该错误，你还可以高亮错误的位置然后反馈给（编写该）库的核心团队。</p>
<h3>2. 坏坏代码难免有，越早发现越好走</h3>
<p>如果你使用允许社区插件（zxx：指论坛之类的些杂碎插件）的库（zxx: 如jQuery, 鱼龙混杂太多），您可能已经遇到了一个不得不从你项目上咔嚓掉的糟糕插件，或者你花了大量时间试图让其工作。能够注意到一种可能会造成性能问题的模式就意味着站点上线后是愉悦的还是让人不爽的客户端。</p>
<h3>3. 买爱疯，宁换肾；需不需要先自问？</h3>
<p><img alt="" src="http://image.zhangxinxu.com/image/emtion/ask.png" title="鑫表情" class="" width="150" height="150" style="float:right;" />根据你要求的功能，你需要的代码可能不需要库。例如，你只是做一些简单的dom操作，值得你一试。</p>
<p>页面的大小和性能是web上重要因素，一个JavaScript的大小20K ~ 80K大小不等。在高度连接的桌面设备上，80Kb不算多。但是，如果你的站点是针对手机用户的，则越轻量越好。我最近推出了一个CSS动画可用时只需要JavaScript的站点。</p>
<p>我决定我并不需要的库所提供的援助之手，因为我只要处理一个浏览器JavaScript实现。 最终，JavaScript的总大小约2KB。</p>
<h3>4. 国际油价要接轨，技术俱进抱大腿</h3>
<p><img alt="" src="http://image.zhangxinxu.com/image/emtion/cute.png" title="鑫表情" class="" width="150" height="150" style="float:right;" />JavaScript是一个不断发展的语言，我们现在身处一个全新的世界，远远超出我们认为可用的能力的范围。你可以在Server端使用<code>node.js</code>, 你可以通过app访问地理位置信息。HTML5提供了新的APIs，可用于控制嵌入式多媒体，信息存储，并确定你的用户是否在线。</p>
<p>因为我们正在谈论有关新技术和开发技术，文档目前的水平是能够在传统深入和密集API文档中发现所需。了解JavaScript对于你研究这些你想使用的功能会是一个巨大的帮助。许多网上例子不使用库，有助于你能够从最底层准确了解发生了什么。</p>
<h3>学习资源</h3>
<p>那么，我所说的这些对你有所触动了吗？如果是这样，开始学习的最佳之地就是你使用的JS库，在<a href="http://code.google.com/apis/library">code.google.com/apis/library</a>上有非压缩版本，而且我推荐你从最新的版本入手。</p>
<p>如果你遇到什么不懂的，可以去<a href="http://developer.mozilla.org/En/JavaScript">Mozilla MDC</a>（zxx:MDC指Mozilla Developer Center, <del datetime="2012-03-29T09:43:01+00:00">类似于国内蓝色理想</del>）寻求解释。如果你寻找HTML5提供的可能示例，<a href="http://html5demos.com/">html5demos.com</a>满是精彩而又简单的例子。</p>
<p style="color:#999;"><span class="s">&#8212;&#8212;&#8212; 以上就是翻译内容了 &#8212;&#8212;&#8212;</span></p>
<h3>译者现身说法</h3>
<p><img alt="" src="http://image.zhangxinxu.com/image/emtion/blue.png" title="鑫表情" class="" width="150" height="150" style="float:right;" />是不是感觉作者说得有点淡，一股忧郁的无力吐槽的感觉。无法让那些依赖库完成一些功能的泛泛之辈们引起重视，因此，末了，我也一舒己见。</p>
<p>首先，作者的观点我都是赞同的，但是在托辞与表达上过于苍白无力，无法发人深省，看了只会让人打瞌睡。</p>
<p>如果你认定了前端这条路，依赖JavaScript库只会让你日后成为一个悲催的前端人员：工资涨不上，新技术跟不上，混迹于各个公司间，妄图有所发展，结果都是平淡收场，虽说铁定饿不死，但是而立之年的人生压力会让你觉得混得真是惨淡。这些都是可以预见的。</p>
<p>在中国，从事所谓前端之人何其多也，可以依赖JavaScript库实现功能的人何其多也，比牛魔王身上的虱子还要多。时间流逝，就凭抱着JS库过日子，你怎么可能从这么多人之间脱颖而出（当然你爸姓李或有干爹另当别论）。</p>
<p>正如Ross Bruniges所说的，如果JS库报错或是插件冲突了，你晓得症结在哪里吗？好不容易从哪搞来个插件，效果实现了，一上线，尼玛IE6下老是爆掉，你知道什么原因吗？手机页面，没有JS库你能搞定里面的交互吗？你能读懂node.js代码吗？你能读懂HTML5 APIs文档中的JS示例代码吗？如果不能，你永远就是在别人手下干活，按部就班做事的命，这东西不是钓鱼，靠经验积累就行的。你必须好好学习原生JS, 这决定了你以后的位置和高度。</p>
<p>世事无常，如何应对风云万变，扎实的基本功才是王道（学什么新东西都快）。新技术层出不穷，各种框架、库应接不暇，三年河东三年河西，如何在时代大潮中屹立不倒？只要掌握了语言本身，才能兵来将敌水来土堰，永远不要担心没饭吃。</p>
<p>设想下，如果jQuery被国家禁止使用了，你还能完成页面上的各类交互吗？不要将自己栓死在一棵树上。</p>
<p>依赖库，只是应用；掌握核心，才能创造。应用与创造的差异不言而谕。</p>
<p>原创文章，转载请注明来自<a href="http://www.zhangxinxu.com/">张鑫旭-鑫空间-鑫生活</a>[<a href="http://www.zhangxinxu.com/">http://www.zhangxinxu.com</a>]<br />
本文地址：<a href="http://www.zhangxinxu.com/wordpress/?p=2314">http://www.zhangxinxu.com/wordpress/?p=2314</a></p>
<p>（本篇完）</p>
<div class="hidden">有话要说，点击<a href="http://www.zhangxinxu.com/wordpress/2012/03/%e8%a7%82%e7%82%b9%ef%bc%9a%e4%b8%8d%e8%a6%81%e5%a4%aa%e4%be%9d%e8%b5%96javascript%e5%ba%93/#response">这里</a>发表评论。</div>]]></content:encoded>
			<wfw:commentRss>http://www.zhangxinxu.com/wordpress/2012/03/%e8%a7%82%e7%82%b9%ef%bc%9a%e4%b8%8d%e8%a6%81%e5%a4%aa%e4%be%9d%e8%b5%96javascript%e5%ba%93/feed/</wfw:commentRss>
		<slash:comments>22</slash:comments>
		</item>
		<item>
		<title>折腾:瀑布流布局（基于多栏列表流体布局实现）</title>
		<link>http://www.zhangxinxu.com/wordpress/2012/03/%e5%a4%9a%e6%a0%8f%e5%88%97%e8%a1%a8%e5%8e%9f%e7%90%86%e4%b8%8b%e5%ae%9e%e7%8e%b0%e7%9a%84%e7%80%91%e5%b8%83%e6%b5%81%e5%b8%83%e5%b1%80-waterfall-layout/</link>
		<comments>http://www.zhangxinxu.com/wordpress/2012/03/%e5%a4%9a%e6%a0%8f%e5%88%97%e8%a1%a8%e5%8e%9f%e7%90%86%e4%b8%8b%e5%ae%9e%e7%8e%b0%e7%9a%84%e7%80%91%e5%b8%83%e6%b5%81%e5%b8%83%e5%b1%80-waterfall-layout/#comments</comments>
		<pubDate>Fri, 23 Mar 2012 14:56:57 +0000</pubDate>
		<dc:creator>张 鑫旭</dc:creator>
				<category><![CDATA[js实例]]></category>
		<category><![CDATA[inline-block]]></category>
		<category><![CDATA[两端对齐]]></category>
		<category><![CDATA[流体布局]]></category>
		<category><![CDATA[滚动加载]]></category>
		<category><![CDATA[瀑布流布局]]></category>

		<guid isPermaLink="false">http://www.zhangxinxu.com/wordpress/?p=2308</guid>
		<description><![CDATA[跟风，尤其受pinterest的煽风点火，瀑布流就有不少人关注了。我正好最近比较闲，加上有人曾在我站点提出希望我介绍点瀑布流的东西，所以，今儿个也随下大流。
pinterest以及上面迅雷UED xwei的瀑布流demo（至少在FireFox下还是有致命的显示bug的）都是采用的绝对定位实现的，有相对复杂的位置计算。
我一向不喜欢吃别人嚼过的米饭，于是尝试使用另外的原理实现。我是个流体布局控，对绝对定位啊、浮动啊什么的一向没什么好感，于是，这里要介绍的就是基于多栏列表流体布局实现的瀑布流布局效果。]]></description>
			<content:encoded><![CDATA[<p>by <a href="http://www.zhangxinxu.com/">zhangxinxu</a> from <a href="http://www.zhangxinxu.com/">http://www.zhangxinxu.com</a><br />
本文地址：<a href="http://www.zhangxinxu.com/wordpress/?p=2308">http://www.zhangxinxu.com/wordpress/?p=2308</a></p>
<h3>一、开篇无关紧要的话</h3>
<p>今天四处闲逛，看到<a href="http://cued.xunlei.com/">迅雷UED</a>xwei兄写了篇名为“浅谈个人在瀑布流网页的实现中遇到的问题和解决方法(<a href="http://cued.xunlei.com/log031">http://cued.xunlei.com/log031</a>)”的文章，我两只沉沉的萝卜眼顿时放出无数闪亮的小星星。<br />
<img alt="" src="http://image.zhangxinxu.com/image/blog/201203/lufei-eye-star.jpg" title="眼睛放星星" class="alignnone" width="440" height="313" /></p>
<p>倒不是文章本身，而是可以用来制作demo的图片资源啊，啊咔咔<img src="http://img.t.sinajs.cn/t35/style/images/common/face/ext/normal/6a/laugh.gif" />（得瑟中……）！！</p>
<p>因此，本文即将展示的demo中的图片都有迅雷UED提供，这里先郑重感谢。</p>
<h3>二、稍稍要紧的话</h3>
<p>跟风，尤其受pinterest的煽风点火，瀑布流现在不少人关注。我正好最近比较闲，加上有人曾在我站点提出希望我介绍点瀑布流的东西，所以，今儿个也随下大流。</p>
<p><a href="http://www.pinterest.com">pinterest</a>以及上面迅雷UED xwei的<a href="http://cued.xunlei.com/demos/publ/demo2.html">瀑布流demo</a>（至少在FireFox下还是有致命的显示bug的）都是采用的绝对定位实现的，有相对复杂的位置计算。</p>
<p>我一向不喜欢吃别人嚼过的米饭，于是尝试使用另外的原理实现。我是个流体布局控，对绝对定位啊、浮动啊什么的一向没什么好感，于是，这里要介绍的就是基于多栏列表流体布局实现的瀑布流布局效果。</p>
<p>大致结构、布局见下面的手绘图：<br />
<img alt="流体布局下的瀑布流结构草图 张鑫旭-鑫空间-鑫生活" src="http://image.zhangxinxu.com/image/blog/201203/2012-03-23_233114.png" title="流体布局下的瀑布流结构草图" class="alignnone" width="526" height="427" /></p>
<p>没有复杂的位置计算，不需要知道里面元素的高度以及宽度，且易理解，关键是具体实现~~</p>
<h3>三、高潮来了：demo展示</h3>
<p>您可以狠狠地点击这里：<a class="a_link" target="_blank" href="http://www.zhangxinxu.com/study/201203/waterfall-layout.html">基于多栏列表瀑布流布局demo</a></p>
<p><img alt="瀑布流demo页面效果截图 张鑫旭-鑫空间-鑫生活" src="http://image.zhangxinxu.com/image/blog/201203/2012-03-23_233833.jpg" title="瀑布流demo页面效果截图" class="alignnone" width="514" height="280" /></p>
<p>欢迎各种滚动，缩放等测试。低版本IE浏览器也是兼容滴。问题嘛也是有滴，就是滚动到一定位置再F5刷新的时候，部分加载的内容有丢失，需要重新滚动加载。这个嘛，我个人觉得小小demo，没必要折腾啦（实际上要实现也比较容易，改动如下：每次滚动不是append一个节点，而是连续回调直到加载到屏幕下方。不懂什么意思？花点功夫看看JS实现原理就会明白了）~~</p>
<h3>四、说说原理</h3>
<p>第一次进入的时候，根据浏览器宽度以及每列宽度计算出列表个数，然后不管三七二十一，每列先加载个5张图片再说。</p>
<p>当滚动的时候，对每一列的底部位置做检测，如果在屏幕中或屏幕上方，则立即append一个新图片（注意：为了简化代码，提高性能，同时便于演示等，这里只append了一个）。因为，滚动时连续的，因此，我们实际看到的效果是图片不断load出来。</p>
<p>当浏览器宽度改变的时候，页面上有个<code>id</code>为<code>waterFallDetect</code>空<code>span</code>标签，这个标签作用有两个：一是实现两端对齐效果，二是用来检测瀑布流布局是否需要刷新。</p>
<p>检测原理如下：<br />
该<code>span</code>标签宽度与一个列表宽度一致，当浏览器宽度变小的时候，如果小到一定程度，显然，浏览器最右边的列表就会跑到下一行，把空<code>span</code>挤到后面去，空<code>span</code>发生较大的水平位移，显然，可以通知脚本，布局需要刷新；当浏览器宽度变大的时候，如果变大的尺寸超过一列的宽度，显然，这个空<code>span</code>灰跑到第一行去，同样是发生较大的水平位移，因此，又可以通知脚本刷新瀑布流布局了。</p>
<p>这个方法的好处是几乎没有计算就可以一点不差地知道何时瀑布流布局需要刷新。这显然要比设置resize定时器+位置尺寸计算要简单高性能地多。</p>
<p><img alt="浏览器宽度变小时触发瀑布流更新的原理示意" src="http://image.zhangxinxu.com/image/blog/201203/2012-03-24_000610.png" title="浏览器宽度变小时触发瀑布流更新的原理示意" class="alignnone" width="401" height="397" style="vertical-align:top;" /> <img alt="浏览器宽度变宽时触发的瀑布流更新原理示意" src="http://image.zhangxinxu.com/image/blog/201203/2012-03-24_000816.png" title="浏览器宽度变宽时触发的瀑布流更新原理示意" class="alignnone" width="509" height="322" style="vertical-align:top;" /></p>
<p>滚动时的页面刷新是基于HTML字符串的处理，而不是更改每个DOM元素的位置（这是绝对定位实现的处理），因此，这里的效率显然更高。</p>
<h3>五、总结：基于多栏列表流体布局瀑布流效果优点</h3>
<ol>
<li><strong>简单</strong>：最大限度利用了浏览器的流体特性进行布局，省去了很多计算的麻烦；新人更易懂和上手</li>
<li><strong>更好的性能</strong>：这个体现在多处，如浏览器宽度改变，瀑布流刷新时候的效率等</li>
<li><strong>无需知晓尺寸</strong>：如果是要绝对定位实现瀑布流，必须知道每个小模块的高度以及宽度（否则无法定位），而基于列表的布局则无需知道高宽</li>
</ol>
<p>无聊时候的折腾，有不足与不准确之处欢迎指正。一些实现的具体细节等也是非常欢迎提问交流的。</p>
<p>原创文章，转载请注明来自<a href="http://www.zhangxinxu.com/">张鑫旭-鑫空间-鑫生活</a>[<a href="http://www.zhangxinxu.com/">http://www.zhangxinxu.com</a>]<br />
本文地址：<a href="http://www.zhangxinxu.com/wordpress/?p=2308">http://www.zhangxinxu.com/wordpress/?p=2308</a></p>
<p>（本篇完）</p>
<div class="hidden">有话要说，点击<a href="http://www.zhangxinxu.com/wordpress/2012/03/%e5%a4%9a%e6%a0%8f%e5%88%97%e8%a1%a8%e5%8e%9f%e7%90%86%e4%b8%8b%e5%ae%9e%e7%8e%b0%e7%9a%84%e7%80%91%e5%b8%83%e6%b5%81%e5%b8%83%e5%b1%80-waterfall-layout/#response">这里</a>发表评论。</div>]]></content:encoded>
			<wfw:commentRss>http://www.zhangxinxu.com/wordpress/2012/03/%e5%a4%9a%e6%a0%8f%e5%88%97%e8%a1%a8%e5%8e%9f%e7%90%86%e4%b8%8b%e5%ae%9e%e7%8e%b0%e7%9a%84%e7%80%91%e5%b8%83%e6%b5%81%e5%b8%83%e5%b1%80-waterfall-layout/feed/</wfw:commentRss>
		<slash:comments>14</slash:comments>
		</item>
	</channel>
</rss>

