<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0" xmlns:wfw="http://wellformedweb.org/CommentAPI/">
  <channel>
    <title><![CDATA[never-online]]></title> 
    <link>http://www.never-online.net/blog/</link> 
    <description><![CDATA[A crisis is a terrible thing to waste.]]></description> 
    <language>en</language> 
    <copyright><![CDATA[Copyright 2010, never-online]]></copyright> 
    <webMaster><![CDATA[blueDestiny[at]126.com (never-online)]]></webMaster> 
    <generator>LBS v2.0.304</generator> 
    <pubDate>Sat, 31 Jul 2010 20:18:00 +0800</pubDate> 
    <ttl>60</ttl>
  
    <item>
      <title><![CDATA[js selector设计及实现（二）——完善及优化]]></title> 
      <link><![CDATA[http://www.never-online.net/blog/article.asp?id=296]]></link> 
      <category><![CDATA[Web Dev]]></category> 
      <author><![CDATA[Rank <null@null.com>]]></author> 
      <pubDate>Mon, 05 Jul 2010 19:24:02 +0800</pubDate> 
      <description><![CDATA[see also <a href="http://www.never-online.net/blog/article.asp?id=295" title="http://www.never-online.net/blog/article.asp?id=295" target="_blank">js selector设计及实现（一）</a><br /><br /><b>5. 除掉重复的节点</b><br /><br />5.1 考虑selector: &quot;div div&quot;<br /><br />上面的步骤看下来还比较容易接受，那下面有头疼的问题了。<br /><br />HTML代码还是上面的代码，但换个selector来考虑，假设selector是：“div div”，如果仅是用documentElement.getElementsByTagName(&#39;div&#39;)，再循环该集合获取&#39;div&#39;而没有形成上述的NodeFilter函数进行过滤，再合并的时候获取的节点集合就会有重复了。<br />为说明问题，看下面的代码：<div class="code-op"><a href="javascript:NS_code.copy('codeFragment1')" title="拷贝代码(Copy Code)">Copy Code(拷贝代码)</a>-<a href="javascript:NS_code.runHTML('codeFragment1')" title="运行代码(Run HTML Code)">Run HTML(运行代码)</a>-<a href="javascript:NS_code.saveAs('codeFragment1')" title="另存代码(Save Code)">Save Code(另存代码)</a></div><div class="code" id="codeFragment1">&lt;html&gt;<br />&lt;body&gt;<br />&lt;div id=&quot;1&quot;&gt;<br />&nbsp;&nbsp;&lt;div id=&quot;2&quot;&gt;<br />&nbsp;&nbsp;&nbsp;&nbsp;&lt;div id=&quot;3&quot;&gt;&lt;/div&gt;<br />&nbsp;&nbsp;&lt;/div&gt;<br />&nbsp;&nbsp;&lt;div id=&quot;4&quot;&gt;<br />&nbsp;&nbsp;&nbsp;&nbsp;&lt;div id=&quot;5&quot;&gt;&lt;/div&gt;<br />&nbsp;&nbsp;&lt;/div&gt;<br />&lt;/div&gt;<br />&lt;/body&gt;<br />&lt;/html&gt;<br />&lt;script type=&quot;text/javascript&quot;&gt;<br />/**<br />HTMLElement Collection转化成Array<br />*/<br />var makeArray = (function(arr) {<br />&nbsp;&nbsp;if (!!window.ActiveXObject) {<br />&nbsp;&nbsp;&nbsp;&nbsp;return function(arr) {<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;var result = [], len=arr.length;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;for (var i=0; i&lt;len; i++) result.push(arr[i]);<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return result;<br />&nbsp;&nbsp;&nbsp;&nbsp;}<br />&nbsp;&nbsp;} else {<br />&nbsp;&nbsp;&nbsp;&nbsp;return function(arr) {<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return Array.prototype.slice.call(arr,0); <br />&nbsp;&nbsp;&nbsp;&nbsp;}<br />&nbsp;&nbsp;}<br />})(),<br /><br />isie = !!window.ActiveXObject;<br /><br />(function () {<br />&nbsp;&nbsp;var divs   = document.documentElement.getElementsByTagName(&#39;div&#39;);<br />&nbsp;&nbsp;var result = [];<br />&nbsp;&nbsp;for (var i=0; i&lt;divs.length; i++) {<br />&nbsp;&nbsp;&nbsp;&nbsp;result = result.concat(makeArray(divs[i].getElementsByTagName(&#39;div&#39;)));<br />&nbsp;&nbsp;}<br />&nbsp;&nbsp;alert(result.length);<br />&nbsp;&nbsp;return result; //这里的result是对的吗？<br />})();<br /><br />!isie ? alert(&#39;正确答案是&#39; +document.querySelectorAll(&#39;div div&#39;).length) : &#39;&#39;;<br />&lt;/script&gt;</div>如上面所说，我们还不能单纯的concat，如果concat后还需要除掉重复的节点（除重）。（除重代码较简单略过。）<br />如果除重，会有很大的性能损失。约N^2的算法。<br /><br />那么考虑下怎么优化下这个性能。<br />从DOM的树结构入手，如果说我们第一次能拿到DOM树的第一层div节点，用第一层的div节点分别调用getElementsByTagName(&#39;div&#39;)，再合并，这就是正确的结果。<br />问题是没有一个方法能够获取某个tagName第一层的节点集合的方法。<br />但是根据树的有序原理做一个优化。<br />用document.documentElement.getElementByTagName(&#39;div&#39;)得到的节点集合肯定是id为[1,2,3,4,5,6]的节点集合。<br />树节点是一个有序的结点集合，父节点肯定是在前，子节点是在后。<br />如果要找到&quot;div div&quot;的第一层的节点就可以利用这一特性来处理，看代码吧：<div class="code-op"><a href="javascript:NS_code.copy('codeFragment2')" title="拷贝代码(Copy Code)">Copy Code(拷贝代码)</a>-<a href="javascript:NS_code.runHTML('codeFragment2')" title="运行代码(Run HTML Code)">Run HTML(运行代码)</a>-<a href="javascript:NS_code.saveAs('codeFragment2')" title="另存代码(Save Code)">Save Code(另存代码)</a></div><div class="code" id="codeFragment2">&lt;html&gt;<br />&lt;body&gt;<br />&lt;div id=&quot;1&quot;&gt;<br />&nbsp;&nbsp;&lt;div id=&quot;2&quot;&gt;<br />&nbsp;&nbsp;&nbsp;&nbsp;&lt;div id=&quot;3&quot;&gt;&lt;/div&gt;<br />&nbsp;&nbsp;&lt;/div&gt;<br />&nbsp;&nbsp;&lt;div id=&quot;4&quot;&gt;<br />&nbsp;&nbsp;&nbsp;&nbsp;&lt;div id=&quot;5&quot;&gt;&lt;/div&gt;<br />&nbsp;&nbsp;&lt;/div&gt;<br />&lt;/div&gt;<br />&lt;/body&gt;<br />&lt;/html&gt;<br />&lt;script type=&quot;text/javascript&quot;&gt;//&lt;![CDATA[<br />/**<br />快速判断contains方法<br />*/<br />var dom_contains = document.compareDocumentPosition ? function(a, b) {<br />&nbsp;&nbsp;return !!(a.compareDocumentPosition(b) &amp; 16);<br />} : function(a, b){<br />&nbsp;&nbsp;return a !== b &amp;&amp; (a.contains ? a.contains(b) : true);<br />};<br />/**<br />HTMLElement Collection转化成Array<br />*/<br />var makeArray = (function(arr) {<br />&nbsp;&nbsp;if (!!window.ActiveXObject) {<br />&nbsp;&nbsp;&nbsp;&nbsp;return function(arr) {<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;var result = [], len=arr.length;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;for (var i=0; i&lt;len; i++) result.push(arr[i]);<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return result;<br />&nbsp;&nbsp;&nbsp;&nbsp;}<br />&nbsp;&nbsp;} else {<br />&nbsp;&nbsp;&nbsp;&nbsp;return function(arr) {<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return Array.prototype.slice.call(arr,0); <br />&nbsp;&nbsp;&nbsp;&nbsp;}<br />&nbsp;&nbsp;}<br />})();<br /><br />(function() {<br /><br />var divs = document.documentElement.getElementsByTagName(&#39;div&#39;);<br />divs = makeArray(divs);<br /><br />for (var i=1; i&lt;divs.length; i++) {<br />&nbsp;&nbsp;if (dom_contains(divs[i-1], divs[i])) { <br />&nbsp;&nbsp;//除重，复杂度N。<br />&nbsp;&nbsp;//如果dom里前者包含后者，则移者后者<br />&nbsp;&nbsp;//当前循环标记-1<br />&nbsp;&nbsp;//结果将是<br />&nbsp;&nbsp;//第一轮：[1,3,4,5,6], i=1<br />&nbsp;&nbsp;//第二轮：[1,4,5,6] i=1<br />&nbsp;&nbsp;//第三轮：[1,5,6] i=1<br />&nbsp;&nbsp;//第四轮：[1,6] i=1<br />&nbsp;&nbsp;//第五轮：[1] i=1<br />&nbsp;&nbsp;&nbsp;&nbsp;divs.splice(i,1);<br />&nbsp;&nbsp;&nbsp;&nbsp;i--;<br />&nbsp;&nbsp;}<br />}<br /><br />alert(divs);<br /><br />}());<br />//]]&gt;&lt;/script&gt;</div><br />5.2 上述去重的缺陷<br />虽然上述的去重策略的性能不错，但也不是万能。上述的selector是个特例。（selector为&quot;div div&quot;）<br /><b>上述的除重策略只能用在前一个关系符是空格，随后的一个关系符也是空格的情况下使用。</b><br />例如说selector不是包含选择符的情况下，就会有问题。例如selector为&quot;div~div div&quot;的情况。这时用上述的策略就会有问题。（此部分不再多述，有兴趣的同学可以试一下，画个简单树图就能明白了）<br />那这个时候就要用传统的除重方法——即求并集。<div class="code-op"><a href="javascript:NS_code.copy('codeFragment3')" title="拷贝代码(Copy Code)">Copy Code(拷贝代码)</a>-<a href="javascript:NS_code.runHTML('codeFragment3')" title="运行代码(Run HTML Code)">Run HTML(运行代码)</a>-<a href="javascript:NS_code.saveAs('codeFragment3')" title="另存代码(Save Code)">Save Code(另存代码)</a></div><div class="code" id="codeFragment3">&lt;script type=&quot;text/javascript&quot;&gt;//&lt;![CDATA[<br />Array.prototype.indexOf = function(obj,fromIdx){<br />&nbsp;&nbsp;var arr = this, len = arr.length;<br />&nbsp;&nbsp;fromIdx=fromIdx|0;//取整<br />&nbsp;&nbsp;if(fromIdx&lt;0) fromIdx+=len;<br />&nbsp;&nbsp;if(fromIdx&lt;0) fromIdx=0;<br />&nbsp;&nbsp;for(; fromIdx &lt; len; fromIdx ++){<br />&nbsp;&nbsp;&nbsp;&nbsp;if(fromIdx in arr &amp;&amp; arr[fromIdx] === obj) return fromIdx;<br />&nbsp;&nbsp;}<br />&nbsp;&nbsp;return -1;<br />}<br />Array.prototype.contains = function(a) {<br />&nbsp;&nbsp;return this.indexOf(a)&gt;-1;<br />};<br />Array.prototype.uniquelize = function(){<br />&nbsp;var ra = [];<br />&nbsp;for(var i = 0; i &lt; this.length; i ++){<br />&nbsp;if(!ra.contains(this[i])){<br />&nbsp;ra.push(this[i]);<br />&nbsp;}<br />&nbsp;}<br />&nbsp;return ra;<br />};<br />Array.prototype.union = function(b){<br />&nbsp;return this.concat(b).uniquelize();<br />};<br />alert([1,2,3].union([2,3,4]));<br />//]]&gt;&lt;/script&gt;</div><br />5.3 伪类。<br /><br />关系符我们没有疑问了；属性选择符我们没有疑问了；标签元素我们也没有疑问了。<br />最后还有伪类。上面提到我们的总体思路都是得到HTMLElements然后通过过滤函数进行筛选，伪类这里也不另外。<br /><br />伪类做的时候需要注意的也就是两个较麻烦点：<ul class="ubb-list" ><li>nth伪类。——用来做斑马线很管用。div.grid:nth-child(2n)，div.grid:nth-child(2n+1)，下面会详细说。</li><li>not伪类。——要了解not伪类。not伪类可以这么写&quot;div div:not([className~=&#39;test&#39;])&quot;，意味着not里可以递归selector。</li></ul>5.3.1 nth<br /><br />nth最常见的应用是用在制作斑马线。选择奇数行或偶数列。<br />没用过的同学先扫下盲，如nth-child伪类，在css selector里对nth-child的定义是：<div class="quote"><div class="quote-title">引用 <u></u></div><div class="quote-content">nth-child(N): matches elements on the basis of their positions within a parent element&#39;s list of child elements.</div></div>使用方法如：<br />#table tr:nth-child(2n+1)义为：选中id为table中tr元素的奇数行。<br /><br />nth值的格式有两种：<div class="quote"><div class="quote-title">引用 <u></u></div><div class="quote-content">1. odd或even，非奇则偶<br />2. 表达式。 a*n+b。这个等式的结果等于当前元素在父元素下的索引。a，b变量都由用户写，也是自然数。例如2n+1（奇），2n（偶）等。</div></div>5.3.1.1 nth实现过程<br /><br />例如最常见的query(&quot;#table tr:nth-child(2n+1)&quot;);选中table中tr元素的奇数行。<br /><br />在这里过滤函数 = ((父元素里的索引值 - 1)是 % 2) 是否等于0。<br />那如何得到当前元素在父元素下的索引？——初始化时可以循环父元素的childNodes，添加自定义属性。过滤函数直接读这个HTMLElement的自定义属性当索引值。并为父元素置上标记，以免下次nth时再建一次索引。<br /><div class="code-op"><a href="javascript:NS_code.copy('codeFragment4')" title="拷贝代码(Copy Code)">Copy Code(拷贝代码)</a>-<a href="javascript:NS_code.runHTML('codeFragment4')" title="运行代码(Run HTML Code)">Run HTML(运行代码)</a>-<a href="javascript:NS_code.saveAs('codeFragment4')" title="另存代码(Save Code)">Save Code(另存代码)</a></div><div class="code" id="codeFragment4">&lt;table cellpadding=&quot;0&quot; cellspacing=&quot;0&quot; border=&quot;0&quot; width=&quot;100%&quot;&gt;<br />&lt;tr&gt;<br />&nbsp;&nbsp;&lt;td&gt;test&lt;/td&gt;<br />&nbsp;&nbsp;&lt;td&gt;tet&lt;/td&gt;<br />&nbsp;&nbsp;&lt;td&gt;test&lt;/td&gt;<br />&lt;/tr&gt;<br />&lt;tr id=&quot;trtest&quot;&gt;<br />&nbsp;&nbsp;&lt;td&gt;test nth&lt;/td&gt;<br />&nbsp;&nbsp;&lt;td&gt;test nth&lt;/td&gt;<br />&nbsp;&nbsp;&lt;td&gt;test nth&lt;/td&gt;<br />&lt;/tr&gt;<br />&lt;tr&gt;<br />&nbsp;&nbsp;&lt;td&gt;test&lt;/td&gt;<br />&nbsp;&nbsp;&lt;td&gt;test&lt;/td&gt;<br />&nbsp;&nbsp;&lt;td&gt;test&lt;/td&gt;<br />&lt;/tr&gt;<br />&lt;/table&gt;<br />&lt;script&gt;<br />var timestamp = new Date*1;<br /><br />function buildIndex(el) {<br />&nbsp;&nbsp;var p = el.parentNode;<br />&nbsp;&nbsp;var c = p.childNodes;<br />&nbsp;&nbsp;var index = 1;<br />&nbsp;&nbsp;for (var i=0, l=c.length; i&lt;l; i++) {<br />&nbsp;&nbsp;&nbsp;&nbsp;if (c[i].tagName) c[i]._index = index++; //建索引<br />&nbsp;&nbsp;}<br />&nbsp;&nbsp;p._timestamp = timestamp;//时间戳<br />&nbsp;&nbsp;p._length = index;//总长度<br />};<br /><br />function getIndex(el) {<br />&nbsp;&nbsp;//如果时间戳变了，则重建索引<br />&nbsp;&nbsp;if (el.parentNode._timestamp!=timestamp) buildIndex(el);<br />&nbsp;&nbsp;return el._index;<br />};<br /><br />alert(getIndex(document.getElementById(&#39;trtest&#39;)));<br />&lt;/script&gt;</div><br /><b>6. selector的内部代码结构大致设计</b><br />selector也要考虑扩展，例如标准里伪类以后增加了怎么办？使用者要为自己加个几伪类怎么办？<br />最好的方式是将上面的selector实现抽象一下，将所有的过滤函数封装成配置一样的JSON对象，使得以后灵活的控制。<br /><br />原来本来还画了个图的，后来一想算了，就几个方法，大致看下代码结构就好：<br />文后会给出详细的selector实现代码。<div class="code-op"><a href="javascript:NS_code.copy('codeFragment5')" title="拷贝代码(Copy Code)">Copy Code(拷贝代码)</a>-<a href="javascript:NS_code.runHTML('codeFragment5')" title="运行代码(Run HTML Code)">Run HTML(运行代码)</a>-<a href="javascript:NS_code.saveAs('codeFragment5')" title="另存代码(Save Code)">Save Code(另存代码)</a></div><div class="code" id="codeFragment5">&lt;script type=&quot;text/javascript&quot;&gt;<br />//Fox为主要命名空间<br />var Fox  = {<br /><br />&nbsp;&nbsp;/**<br />&nbsp;&nbsp;* 程序入口点，即浏览器里的document.querySelectorAll函数<br />&nbsp;&nbsp;*/<br />&nbsp;&nbsp;query: function(selector, context) {},<br /><br />&nbsp;&nbsp;/** <br />&nbsp;&nbsp;* 通用抛异常函数<br />&nbsp;&nbsp;*/<br />&nbsp;&nbsp;exception: function(expr) {},<br /><br />&nbsp;&nbsp;/** <br />&nbsp;&nbsp;* 跨浏览器兼容的contains函数，即一个元素是否是包含另一个节点<br />&nbsp;&nbsp;*/<br />&nbsp;&nbsp;contains: function(a,b) {},<br /><br />&nbsp;&nbsp;/** <br />&nbsp;&nbsp;* 跨浏览器兼容的children函数，返回一个元素下的所有子节点<br />&nbsp;&nbsp;*/<br />&nbsp;&nbsp;children: function(el) {},<br /><br />&nbsp;&nbsp;/** <br />&nbsp;&nbsp;* 得到一个树集合中第一层级的节点，即所谓的快速去重<br />&nbsp;&nbsp;*/<br />&nbsp;&nbsp;getFirstLevelNodes: function(nodes) {},<br /><br />&nbsp;&nbsp;/**<br />&nbsp;&nbsp;* 创建nth索引，方便nth查找<br />&nbsp;&nbsp;*/<br />&nbsp;&nbsp;buildIndex: function(el) {},<br /><br />&nbsp;&nbsp;/**<br />&nbsp;&nbsp;* 找到当前节点的索引值位置。<br />&nbsp;&nbsp;*/<br />&nbsp;&nbsp;position: function(el) {},<br /><br />};<br /><br />//selector表达式相关的命名空间<br />var Expr = {<br /><br />&nbsp;&nbsp;/**<br />&nbsp;&nbsp;* 表达式配置字符串方法，可以通过Util.substitute({})来替换<br />&nbsp;&nbsp;*/<br />&nbsp;&nbsp;operators: {},<br /><br />&nbsp;&nbsp;/**<br />&nbsp;&nbsp;伪类配置<br />&nbsp;&nbsp;*/<br />&nbsp;&nbsp;pseudos: {},<br />&nbsp;&nbsp;<br />&nbsp;&nbsp;/**<br />&nbsp;&nbsp;* 关系selector配置查找函数<br />&nbsp;&nbsp;*/<br />&nbsp;&nbsp;relations: {},<br />&nbsp;&nbsp;<br />&nbsp;&nbsp;/**<br />&nbsp;&nbsp;* 快捷选择符配置替换函数<br />&nbsp;&nbsp;*/<br />&nbsp;&nbsp;shortcuts: {},<br /><br />&nbsp;&nbsp;/** <br />&nbsp;&nbsp;* 通过一个attribute来判断是用内置还是getAttribute方法来获得相应的属性值。<br />&nbsp;&nbsp;*/<br />&nbsp;&nbsp;getAttriHandle: function(attri) {},<br /><br />&nbsp;&nbsp;/**<br />&nbsp;&nbsp;* 快捷选择符解析函数，将快捷选符符解析成普通选择符<br />&nbsp;&nbsp;*/<br />&nbsp;&nbsp;parseShortcuts: function(selector) {},<br /><br />&nbsp;&nbsp;/**<br />&nbsp;&nbsp;* 将一个格式化好的attribute selector数组解析成过滤函数<br />&nbsp;&nbsp;*/<br />&nbsp;&nbsp;parseAttributesToFilter: function(attris) {},<br /><br />&nbsp;&nbsp;/**<br />&nbsp;&nbsp;* 将一个格式化好的pseudos selector数组解析成过滤函数<br />&nbsp;&nbsp;*/<br />&nbsp;&nbsp;parsePseudosToFilter: function(pseudos) {},<br /><br />&nbsp;&nbsp;/** <br />&nbsp;&nbsp;* 除去字符串两边的空白字符<br />&nbsp;&nbsp;*/<br />&nbsp;&nbsp;parseToFilter: function(selector) {}<br />};<br /><br />//一些扩展函数的命名空间<br />var Util = {<br />&nbsp;&nbsp;//这里略过，一些基础函数<br />};<br />&lt;/script&gt;</div><br /><b>7.解析优化</b><br /><br />7.1<br />效率问题主要出现在除掉重复节点上。那反过来考虑，是否可以从右向左找来解决重复节点的问题呢？<br /><br />7.2 反向查找<br /><br />反向查找也就是从表达式的右往左找。<br /><br />反向查找的优点：<br />如果由后向前查找，就可以解决查找出来节点重复的问题。不用去重。（据duoyi同学研究webkit的源码来看，webkit里css selector的解析顺序是由后往前找的。我想webkit查找策略也与此有一定关系。）<br />注：反向查找与正向相似，但是所有的过滤函数也得反着写。<br /><br />反向查找的缺点：<br />假设要找的selector表达式为：&quot;div ul~li&quot;（ID为test结点下所有儿子为div下所有ul里所有nextSibling为li的结点集合）<br />而HTML的结构为<br />&lt;html&gt;<br />&lt;body&gt;<br />&lt;div id=&quot;test&quot;&gt;<br />&nbsp;&nbsp;&lt;div&gt;<br />&nbsp;&nbsp;&nbsp;&nbsp;&lt;ol&gt;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;li&gt;test&lt;/li&gt;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;li&gt;test&lt;/li&gt;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;li&gt;test&lt;/li&gt;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;li&gt;test&lt;/li&gt;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;li&gt;test&lt;/li&gt;<br />&nbsp;&nbsp;&nbsp;&nbsp;&lt;/ol&gt;<br />&nbsp;&nbsp;&lt;/div&gt;<br />&lt;/div&gt;<br />&lt;/body&gt;<br />&lt;/html&gt;<br />这里的结构是不符合上述的selector的，在这时也就可以发现从右往左找节点的不足——这个时候，所有回溯都必须查找到documentElement这一级，这也是个费时间的操作。<br />总结：由后向前回溯树，最坏情况会回溯到树的根结点。<br /><br />7.3 正反查找两者结合？<ul class="ubb-list" ><li>顺序解析最大的问题在除重，优势是确定性（确定性是指，层层往下找，如果找不到下个selector表达式的节点，则直接可以返回；后面的表达式就不需再找）。</li><li>反向解析的最大问题则是在回溯不确定性，有可能回溯到根结点，优势则是不用除重。</li></ul>如果这两者结合起来互补的话，那么肯定是效率较高的了。<br /><br />分析下如何结合两者优势考虑查找策略：<br /><br />正向查找的问题是重复，而重复节点的问题则是出现在关系选择符上。<br />只要selector出现集合都有可能出现重复节点，所以这包括：<ul class="ubb-list" ><li>包含选择符&quot; &quot;。</li><li>子对象选择符&quot;&gt;&quot;。</li><li>所有的siblings选择符“~”。</li></ul>而剩下的兄弟选择符“+”只有一个节点，不存在集合情况，因此不可能出现重复节点。<br /><br />再思考下去，结合正向与反向的特性，这三者关系更适合 从右往左查找 有包含选择符与子对象选择符。<br />因为除掉包含选择符与子对象选择符，所有siblings的选择符集合，回溯节点后的结果是错误的。<br />举例：<br />selector为：#a~div div，在下列选择中正确结果应是e节点。<div class="code-op"><a href="javascript:NS_code.copy('codeFragment6')" title="拷贝代码(Copy Code)">Copy Code(拷贝代码)</a>-<a href="javascript:NS_code.runHTML('codeFragment6')" title="运行代码(Run HTML Code)">Run HTML(运行代码)</a>-<a href="javascript:NS_code.saveAs('codeFragment6')" title="另存代码(Save Code)">Save Code(另存代码)</a></div><div class="code" id="codeFragment6">&lt;html&gt;<br />&lt;body&gt;<br />&lt;div id=&quot;a&quot;&gt;<br />&nbsp;&nbsp;&lt;div id=&quot;b&quot;&gt;&lt;/div&gt;<br />&nbsp;&nbsp;&lt;div id=&quot;c&quot;&gt;&lt;/div&gt;<br />&lt;/div&gt;<br />&lt;div id=&quot;d&quot;&gt;&lt;div id=&quot;e&quot;&gt;&lt;/div&gt;&lt;/div&gt;<br />&lt;/body&gt;<br />&lt;/html&gt;</div>论证&quot;~&quot;选择符由后向前找是错误结果：<br />如果遇到包含选择符空格，子对象选择符&quot;&gt;&quot;，或所有的siblings选择符“~”都反向查找，则。<br /><br />1. 先查到id为a的元素；<br />2. a.getElementsByTagName(&#39;div&#39;)，即是b,c<br />3. b,c回溯“~”关系符，c符合规则。<br />4. c回溯，回到a。<br />5. 再回溯，到body，再到html，不符合规则，抛弃。这时退出。<br /><br />这里出现错误是因为关系已经复杂化，上面的selector要选的是#a的侄子，而不是子孙。<br />所以，&quot;~&quot;关系符适合正向查找。<br /><br />总结：直接的线性关系从后往前查找才能保证查找的确定性，正确性，否则就从前往后查找。<br /><br />把整个策略可以结合总结，并理清解析思路：<div class="quote"><div class="quote-title">引用 <u></u></div><div class="quote-content">由前往后查找，如遇包含选择符或子对象选择符，则开始反向查找，找到的元素集合回溯之前的关系是否正确。</div></div>举例：<br />selector为：&quot;#a div li~li&quot;，查找步骤为：<ul class="ubb-list" ><li>找到id为a的元素。</li><li>接下来发现第一个是包含关系符，由后往前找；</li><li>分离出关系&quot; div li~&quot;和确定要要找的节点li</li><li>找到所有的li节点。</li><li>检查所有查到的li节点与关系&quot;div li~&quot;是否对应。</li><li>回溯&quot;~&quot; previousSibling关系是否符合li，符合再回溯parentNode最近一级为div的节点。</li><li>只有一级的包含选择符中，用contains判断。</li>即#a.contains(div)返回是否为true。为true返回li，否则去除该li。</ul>需要注意的是由后往前虽然不用除重，但需要查找路径，不管用什么算法，最坏的情况仍然是遍历所有与当前结点为开始的路径，这会非常费时。<br />举个例，selector为：&gt;div div~div。<br />这需要遍历所有div的previousSibling往前回溯，最坏会直至documentElement节点，最好也会到documentElement的子节点。<br />想想就会非常庞大了，要是你拿新浪的页面来玩一下，浏览器肯定运算不过来。<br />但这如果从左往右找，或许就会好很多。<br /><br />所以，我们还要用不同的策略来进行优化，例如：如果没有包含siblings的选择符（&quot;~&quot;与&quot;+&quot;）直接从左往右找。<br /><br />7.4 其他优化。<br /><br />优化上面太多太多了，我列举几条吧：<ul class="ubb-list" ><li>ID查找优化。——例如&quot;div.a span #abc。</li>1.这时可以先找ID为abc的元素，如果没有该元素，可以将该selector略过了。<br />2.如果有的话，可以回朔到最开始的selector进行确认；<br />3.如果关系正确则返回ID为abc元素，否则返回空。<br /><li>调用内置的selector处理器。——因为selector我们都会解析成格式化好的数组，在解析时判断每段的selector是否符合调用内置选择器查找策略。</li>例如document.querySelectorAll(&quot;div.link&quot;)直接调内置的处理器来处理即可（注：ie8-不支持）。<br /><li>加入特殊的策略，例如：这样的规则div&gt;ul&gt;li可以直接用由前往后查找的策略来处理。而且还不用除重。</li></ul><b>8.写完代码之后的总结</b><br /><br />写个selector或许很容易，但优化确实不易。<br />如果你要测试一个selector的性能，用这个selector就好了。&quot;&gt;div div~div&quot;这个速度上是很费时的。不过一般人也没有人这么写selector，呵呵<br /><br />只看别人的代码，没人解答，不写注释，也不告诉你查找策略的优先级，让你来看性能优化后的代码将是十分痛苦的事情。<br />而selector的好坏，很大程度上是取决于性能，而不是结构。<br />之所以jquery的代码(sizzle)快，据jingpu同学说是jquery作者收集了使用者最常用哪种写法，从而进行了针对性的优化，也就是上面所说的特殊优化。<br />这样的80/20策略是很好的一个优化方向。<br />也没有人敢说自己的代码绝对一定比别人的快，只能相对比较。<br />比如，你最后不求并集，不对结合集排序，这样肯定相对会快一些。<br /><br />最后，感觉国家，感谢JK，在一起讨论selector的过程中，让我学习到不少知识。<br /><br />代码可以点这里下载，测试，呵呵<a href="http://www.never-online.net/blog/uploads/201007/js_selector.html" title="http://www.never-online.net/blog/uploads/201007/js_selector.html" target="_blank">点此下载</a><br />此份代码已经注释，比较简单，我没去写优化的代码，之所以代码里面不写，是因为写了解释起来很绕，熟悉思路先吧，以后详细优化的文章及代码可以抽空再写。<br /><br />see also <a href="http://www.never-online.net/blog/article.asp?id=295" title="http://www.never-online.net/blog/article.asp?id=295" target="_blank">js selector设计及实现（一）</a>]]></description>
      <wfw:commentRss><![CDATA[http://www.never-online.net/blog/feed.asp?q=comment&id=296]]></wfw:commentRss>
    </item>
      
    <item>
      <title><![CDATA[js selector设计及实现（一）——实现思路]]></title> 
      <link><![CDATA[http://www.never-online.net/blog/article.asp?id=295]]></link> 
      <category><![CDATA[Web Dev]]></category> 
      <author><![CDATA[Rank <null@null.com>]]></author> 
      <pubDate>Fri, 02 Jul 2010 16:56:20 +0800</pubDate> 
      <description><![CDATA[see also <a href="http://www.never-online.net/blog/article.asp?id=296" title="http://www.never-online.net/blog/article.asp?id=296" target="_blank">js selector设计及实现（二）</a><br /><b>前言</b><br /><br />前阵子和伟大的JK同学学习了一下目前我们框架里新版本的selector，这里列的是第一版selector的代码思路。<br />后一版本调优性能，多了些函数，从性能上与各大框架比还是有竞争力的。<br /><br />说句实在话，虽然各大框架和库都实现了selector。但看他们的selector实现其他的人看上去无疑都是难看懂。<br />而google,baidu上query出的结果基本都是说使用方式的文章，基本没有类似针对<b>selector设计和具体实现上</b>的文章。<br />所以，决定将整个思路和实现写出来，一来是增加印象，二来是给目前想写的人以参考。<br /><br />我是以我学习及写selector的角度及把我向JK学习思路和我自己的设计，代码写的思路写出来。<br />这篇文章我也想不到写了这么长。建议这么看比较好：<ul class="ubb-list" ><li>不熟悉selector用户先去熟悉了休息会，再看此文；文中没有写详细的selector的具体内容，只是为了描述，大略的提了下；</li><li>selector了解了之后再看看思路；顺序解析还是比较容易看懂的；</li><li>后文中的js代码里，我做了详细的注释，结构也和文中提的代码结构一样，有兴趣的同学可以读下，这个selector代码暂名为：Fox，接口为Fox.query(selector, context)。</li></ul>我的blog没有代码高亮，所以看代码会有点累。&gt;_&lt;<br /><br />代码可以点这里下载，测试，呵呵<a href="http://www.never-online.net/blog/uploads/201007/js_selector.html" title="http://www.never-online.net/blog/uploads/201007/js_selector.html" target="_blank">点此下载</a><br />此份代码已经注释，比较简单，我没去写优化的代码，之所以代码里面不写，是因为写了解释起来很绕，熟悉思路先吧，以后详细优化的文章及代码可以抽空再写。<br /><br />OK，开始吧。<br /><br /><b>为什么有selector？</b><br /><br />selector原来是用于CSS开发时方便样式与结构分离的策略。<br />而在如今做JS/DOM开发的时候，绝大部分的代码之一都是选择目标元素/集合。<br />在XML里有XPATH来实现该功能；同理的，在JS/DOM开发时自然出现了selector。<br /><br />现在selector的火很大程度上除了需要感谢国家，还要感谢jquery。它如同当年Prototype带来了Ruby风格，一大批的前端开发人员都投入到jquery的怀抱。给了很多前端开发人员以快速上手，插件copy的方式来开发前端程序。<br />jquery是推进selector使用的催化剂。现在很多浏览器都支持了selector，但各实现都不尽相同，所以做一个适合自己的selector目前来看是有必要的。<br /><br />selector简单实用，减少无技术含量的工作。<br />还可以重新约束一下前端的UI框架，在render接口不是耦合HTML结构，而是与CSS selector做为桥接<br />具体可以<a href="http://www.never-online.net/blog//blog/article.asp?id=256" title="http://www.never-online.net/blog//blog/article.asp?id=256" target="_blank">点这里可以看我之前写的一篇文章(降低HTML结构与脚本之间的强耦合)</a>，这里不再多述。<br /><br /><b>selector的应用接口</b><br /><br />selector提供给外部的接口应该尽量遵循标准。开放的接口应该包括：<ul class="ubb-list" ><li>document|element.querySelector(str)</li><li>document|element.querySelectorAll(str)</li></ul>举例说明：<div class="code-op"><a href="javascript:NS_code.copy('codeFragment1')" title="拷贝代码(Copy Code)">Copy Code(拷贝代码)</a>-<a href="javascript:NS_code.runHTML('codeFragment1')" title="运行代码(Run HTML Code)">Run HTML(运行代码)</a>-<a href="javascript:NS_code.saveAs('codeFragment1')" title="另存代码(Save Code)">Save Code(另存代码)</a></div><div class="code" id="codeFragment1">var element = document.querySelector(selectors);<br />var matches = document.querySelectorAll(&quot;div.note, div.alert&quot;); </div><br /><b>具体在代码里的表现形式</b><br />Fox.query(selector, context);<br /><br /><b>selector及其类型</b><br /><br />selector是一种选择DOM元素/集合的一种符号。它包括以下的类型：<ul class="ubb-list" ><li>包括通配选择符——*</li><li>类型选择符——如E { sRules } </li><li>属性选择符——它包含四种等式：</li>E[attr] 选择具有 attr 属性的 E <br />E[attr=value] 选择具有 attr 属性且属性值等于 value 的 E <br />E[attr~=value] 选择具有 attr 属性且属性值为一用空格分隔的字词列表，其中一个等于 value 的 E 。这里的 value 不能包含空格<br />E[attr|=value] 选择具有 attr 属性且属性值为一用连字符分隔的字词列表，由 value 开始的 E <br />E[attr^=value] 选择具有 attr 属性开始的值为value的 E<br />E[attr$=value] 选择具有 attr 属性结尾的值为value的 E<br />E[attr*=value] 选择具有 attr 属性里包含value的E<br /><li>包含选择符(祖先)——如E1 E2 选择所有被 E1 包含的 E2 。即 E1.contains(E2)==true 。</li><li>子对象选择符——如E1 &gt; E2 选择所有作为 E1 子对象的 E2 。 </li><li>ID选择符——#ID { sRules } 以文档目录树(DOM)中作为对象的唯一标识符的 ID 作为选择符。</li><li>类选择符——E.className { sRules } ，它是属性选择符的一种简写形式。其效果等同于E [ class ~= className ] 。</li><li>伪类选择符——E : Pseudo-Classes { sRules } JS selector里取到的伪类有如下几种：</li>&quot;first-child&quot;,&quot;last-child&quot;,&nbsp;&nbsp;&quot;only-child&quot;,&quot;nth-child&quot;,&quot;nth-last-child&quot;,&quot;first-of-type&quot;,&quot;last-of-type&quot;,<br />&quot;only-of-type&quot;,&quot;nth-of-type&quot;,&quot;nth-last-of-type&quot;,&quot;empty&quot;,&quot;parent&quot;,<br />&quot;not&quot;,&quot;enabled&quot;,&quot;disabled&quot;,&quot;checked&quot;,&quot;contains&quot;<br /><li>伪对象选择符。E : Pseudo-Elements { sRules } 这在JS selector里可不实现（在DOM树里无法找到）</li></ul><b>开发完的代码已支持的selector表</b><div class="quote"><div class="quote-title">引用 <u></u></div><div class="quote-content">*<br />E<br />E F<br />E &gt; F<br />E + F<br />E ~ F<br />E.warning<br />E#myid<br />E:first-child<br />E:last-child<br />E:nth-child(n)<br />E:nth-last-child(n)<br />E:only-child<br />E:enabled<br />E:disabled<br />E:checked<br />E:contains(&quot;foo&quot;)<br />E:not(s)<br />E[foo]<br />E[foo=&quot;bar&quot;]<br />E[foo~=&quot;bar&quot;]<br />E[foo^=&quot;bar&quot;]<br />E[foo$=&quot;bar&quot;]<br />E[foo*=&quot;bar&quot;]<br />E[foo|=&quot;bar&quot;]</div></div>使用示例：<div class="code-op"><a href="javascript:NS_code.copy('codeFragment2')" title="拷贝代码(Copy Code)">Copy Code(拷贝代码)</a>-<a href="javascript:NS_code.runHTML('codeFragment2')" title="运行代码(Run HTML Code)">Run HTML(运行代码)</a>-<a href="javascript:NS_code.saveAs('codeFragment2')" title="另存代码(Save Code)">Save Code(另存代码)</a></div><div class="code" id="codeFragment2">//alert(Fox.query(&#39;div~div&#39;, document.body).length);<br />//alert(Fox.query(&#39;div~div.aa&#39;, document.body).length);<br />//alert(Fox.query(&#39;div span&#39;, document.body).length);<br />//alert(Fox.query(&#39;div div&#39;, document.body).length);<br />//alert(Fox.query(&#39;div&gt;input[type=&quot;text&quot;]&#39;, document.body).length);<br />//alert(Fox.query(&#39;input[type=&quot;text&quot;]&#39;, document.body).length);<br />//alert(Fox.query(&#39;*[type=&quot;text&quot;]&#39;, document.body).length);<br />(function nthTest() {<br />var arr = Fox.query(&#39;tr:nth-child(2n)&#39;);<br />for (var i=0; i&lt;arr.length; i++) {<br />&nbsp;&nbsp;arr[i].style.background=&#39;#eee&#39;;<br />}<br />})();</div><br /><b>总结归纳selector语法</b><br /><br />要想写好selector，必然要熟悉selector的语法，功能。<b>这也是重中之重</b>。<br /><br />观察selector的语法，将所有selector分为四类：<ul class="ubb-list" ><li>标签元素——标签就不解释了，但需要注意的是如果没有标签元素，则为选择符里的通配符。</li>例如这样的selector：&quot;div .link&quot;表示，div后裔节点中所有节点里属性className为link的元素集。<br /><li>选择符——包含“通配符、类型符、属性符。”（注：属性选择符包括了&quot;.link&quot;这样的selector。也包括了&quot;#id&quot;这样的selector。）</li><li>伪类——例如：last-child，first-child等伪类。</li><li>关系符——包括：“祖先、儿子、相邻兄弟。”</li></ul>总结，任意一个selector由上面所述四类构成。<br />以下是描述selector规则，伪正则描述。<div class="quote"><div class="quote-title">引用 <u></u></div><div class="quote-content">(关系符{1}(标签元素{1})((?:属性选择符)*)(:伪类)?)+</div></div>细心些的人应该会提出这样的问题，如果给出这样的selector：document.querySelectorAll(&quot;.link&quot;) 应该怎么理解？<br />——这代表着document根元素下所有className为link的节点集合。可以等价为document.querySelectorAll(&quot; .link&quot;)（注意：.link前有空格）<br />也就是说，<b>如果传入的selector第一个字符不是关系符，那么我们默认会认为它以空格关系符开始</b><br /><br /><b>解析selector表达式与实现思路</b><br />总体思路：由左往右一步步的方式，在查找过程中进行节点滤重。理论实现流程：<ul class="ubb-list" ><li>1.从入口的参数进行解析，即document.querySelectorAll(&quot;div.note, div.alert&quot;)参数解析成格式化好的形式方便处理。</li><li>2.循环解析出来的单个selector，将快捷选择符转换为标准选择符。如上所述，例如将#id属性选择转成[id=&#39;id&#39;]。</li><li>3.用getElementsByTagName得到集合，再根据条件进行过滤。</li><li>4.最后除重。将所有找到的元素集合concat连接，再除重过滤。这里顺便提一下，为什么要除重，例如：document.querySelectorAll(&quot;div a&quot;,&quot;div.alert a&quot;)，很明显，</li>&quot;div a&quot;包含&quot;div.alert a&quot;，所谓除重就是求各子selector的并集。<br /><li>6.之后可能会有针对不同的selector作优化或者作特殊处理。——例如nth-child、selector解析优化。</li></ul>有个简单印象之后再随之实践：<div class="quote"><div class="quote-title">引用 <u></u></div><div class="quote-content">假设selector传入为：Fox.query(&quot;div.panel div[className=&#39;shadow&#39;]&quot;);</div></div>假设HTML结构为:<div class="code-op"><a href="javascript:NS_code.copy('codeFragment3')" title="拷贝代码(Copy Code)">Copy Code(拷贝代码)</a>-<a href="javascript:NS_code.runHTML('codeFragment3')" title="运行代码(Run HTML Code)">Run HTML(运行代码)</a>-<a href="javascript:NS_code.saveAs('codeFragment3')" title="另存代码(Save Code)">Save Code(另存代码)</a></div><div class="code" id="codeFragment3">&lt;body&gt;<br />&lt;div id=&quot;doc&quot;&gt;<br />&nbsp;&nbsp;&lt;div class=&quot;panel&quot;&gt;<br />&nbsp;&nbsp;&nbsp;&nbsp;&lt;div class=&quot;sd&quot;&gt;要找到这个节点&lt;/div&gt;<br />&nbsp;&nbsp;&lt;/div&gt;<br />&nbsp;&nbsp;&lt;div&gt;<br />&nbsp;&nbsp;&nbsp;&nbsp;&lt;div id=&quot;a&quot;&gt;a&lt;/div&gt;<br />&nbsp;&nbsp;&nbsp;&nbsp;&lt;div id=&quot;b&quot;&gt;b&lt;/div&gt;<br />&nbsp;&nbsp;&nbsp;&nbsp;&lt;div id=&quot;c&quot;&gt;c&lt;/div&gt;<br />&nbsp;&nbsp;&lt;/div&gt;<br />&lt;/div&gt;<br />&lt;/body&gt;</div><br />我们来写一下从左到右的顺序解析与查找过程：<br /><br /><b>1. 快捷方式转换。</b><br /><br />暂且称为parseShortcut函数吧，<br />将&quot;div.panel div[className=&#39;shadow&#39;]&quot;转换成&quot;div[className~=&#39;panel&#39; div[className=&#39;shadow&#39;]&quot;<br />这部分的代码相对简单：<div class="code-op"><a href="javascript:NS_code.copy('codeFragment4')" title="拷贝代码(Copy Code)">Copy Code(拷贝代码)</a>-<a href="javascript:NS_code.runHTML('codeFragment4')" title="运行代码(Run HTML Code)">Run HTML(运行代码)</a>-<a href="javascript:NS_code.saveAs('codeFragment4')" title="另存代码(Save Code)">Save Code(另存代码)</a></div><div class="code" id="codeFragment4">&lt;script type=&quot;text/javascript&quot;&gt;//&lt;![CDATA[<br />function parseShortcuts(selector) {<br />&nbsp;&nbsp;var shortcut = [<br />&nbsp;&nbsp;&nbsp;&nbsp;[/\#([\w\-]+)/g , &#39;[id=&quot;$1&quot;]&#39;],//id缩略写法<br />&nbsp;&nbsp;&nbsp;&nbsp;[/\.([\w\-]+)/g , &#39;[className~=&quot;$1&quot;]&#39;]//className缩略写法<br />&nbsp;&nbsp;];<br />&nbsp;&nbsp;for (var i=0, len=shortcut.length; i&lt;len; i++) {<br />&nbsp;&nbsp;&nbsp;&nbsp;selector = selector.replace(shortcut[i][0], shortcut[i][1]);<br />&nbsp;&nbsp;}<br />&nbsp;&nbsp;return selector;<br />}<br />alert(&quot;div.panel div[className=&#39;shadow&#39;]返回的标准表达式为： &quot; +parseShortcuts(&quot;div.panel div[className=&#39;shadow&#39;]&quot;));<br />//]]&gt;&lt;/script&gt;</div><br /><b>2. 表达式解析第一步</b><br /><br />2.1 解析关系符及标签，分离出主要关系与需要过滤的属性，上面的解析成：<br />selectors=[[&#39;&#39;,&#39;div[className~=&quot;panel&quot;]&#39;],[&#39; &#39;,&#39;div[className=&quot;shadow&quot;]&#39;]];<br />//即selectors=[[relation,filters]];<br />2.2 随即我们只需要顺序循环selectors这个数组去解析表达式即可。<br />代码如下：<div class="code-op"><a href="javascript:NS_code.copy('codeFragment5')" title="拷贝代码(Copy Code)">Copy Code(拷贝代码)</a>-<a href="javascript:NS_code.runHTML('codeFragment5')" title="运行代码(Run HTML Code)">Run HTML(运行代码)</a>-<a href="javascript:NS_code.saveAs('codeFragment5')" title="另存代码(Save Code)">Save Code(另存代码)</a></div><div class="code" id="codeFragment5">&lt;script type=&quot;text/javascript&quot;&gt;//&lt;![CDATA[<br />function selectorParser(selector) {<br />&nbsp;&nbsp;var regExp    = /(^|\s*[&gt;+~ ]\s*)(([\w\-\:.#*]+|\([^\)]*\)|\[[^\]]*\])+)(?=($|\s*[&gt;+~ ]\s*))/g;<br />&nbsp;&nbsp;var selectors = [];<br />&nbsp;&nbsp;selector = selector.replace(regExp, function(all, relation, others) {<br />&nbsp;&nbsp;&nbsp;&nbsp;selectors.push([relation, others]);<br />&nbsp;&nbsp;&nbsp;&nbsp;return &#39;&#39;; //将输入参数进行替代，最后不为空，则输入的selector不合法。<br />&nbsp;&nbsp;});<br />&nbsp;&nbsp;if (!/\s*/.test(selector)) throw new Error([&#39;selector unexpect expression[&#39;+selector+&#39;]&#39;]);<br />&nbsp;&nbsp;return selectors;<br />}<br />alert(&quot;div[className~=&#39;panel&#39;] div[className=&#39;shadow&#39;]第一次解析结果：\n&quot; +selectorParser(&quot;div[className~=&#39;panel&#39;] div[className=&#39;shadow&#39;]&quot;).join(&#39;\n&#39;));<br />&lt;/script&gt;</div><br /><b>3. 分而治之，逐个解析关系</b><br /><br />3.1 顺序再解析selectors变量。如第一个元素：[&#39;&#39;,&#39;div[className~=&quot;panel&quot;]&#39;]<br />3.2 如上所述的流程，我们会从documentElement开始查找；<br />3.3 解析第一个元素&#39;&#39;，为空，可以先从tagName里开始查找；<br />3.4 解析出[&#39;&#39;,&#39;div[className~=&quot;panel&quot;]&#39;]的tagName为div；<br />3.5 这一步最终会得到document.documentElement.getElementTagName(&#39;div&#39;);<br />我们给这个结果命名为divs。<br /><br /><b>4. 分而治之，过滤得到的集合</b><br /><br />因为[&#39;&#39;,&#39;div[className~=&quot;panel&quot;]&#39;]所含的div节点className必须包含panel，所以我们需要将divs里的节点集合进行过滤才能得到这一级的正确结果。<br />这么看，我们急需一个过滤属性的函数。这个过滤函数的功能是：<br />4.1 输入：将div[className~=&quot;panel&quot;]表达式传入；<br />4.2 输出：返回一个新函数function(el){return el.hasClass(&#39;panel&#39;);}。<br />注意：其它的attribute也类似，只不过需要做的是有内置属性与自定义属性之分。<br />4.3 最后看过程：<br />在返回函数之前我们还需要解析一下[className~=&quot;panel&quot;]表达式，以特定格式存储，从而使程序进行处理。将属性选择器归纳起来的语法是：<div class="quote"><div class="quote-title">引用 <u></u></div><div class="quote-content">[属性名+运算符+属性值]</div></div>4.3.1 用正则表达式进行解析，存储成attris = [[属性名,运算符,表达式]]。<br />4.3.2 循环attris<br />4.3.3 根据属性名得到获取属性的方式，例如属性for在JS里是用htmlFor。而className这类的属性直接用“.”运算符就可以了，不需要用自定义属性的方式el.getAttribute(&quot;className&quot;)。<br />4.3.4 根据运算符，得到不同的attribute处理方式。例如~=是&#39;el.className &amp;&amp; (&quot; &quot;+el.className+&quot; &quot;).indexOf(&quot; &quot;+attriValue+&quot; &quot;)&gt;-1&#39;。<br />4.3.5 将上面的过程合成一个新函数，使之可以进行过滤。<br /><br />代码如下：<div class="code-op"><a href="javascript:NS_code.copy('codeFragment6')" title="拷贝代码(Copy Code)">Copy Code(拷贝代码)</a>-<a href="javascript:NS_code.runHTML('codeFragment6')" title="运行代码(Run HTML Code)">Run HTML(运行代码)</a>-<a href="javascript:NS_code.saveAs('codeFragment6')" title="另存代码(Save Code)">Save Code(另存代码)</a></div><div class="code" id="codeFragment6">&lt;script type=&quot;text/javascript&quot;&gt;//&lt;![CDATA[<br />/**<br />单独属性过滤<br />*/<br />function parseToFilter(selector) {<br /><br />&nbsp;&nbsp;var attriReg  = /\[\s*([\w\-]+)\s*([!~|^$*]?\=)?\s*(?:([&quot;&#39;]?)([^\]&#39;&quot;]*)\3)?\s*\]/g,<br />&nbsp;&nbsp;&nbsp;&nbsp;attris    = [],<br />&nbsp;&nbsp;&nbsp;&nbsp;attriFunctions = [],<br />&nbsp;&nbsp;&nbsp;&nbsp;operators = {<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&#39;~=&#39; : &#39;attriHandle &amp;&amp; (&quot; &quot;+attriHandle+&quot; &quot;).indexOf(&quot; &quot;+attriValue+&quot; &quot;)&gt;-1&#39;,<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&#39;=&#39;  : &#39;attriHandle &amp;&amp; attriHandle==attriValue&#39;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;/**<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&#39;^=&#39; : TODO,<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&#39;$=&#39; : TODO,<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&#39;*=&#39; : TODO,<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&#39;!=&#39; : TODO<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*/<br />&nbsp;&nbsp;&nbsp;&nbsp;},<br />&nbsp;&nbsp;&nbsp;&nbsp;attriHandle = function(attri) {<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;/* 是否使用内置.attribute形式来获取属性 */<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//内置attribute相关属性转换<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;var attriMap = {<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&#39;class&#39;: &#39;el.className&#39;,<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&#39;for&#39;  : &#39;el.htmlFor&#39;,<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&#39;href&#39; : &#39;el.getAttribute(&quot;href&quot;, 2)&#39;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;};<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//优先.attribute属性获取<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;var nativeAttris = &#39;name,id,className,value,selected,checked,disabled,type,tagName,readOnly&#39;.split(&#39;,&#39;);<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//内置属性获取<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;for (var i=0, len=nativeAttris.length; i&lt;len; i++) {<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;attriMap[nativeAttris[i]] = &#39;el.&#39;+nativeAttris[i];<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return attriMap[attri] || &#39;el.getAttribute(&quot;&#39; +attri+ &#39;&quot;)&#39;;<br />&nbsp;&nbsp;&nbsp;&nbsp;};<br /><br />&nbsp;&nbsp;//属性的格式是[[名,运算符,值]]<br />&nbsp;&nbsp;selector = selector.replace(attriReg,<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;function(a,b,c,d,e) {attris.push([b,c||&quot;&quot;,e||&quot;&quot;]);return &quot;&quot;;});<br /><br />&nbsp;&nbsp;for (var i=0; i&lt;attris.length; i++) {<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;var getAttri = attriHandle(attris[i][0]);<br />&nbsp;&nbsp;&nbsp;&nbsp;var operator = operators[attris[i][1]];<br />&nbsp;&nbsp;&nbsp;&nbsp;var attriVal = attris[i][2];<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;attriFunctions.push(<br />&nbsp;&nbsp;&nbsp;&nbsp;operator.replace(/attriHandle/g, getAttri).replace(&#39;attriValue&#39;, attriVal)<br />&nbsp;&nbsp;&nbsp;&nbsp;);<br /><br />&nbsp;&nbsp;};<br /><br />&nbsp;&nbsp;attriFunctions = &#39;return &#39; +attriFunctions.join(&#39;&amp;&amp;&#39;);<br />&nbsp;&nbsp;return new Function(&quot;el&quot;, attriFunctions);<br />&nbsp;&nbsp;<br />};<br />alert(&#39;div[className~=&quot;panel&quot;]返回的过滤函数为： &#39; +parseToFilter(&#39;div[className~=&quot;panel&quot;]&#39;));<br />//]]&gt;&lt;/script&gt;</div><br /><b>解析流程图</b><br />以下流程先不考虑selector里有“，”号的情况，例如Fox.query(&quot;div,span&quot;)。为了简单看流程，只说明没有“，”号的情况的实现流程。（注：有&quot;,&quot;号的情况是需要求并集，再对DOM节点排序的）<br /><div style="width: 100%;overflow-x : auto;"><a href="http://www.never-online.net/blog/uploads/201007/selector-parser-workflow.png" target="_blank" rel="lightbox"><img src="http://www.never-online.net/blog/uploads/201007/selector-parser-workflow.png" alt="http://www.never-online.net/blog/uploads/201007/selector-parser-workflow.png" class="imgBorder"/></a></div><br /><br />see also <a href="http://www.never-online.net/blog/article.asp?id=296" title="http://www.never-online.net/blog/article.asp?id=296" target="_blank">js selector设计及实现（二）</a>]]></description>
      <wfw:commentRss><![CDATA[http://www.never-online.net/blog/feed.asp?q=comment&id=295]]></wfw:commentRss>
    </item>
      
    <item>
      <title><![CDATA[写前端文档]]></title> 
      <link><![CDATA[http://www.never-online.net/blog/article.asp?id=294]]></link> 
      <category><![CDATA[Web Dev]]></category> 
      <author><![CDATA[Rank <null@null.com>]]></author> 
      <pubDate>Mon, 07 Jun 2010 15:04:07 +0800</pubDate> 
      <description><![CDATA[<b>前端文档缺失的原因</b><br />前端开发的文档相信大多数情况下都没有后端的服务描述详细，而大多数测试也仅仅在黑盒测试，所以很多情况下对这片文档的描述都廖廖无几。<ul class="ubb-list" ><li>前端开发的代码分散——没有规范化，没有很好的设计，大多数人仍以业务为主的开发方式。</li><li>测试人员对前端仍然处于黑盒测试，有没有文档都不影响到他们的测试进程。</li><li>一旦业务定型，用传统方式的文档模式，很难复制到前端开发来。——改变了开发方式（从作坊式到规范化）让人难以适应。</li></ul><b>尝试对症下药</b><br />对于代码分散的问题需要从源头解决。从规范化开始，试点从头到尾惯穿规范化，强制的约定，使代码质量提高。<br />这一块需要下大力气，中间加入设计review、代码review等环节。需要注意的是粒度把控，即什么是必须的，什么是可选的，什么是约定的等有共识。<ul class="ubb-list" ><li>功能描述——开发前的工作，对编码者来说<b>必须收集需求</b>。对于使用者来说，能够知道写这个代码的目的是什么，解决了什么问题，还有什么问题没有解决，或需要改进。</li><li>设计描述——分享你的思想，这很重要，一个成熟的开发人员看开码的时候很多时候不是看你实现如何如何，而是看你的设计。</li><li>API描述——使用者快速上手。接口是代码的眼睛。命名要严谨，不能说也可这样，也可那样。经验告诉我们，接口做得不好，历史原因就会多。</li><li>demo/snippets——给使用的人copy/paste没什么不好。</li><li>使用指南——例如库的使用指南等手册。或者说一个简单的上手教程</li></ul><b>文档该由谁来写？</b><br />从理论上看，文档都应该由编码者来写，其实不然。一个软件的周期，可以分为：开发前，开发时，使用时，测试时，维护时。<br />那么各时间段上应该有不同的人来参与。缩小些范围来看的话，应该将<ul class="ubb-list" ><li>开发前收集需求由大家参与。实现者收集后存档到文档里。此为开发目的与预期。</li><li>开发时的API描述，设计描述主要由编码者来实现。</li><li>开发后/维护时的demo及snippets可以由使用者来完善。</li></ul><b>设计文档是否能自动化生成</b><br />代码注释(现在一般都用java doc)可以生成接口文档。<br />以往都必须自己画设计图，配上描述。那么理论上这块也应该可以通过注释加入设计的描述，通过文档生成的工具自动生成设计图。这样应该方便多了。]]></description>
      <wfw:commentRss><![CDATA[http://www.never-online.net/blog/feed.asp?q=comment&id=294]]></wfw:commentRss>
    </item>
      
    <item>
      <title><![CDATA[Ajax还是普通Post？]]></title> 
      <link><![CDATA[http://www.never-online.net/blog/article.asp?id=292]]></link> 
      <category><![CDATA[Web Dev]]></category> 
      <author><![CDATA[Rank <null@null.com>]]></author> 
      <pubDate>Wed, 26 May 2010 16:07:51 +0800</pubDate> 
      <description><![CDATA[从实现与体验来看，无疑用Ajax来做比较好<ul class="ubb-list" ><li>全自动化的错误信息回填</li><li>良好的用户体验</li></ul>从应用的角度来看，需要考虑<ul class="ubb-list" ><li>用户无法提交时，如何找到问题所在</li><li>重要的页面是否要Ajax，普通的post是否更好？</li><li>如果考虑代码可以重用（如跨域，第三方等），Ajax还是有限制。</li></ul>再从Ajax与普通Post的提交的代码上看待这一问题。<br />最重要的问题是在<b>错误信息的回显</b>这一功能。——而这一功能单纯的后端或前端都是不能解决的，要找出一个合理的解决方案是后端结合前端JS来实现一个validator功能。<br />而其它方面Ajax确实能更好的提高用户体验。但并不是主要问题。<br /><br />因此应用POST与AJAX的地方可以大概的归纳如下：<ul class="ubb-list" ><li>大多数业务都可应用，但个别重要的，与第三方接口式的地方可以再考虑普通POST是否更适用。</li><li>复杂的业务或回显信息，更多使用Ajax会更好。使代码更利用阅读和维护。</li><li>跨域（如有必要的话）提交，用普通POST。</li></ul>需要注意的是：Ajax里打印日志是很重要的，在发送，接收，失败时都要有日志方便找出问题所在，否则线上处理用户的问题会让人非常的头痛。<br />发送AJAX post信息时也应该在HTTP头里加上信息标识是ajax发送的。<br />这方便以后的处理（例如：anti-spam，其它手持设备的普通post的支持可以根据HTTP头部来识别）。<br /><br />解决问题很容易，如果在现阶段把握当前的信息，看到以后会大概出现的问题，或者说尽可能少的留下历史问题，这才是真正公司需要的开发人员。]]></description>
      <wfw:commentRss><![CDATA[http://www.never-online.net/blog/feed.asp?q=comment&id=292]]></wfw:commentRss>
    </item>
      
    <item>
      <title><![CDATA[关于前端开发的那些事（一）]]></title> 
      <link><![CDATA[http://www.never-online.net/blog/article.asp?id=290]]></link> 
      <category><![CDATA[Web Dev]]></category> 
      <author><![CDATA[Rank <null@null.com>]]></author> 
      <pubDate>Fri, 14 May 2010 01:17:40 +0800</pubDate> 
      <description><![CDATA[<b>前 言</b><br />一般我的blog只写些开发时遇到的坑，让大家在开发的时候少遇到这种坑，从而更好的顺畅的开发程序，<br />也或许是很久没写blog了，最近这阵子不停的发博，有点上瘾的意思，今天想以发博客的方式来表达自己的思想。我没有一个更好的标题来标明主要的内容，其实不一定是前端开发的内容，:)。但本人现在做前端，所以暂且以《关于前端开发的那些事》来命名。<br />这也是算是理清自己的思路，准备迎接下一场战斗，任何时刻，希望自己应该有清醒的头脑，当然在感情上最好不要这样。<br /><br />现在国内的前端团队都很年轻，换句话说就是要么是成立不久的，要么是正在建立当中。都有很多问题尚须解决，但哪些问题真正是我们现阶段要解决的呢？每个团队都有自己的答案。<br />没有什么最佳实践，也没有永远的银弹，只有不停的摸索，找出适合自己的开发方式，管理方式和执行方式。<br />所以，我也有自己的想法，以下的一些话，肯定也不一定全对。<br /><br /><b>找到现在真正的问题所在</b><ul class="ubb-list" ><li>我们现在缺人，请调些人过来帮帮忙。</li><li>我们现在比较闲，但闲的时间也不知道利用到哪里。</li><li>现在的项目管理上很混乱。需要一个管理者去沟通解决这些问题</li><li>现在没有一个人可以做决策，我们需要招聘一些技术牛人来领导，引导我们作决策。</li><li>现在项目中是用YUI, Jquery, dojo, 还是Prototype？</li><li>大家的开发方式都很混乱，如命名，如接口，各自都有自己的一套。。。</li><li>大家都在重复的造轮子，某一天share的时候发现，很多人都在做同一件事，然后，相视而笑。。。</li><li>脚本库维护，请帮我们写写通用UI组件。。。</li><li>新人来了怎么培养，很头疼呀。。。</li><li>....</li></ul>这些问题相信前端的同学或多或少都遇到过，更或者今天你正在解决这样的问题。而我想说，请静下心来仔细想想，你现在真正遇到的问题是表象上的这些吗？<br /><br />大学有云：“知止而后有定，定而后能静，静而后能安，安而后能虑，虑而后能得。<br /><b>物有本末，事有终始。知所先后，则近道矣。</b>”<br /><br />我不是照本宣科，也不要拿鸡蛋扔我，凭良心讲，是不是我们很多时候头疼医头，脚疼医脚的？<br /><b>前端开发，我们同样也需要有敏锐的洞察力找出真正的问题。</b><br />其实每个行业都如此，上次在书上看到个故事。说的是A城市和B城市有一天建了一座8车道的大桥，但是发现每天这座大桥都堵车，于是向这两座城市的人征集修改意见。有人说拓宽车道，有人说再建一座等等等等的意见都有。但最后的解决方案是有人通过观察发现每天早上是A城市到B城市的人很多，于是堵上了。而下班时间是B城市到A城市的车多。于是一个很自然的解决办法是，上班时间A到B城市变6车道，下班时间B到A城市是6车道。<br />不知道各位看到这个故事是何感想？我们现在需要的不正是这样的解决办法吗？<br /><br />缺人的问题是不是资源配置有问题，是要了解下属的工作内容，工作计划太饱和，是不是周期性的原因，而这个原因又是什么？又是不是会议太多了？不能缺人就去补人，而应该找出目前真正的问题，再讨论解决方案。<br /><br />我所遇到过缺人的问题，有会议过多，产品业务过多，一些同学的工作量安排不均匀，也没有充分了解他们的特长，发挥好他们的自身优势，工作效率最大化。<br />甚至有可能还会因为没有个人发展空间的问题导致的。。。<br />往往导致直接原因极有可能是项目周期性的原因。<br />那好吧。我们就从这里开始说，<br />有些高峰期其实我们完全可以避免。不知道各位的项目开发是怎么样的，是否是关心你下一周要做什么？是不是每天都按例写周报？而你写日报这些可能都不知道是为什么。。。现在很多团队都把敏捷开发当作互联网开发的圣经，什么scrum，XP等等。而敏捷开发的大师告诉我们的也是一种理念，没有一个精确的答案。回到正题，如果是我，我会更关心的是接下来一段时间内的计划，然后根据自己的判断做规划。例如，一个月。拥抱PM，拥包后端研发吧。让大家在这些计划当中形成共识，从而更好的拥抱变化。而上面缺人问题，很有可能是没有计划和规划好导致的。如果协调好，或许根本不存在缺人问题。<br /><b>因为不是到处都着火，所以我们应该考虑我们现在要的是不是救火队</b><br />也或许，有些人认为上面的话相当于什么都没说。<br /><br /><b>关于脚本库？</b><br />脚本库是一个产品，一个项目，一个公司某一阶段的产物。<br />自然就会有，不同阶段的产物不同。<br />也就是不一样的产品、项目、公司，有自己各自的问题和脚本库。<br />要说的是 不是你用YUI就什么事都没了，一大堆配套的解决方案没有给你。YUI也一样。<br />比如：YUI2，和YUI3升级了。要你痛苦，你怎么升级？不要YUI2了？<br />唉。以前没想过这个问题。OK，你升级吧，你要测试的同学拿枪指你脑袋吗。<br />回到原点，重新反思，你需要的是什么，当然，我没说你不能用YUI，juery。<br />任何事有利有弊，需要的是我们去发现缺的是什么，需要的是什么。<br />再补一句，壶底抽薪的解决方法是重新审视自己，抽象再抽象，然后。<br /><b>瞧瞧w3c多聪明，只做标准，能忽悠，谁去它那打酱油还能卖钱。眼红得不得了。我们呢？不能这么做吗？IDL谁说只能给w3c用？</b><br /><br /><b>反思自己：我们是前端开发吗？</b><br />说到这个问题，其实与上面提到怎么培养新人的问题密切相关，如何相关？等会自然各自有各自的答案。<br />在第一次做这件事之前，先想想，学校是怎么教你的。你更意愿，更想是什么样的方式来教你，来教你什么内容。<br />这样你就会有自己的想法了吧？<br /><br />我本人没有什么技术，脾气比较急，对人比较严格（女的除外）。<br />其实他们新人很多很多人很优秀，有可能是我们没发现挖掘出来。所以要做的事是：<ul class="ubb-list" ><li>了解他的不足，了解他的优势。——没谁是个圣人。</li><li>给一个平台，展示自己。——每个人有属于自己的舞台，如果你没有给他这个平台，十个有八个想要走。</li>除非你给他足够高的工资，高工资的概念不是每个人都一样的。<br />他原来一千块工资，你现在给他两千块，当然可以留，如果原来是一万，现在给一万一，你说呢？<br />有句话说得好，<b>一分钟有多长？这在于你在厕所里面还是在厕所外面。</b><br /><b>给个好平台，他可以自己得到更多。如果他还有激情，至少，他实现了自己自身的价值。</b><br /><li>帮助他们引导，而不是解决。——古语这个说得很多了，不需要多说这些了。</li><li>新人来不是一上来就让他告诉他这个是一那个是二。我个人更倾向于让他看流程图。他自己理解，如果他来执行，怎么样更有执行力。</li>如果他觉得某个地方有问题，不要否认他，也不要认为公司流程一定是对的。<br /><b>有可能原先的流程就是错的，只不过大家都在一个山洞里做事，不知道外面还有房子住。</b><br /><li>解决问题不是满分，请永远记得这句话。纵观所有行业都是如此，现在的年代技术一般不是瓶颈，中国最不缺的就是代码工。</li>其实我想说的是，不要一成不变的做事情，人只有思考才能成长。多总结多思考，好处在于坏处，当然支持多分享。他山之石可以攻玉。<br />如果以前我们的先辈们以为单车帮我们解决了走路慢的问题，那么现在我肯定漂不到北京。</ul>通常来说新人同学来我总是强调，我们很多人都只看到一面，特别是在自己心情不平静的时候。<br />从世界的表象看来本来就是看圆，当我看只到一面的话，而不去想地球对面是什么的话永远也不知道对面是黑暗的。不是吗？<br />更何况我们所见不只是这些，它是一个N维立方体。如果你看到的面越多，了解越多，你的世界就越多彩。<br />所以我更愿意大家更多的去了解PM，思考，多去听听后端的工程师逻辑。了解后端工作这对我们极有好处，对于找线上问题，对于开发当中的业务理解等等都有帮助。<br />我记得原来后端的新同学来的时候我还可以讲解一下后端的负载和架构部署，嘿嘿。<br />而了解PM你不觉得很爽吗？你知道现在我们拿到的数据，下一步可以做什么事吗？做运营，做产品为什么这么做，交互与产品与速度如何折衷？了解之后可以多提提建议。<br /><br />还有可能。。。以后还可以考虑做PM，哈哈。<br />所以，回到小标题的问题——我们，不一定是前端。<br /><br /><b>培训，topic</b><br />一些大的公司都有学院，一些必选课程，帮助新人来快速成长。<br />也有topic这样的内容。一般来说这样的topic都是<ul class="ubb-list" ><li>技术研究成果。例如优化flash的swf文件体积</li><li>新方向。例如CSS3，HTML5。</li><li>标准。例如ecma。</li></ul>但效果往往都没有太好的效果。我作为一个听者与演讲者的角度看，其原因是因为<br />演讲者不知道讲什么让大家听，听众不一定感兴趣。<br />其结果讲么是不知道怎么讲，或者听众人数少，亦或者大家都在用笔记本看小说。<br />两者兼顾的topic相对比较少，达不到期望值。甚至有可能形成我们为之“骄傲”的形式主义。<br /><br />是不是有什么方法来解决这个问题呢？习惯从现实当中找找什么解决方案，听上去这个问题象学校一样，那么从学校说起。<br />我们先假设所有的老师水平是一样的。<br />在学校里，有选修课和必须课，你会听什么类型的课。<br />再假设，如果老师知道你们都想问什么，都想学到什么（当然，老师的经验丰富，一般都知道）<br /><br />如果上述的情况类比到topic，做个简单的系统：<ul class="ubb-list" ><li>开设“选修”。对所有人员在系统里进行征集问题——想听什么topic。topic的什么内容。当然演讲者也可以</li>一定要是技术的吗？不见得。我们太多时候都以程序员的方式去思考问题了，该改改了。<br />一定要是上述技术的吗？就不能是某个做得比较好的项目的项目管理，协调的经验分享？<br /><li>演讲者可以领取某个topic，更可以找外部的人员进行培训。</li><li>最近再给个投票。</li></ul>例如我想听听整个后端的系统架构和设计思路topic。相关问题是，数据库有多少？机器多少？怎么计算带宽。怎么负载均衡。和架设CDN等知识。<br /><b>topic本身就是为了解决问题，所以只有知道问题，才有解决之道。</b>，还可以将这些toipc的问题总结和结果出来，以后来新人了还可以让其它学习，了解得比较好的同学来讲解。还对大家的职业规划有点好处。<b>做自己感兴趣的有共识的，才有意思。</b><br /><br />好象写得有点多。。。我自己都没想到写那么多，如果你看到这里，恭喜你，解脱了，你看完了。<br /><br /><b>下次有空，再罗索下这些。</b><ul class="ubb-list" ><li>不要再重复造轮子</li><li>我们想了解大家即时遇到的问题</li><li>让会议尽可能少些吧</li></ul>---------------<br />over。]]></description>
      <wfw:commentRss><![CDATA[http://www.never-online.net/blog/feed.asp?q=comment&id=290]]></wfw:commentRss>
    </item>
      
    <item>
      <title><![CDATA[上次讲了个简单的andoird开发扫盲ppt]]></title> 
      <link><![CDATA[http://www.never-online.net/blog/article.asp?id=289]]></link> 
      <category><![CDATA[Android]]></category> 
      <author><![CDATA[Rank <null@null.com>]]></author> 
      <pubDate>Thu, 13 May 2010 15:18:17 +0800</pubDate> 
      <description><![CDATA[从了解android过程中，也了解和学习到不少的东西。可以在工作中借鉴和使用。share一下ppt。<br />我已转成png图了。也不怕高手BS，刚接触不久，呵呵，因为大家也没说讲啥，所以我也只能从我自己的角度理解下android的开发需要注意的内容吧。<br />不习惯看图的同学也可以上slideshare上看，刚传上去。（由于ppt有动画，所以我都转成无动画版了）<a href="http://www.slideshare.net/ranklau/anroid-development1-export" title="http://www.slideshare.net/ranklau/anroid-development1-export" target="_blank">http://www.slideshare.net/ranklau/anroid-development1-export</a><br /><div style="width: 100%;overflow-x : auto;"><a href="http://www.never-online.net/tutorial/android/android_01.png" target="_blank" rel="lightbox"><img src="http://www.never-online.net/tutorial/android/android_01.png" alt="http://www.never-online.net/tutorial/android/android_01.png" class="imgBorder"/></a></div><br /><div style="width: 100%;overflow-x : auto;"><a href="http://www.never-online.net/tutorial/android/android_02.png" target="_blank" rel="lightbox"><img src="http://www.never-online.net/tutorial/android/android_02.png" alt="http://www.never-online.net/tutorial/android/android_02.png" class="imgBorder"/></a></div><br /><div style="width: 100%;overflow-x : auto;"><a href="http://www.never-online.net/tutorial/android/android_03.png" target="_blank" rel="lightbox"><img src="http://www.never-online.net/tutorial/android/android_03.png" alt="http://www.never-online.net/tutorial/android/android_03.png" class="imgBorder"/></a></div><br /><div style="width: 100%;overflow-x : auto;"><a href="http://www.never-online.net/tutorial/android/android_04.png" target="_blank" rel="lightbox"><img src="http://www.never-online.net/tutorial/android/android_04.png" alt="http://www.never-online.net/tutorial/android/android_04.png" class="imgBorder"/></a></div><br /><div style="width: 100%;overflow-x : auto;"><a href="http://www.never-online.net/tutorial/android/android_05.png" target="_blank" rel="lightbox"><img src="http://www.never-online.net/tutorial/android/android_05.png" alt="http://www.never-online.net/tutorial/android/android_05.png" class="imgBorder"/></a></div><br /><div style="width: 100%;overflow-x : auto;"><a href="http://www.never-online.net/tutorial/android/android_06.png" target="_blank" rel="lightbox"><img src="http://www.never-online.net/tutorial/android/android_06.png" alt="http://www.never-online.net/tutorial/android/android_06.png" class="imgBorder"/></a></div><br /><div style="width: 100%;overflow-x : auto;"><a href="http://www.never-online.net/tutorial/android/android_07.png" target="_blank" rel="lightbox"><img src="http://www.never-online.net/tutorial/android/android_07.png" alt="http://www.never-online.net/tutorial/android/android_07.png" class="imgBorder"/></a></div><br /><div style="width: 100%;overflow-x : auto;"><a href="http://www.never-online.net/tutorial/android/android_08.png" target="_blank" rel="lightbox"><img src="http://www.never-online.net/tutorial/android/android_08.png" alt="http://www.never-online.net/tutorial/android/android_08.png" class="imgBorder"/></a></div><br /><div style="width: 100%;overflow-x : auto;"><a href="http://www.never-online.net/tutorial/android/android_09.png" target="_blank" rel="lightbox"><img src="http://www.never-online.net/tutorial/android/android_09.png" alt="http://www.never-online.net/tutorial/android/android_09.png" class="imgBorder"/></a></div><br /><div style="width: 100%;overflow-x : auto;"><a href="http://www.never-online.net/tutorial/android/android_10.png" target="_blank" rel="lightbox"><img src="http://www.never-online.net/tutorial/android/android_10.png" alt="http://www.never-online.net/tutorial/android/android_10.png" class="imgBorder"/></a></div><br /><div style="width: 100%;overflow-x : auto;"><a href="http://www.never-online.net/tutorial/android/android_11.png" target="_blank" rel="lightbox"><img src="http://www.never-online.net/tutorial/android/android_11.png" alt="http://www.never-online.net/tutorial/android/android_11.png" class="imgBorder"/></a></div><br /><div style="width: 100%;overflow-x : auto;"><a href="http://www.never-online.net/tutorial/android/android_12.png" target="_blank" rel="lightbox"><img src="http://www.never-online.net/tutorial/android/android_12.png" alt="http://www.never-online.net/tutorial/android/android_12.png" class="imgBorder"/></a></div><br /><div style="width: 100%;overflow-x : auto;"><a href="http://www.never-online.net/tutorial/android/android_13.png" target="_blank" rel="lightbox"><img src="http://www.never-online.net/tutorial/android/android_13.png" alt="http://www.never-online.net/tutorial/android/android_13.png" class="imgBorder"/></a></div><br /><div style="width: 100%;overflow-x : auto;"><a href="http://www.never-online.net/tutorial/android/android_14.png" target="_blank" rel="lightbox"><img src="http://www.never-online.net/tutorial/android/android_14.png" alt="http://www.never-online.net/tutorial/android/android_14.png" class="imgBorder"/></a></div><br /><div style="width: 100%;overflow-x : auto;"><a href="http://www.never-online.net/tutorial/android/android_15.png" target="_blank" rel="lightbox"><img src="http://www.never-online.net/tutorial/android/android_15.png" alt="http://www.never-online.net/tutorial/android/android_15.png" class="imgBorder"/></a></div><br /><div style="width: 100%;overflow-x : auto;"><a href="http://www.never-online.net/tutorial/android/android_16.png" target="_blank" rel="lightbox"><img src="http://www.never-online.net/tutorial/android/android_16.png" alt="http://www.never-online.net/tutorial/android/android_16.png" class="imgBorder"/></a></div><br /><div style="width: 100%;overflow-x : auto;"><a href="http://www.never-online.net/tutorial/android/android_17.png" target="_blank" rel="lightbox"><img src="http://www.never-online.net/tutorial/android/android_17.png" alt="http://www.never-online.net/tutorial/android/android_17.png" class="imgBorder"/></a></div><br /><div style="width: 100%;overflow-x : auto;"><a href="http://www.never-online.net/tutorial/android/android_18.png" target="_blank" rel="lightbox"><img src="http://www.never-online.net/tutorial/android/android_18.png" alt="http://www.never-online.net/tutorial/android/android_18.png" class="imgBorder"/></a></div><br /><div style="width: 100%;overflow-x : auto;"><a href="http://www.never-online.net/tutorial/android/android_19.png" target="_blank" rel="lightbox"><img src="http://www.never-online.net/tutorial/android/android_19.png" alt="http://www.never-online.net/tutorial/android/android_19.png" class="imgBorder"/></a></div><br /><div style="width: 100%;overflow-x : auto;"><a href="http://www.never-online.net/tutorial/android/android_20.png" target="_blank" rel="lightbox"><img src="http://www.never-online.net/tutorial/android/android_20.png" alt="http://www.never-online.net/tutorial/android/android_20.png" class="imgBorder"/></a></div><br /><div style="width: 100%;overflow-x : auto;"><a href="http://www.never-online.net/tutorial/android/android_21.png" target="_blank" rel="lightbox"><img src="http://www.never-online.net/tutorial/android/android_21.png" alt="http://www.never-online.net/tutorial/android/android_21.png" class="imgBorder"/></a></div><br /><div style="width: 100%;overflow-x : auto;"><a href="http://www.never-online.net/tutorial/android/android_22.png" target="_blank" rel="lightbox"><img src="http://www.never-online.net/tutorial/android/android_22.png" alt="http://www.never-online.net/tutorial/android/android_22.png" class="imgBorder"/></a></div><br /><div style="width: 100%;overflow-x : auto;"><a href="http://www.never-online.net/tutorial/android/android_23.png" target="_blank" rel="lightbox"><img src="http://www.never-online.net/tutorial/android/android_23.png" alt="http://www.never-online.net/tutorial/android/android_23.png" class="imgBorder"/></a></div><br /><div style="width: 100%;overflow-x : auto;"><a href="http://www.never-online.net/tutorial/android/android_24.png" target="_blank" rel="lightbox"><img src="http://www.never-online.net/tutorial/android/android_24.png" alt="http://www.never-online.net/tutorial/android/android_24.png" class="imgBorder"/></a></div><br /><div style="width: 100%;overflow-x : auto;"><a href="http://www.never-online.net/tutorial/android/android_25.png" target="_blank" rel="lightbox"><img src="http://www.never-online.net/tutorial/android/android_25.png" alt="http://www.never-online.net/tutorial/android/android_25.png" class="imgBorder"/></a></div><br /><div style="width: 100%;overflow-x : auto;"><a href="http://www.never-online.net/tutorial/android/android_26.png" target="_blank" rel="lightbox"><img src="http://www.never-online.net/tutorial/android/android_26.png" alt="http://www.never-online.net/tutorial/android/android_26.png" class="imgBorder"/></a></div><br /><div style="width: 100%;overflow-x : auto;"><a href="http://www.never-online.net/tutorial/android/android_27.png" target="_blank" rel="lightbox"><img src="http://www.never-online.net/tutorial/android/android_27.png" alt="http://www.never-online.net/tutorial/android/android_27.png" class="imgBorder"/></a></div><br /><div style="width: 100%;overflow-x : auto;"><a href="http://www.never-online.net/tutorial/android/android_28.png" target="_blank" rel="lightbox"><img src="http://www.never-online.net/tutorial/android/android_28.png" alt="http://www.never-online.net/tutorial/android/android_28.png" class="imgBorder"/></a></div><br /><div style="width: 100%;overflow-x : auto;"><a href="http://www.never-online.net/tutorial/android/android_29.png" target="_blank" rel="lightbox"><img src="http://www.never-online.net/tutorial/android/android_29.png" alt="http://www.never-online.net/tutorial/android/android_29.png" class="imgBorder"/></a></div><br /><div style="width: 100%;overflow-x : auto;"><a href="http://www.never-online.net/tutorial/android/android_30.png" target="_blank" rel="lightbox"><img src="http://www.never-online.net/tutorial/android/android_30.png" alt="http://www.never-online.net/tutorial/android/android_30.png" class="imgBorder"/></a></div><br /><div style="width: 100%;overflow-x : auto;"><a href="http://www.never-online.net/tutorial/android/android_31.png" target="_blank" rel="lightbox"><img src="http://www.never-online.net/tutorial/android/android_31.png" alt="http://www.never-online.net/tutorial/android/android_31.png" class="imgBorder"/></a></div><br /><div style="width: 100%;overflow-x : auto;"><a href="http://www.never-online.net/tutorial/android/android_32.png" target="_blank" rel="lightbox"><img src="http://www.never-online.net/tutorial/android/android_32.png" alt="http://www.never-online.net/tutorial/android/android_32.png" class="imgBorder"/></a></div><br /><div style="width: 100%;overflow-x : auto;"><a href="http://www.never-online.net/tutorial/android/android_33.png" target="_blank" rel="lightbox"><img src="http://www.never-online.net/tutorial/android/android_33.png" alt="http://www.never-online.net/tutorial/android/android_33.png" class="imgBorder"/></a></div><br /><div style="width: 100%;overflow-x : auto;"><a href="http://www.never-online.net/tutorial/android/android_34.png" target="_blank" rel="lightbox"><img src="http://www.never-online.net/tutorial/android/android_34.png" alt="http://www.never-online.net/tutorial/android/android_34.png" class="imgBorder"/></a></div><br /><div style="width: 100%;overflow-x : auto;"><a href="http://www.never-online.net/tutorial/android/android_35.png" target="_blank" rel="lightbox"><img src="http://www.never-online.net/tutorial/android/android_35.png" alt="http://www.never-online.net/tutorial/android/android_35.png" class="imgBorder"/></a></div><br /><div style="width: 100%;overflow-x : auto;"><a href="http://www.never-online.net/tutorial/android/android_36.png" target="_blank" rel="lightbox"><img src="http://www.never-online.net/tutorial/android/android_36.png" alt="http://www.never-online.net/tutorial/android/android_36.png" class="imgBorder"/></a></div><br /><div style="width: 100%;overflow-x : auto;"><a href="http://www.never-online.net/tutorial/android/android_37.png" target="_blank" rel="lightbox"><img src="http://www.never-online.net/tutorial/android/android_37.png" alt="http://www.never-online.net/tutorial/android/android_37.png" class="imgBorder"/></a></div><br /><div style="width: 100%;overflow-x : auto;"><a href="http://www.never-online.net/tutorial/android/android_38.png" target="_blank" rel="lightbox"><img src="http://www.never-online.net/tutorial/android/android_38.png" alt="http://www.never-online.net/tutorial/android/android_38.png" class="imgBorder"/></a></div><br /><div style="width: 100%;overflow-x : auto;"><a href="http://www.never-online.net/tutorial/android/android_39.png" target="_blank" rel="lightbox"><img src="http://www.never-online.net/tutorial/android/android_39.png" alt="http://www.never-online.net/tutorial/android/android_39.png" class="imgBorder"/></a></div><br /><div style="width: 100%;overflow-x : auto;"><a href="http://www.never-online.net/tutorial/android/android_40.png" target="_blank" rel="lightbox"><img src="http://www.never-online.net/tutorial/android/android_40.png" alt="http://www.never-online.net/tutorial/android/android_40.png" class="imgBorder"/></a></div><br /><div style="width: 100%;overflow-x : auto;"><a href="http://www.never-online.net/tutorial/android/android_41.png" target="_blank" rel="lightbox"><img src="http://www.never-online.net/tutorial/android/android_41.png" alt="http://www.never-online.net/tutorial/android/android_41.png" class="imgBorder"/></a></div><br /><div style="width: 100%;overflow-x : auto;"><a href="http://www.never-online.net/tutorial/android/android_42.png" target="_blank" rel="lightbox"><img src="http://www.never-online.net/tutorial/android/android_42.png" alt="http://www.never-online.net/tutorial/android/android_42.png" class="imgBorder"/></a></div><br /><div style="width: 100%;overflow-x : auto;"><a href="http://www.never-online.net/tutorial/android/android_43.png" target="_blank" rel="lightbox"><img src="http://www.never-online.net/tutorial/android/android_43.png" alt="http://www.never-online.net/tutorial/android/android_43.png" class="imgBorder"/></a></div><br /><div style="width: 100%;overflow-x : auto;"><a href="http://www.never-online.net/tutorial/android/android_44.png" target="_blank" rel="lightbox"><img src="http://www.never-online.net/tutorial/android/android_44.png" alt="http://www.never-online.net/tutorial/android/android_44.png" class="imgBorder"/></a></div>]]></description>
      <wfw:commentRss><![CDATA[http://www.never-online.net/blog/feed.asp?q=comment&id=289]]></wfw:commentRss>
    </item>
      
    <item>
      <title><![CDATA[iframe里src=&quot;about:blank&quot;的问题。]]></title> 
      <link><![CDATA[http://www.never-online.net/blog/article.asp?id=288]]></link> 
      <category><![CDATA[Web Dev]]></category> 
      <author><![CDATA[Rank <null@null.com>]]></author> 
      <pubDate>Tue, 11 May 2010 20:59:13 +0800</pubDate> 
      <description><![CDATA[很久之前就发现这个问题了，现在记录分享一下。<br /><br /><b>IE下才有的问题</b><br />首先不得不说，这个问题在IE下才会有。废话不多说了吧，直接上代码。<div class="code-op"><a href="javascript:NS_code.copy('codeFragment1')" title="拷贝代码(Copy Code)">Copy Code(拷贝代码)</a>-<a href="javascript:NS_code.runHTML('codeFragment1')" title="运行代码(Run HTML Code)">Run HTML(运行代码)</a>-<a href="javascript:NS_code.saveAs('codeFragment1')" title="另存代码(Save Code)">Save Code(另存代码)</a></div><div class="code" id="codeFragment1">&lt;iframe src=&quot;about:blank&quot;&gt;not support iframe element.&lt;/iframe&gt;</div>这句代码有无问题？看半天你也看不出什么来吧。<br />如果放在另一个环境下就不一样了。——这个环境是https协议。<br />出现现象是会弹出一个提示框，提示此网站不是全部用https，可能会危害您的安全之类的框框。。。如下图。<br /><div style="width: 100%;overflow-x : auto;"><a href="http://home.cssxuexi.cn/attachment/200912/29/1_1262049402jaqn.gif" target="_blank" rel="lightbox"><img src="http://home.cssxuexi.cn/attachment/200912/29/1_1262049402jaqn.gif" alt="http://home.cssxuexi.cn/attachment/200912/29/1_1262049402jaqn.gif" class="imgBorder"/></a></div><br /><br /><b>怎么发现的？</b><br />某次提测时，发现我写的控件在有些同学的浏览器上出现上述问题，此问题肯定是引用了某些非https协议的资源有关。<br />抓包发现，请求被阻塞在about:blank这里，后修改确认我的判断没有问题。<br /><br /><b>解决方案</b><br />解决方法很简单，去除这种写法，或者引用一个存在的blank.html。<br /><br /><b>好吧，让我们BS IE</b><br />这个是不是BUG？不好说，这种现象怎么解释都可以说得过去。<br />但是不能忽视的是其它的浏览器没有问题，估计IE出现这个问题的原因，要么<ul class="ubb-list" ><li>about:blank本身内部处理机制就是走的是http协议。</li><li>要么是个伪协议，伪协议与https协议里无法共存，这也与ssl有关。</li></ul>另外，据不可靠消息，IE高版本，我的win7+ie8貌似无上述问题。]]></description>
      <wfw:commentRss><![CDATA[http://www.never-online.net/blog/feed.asp?q=comment&id=288]]></wfw:commentRss>
    </item>
      
    <item>
      <title><![CDATA[记开发firefox extension]]></title> 
      <link><![CDATA[http://www.never-online.net/blog/article.asp?id=287]]></link> 
      <category><![CDATA[Web Dev]]></category> 
      <author><![CDATA[Rank <null@null.com>]]></author> 
      <pubDate>Mon, 10 May 2010 20:13:08 +0800</pubDate> 
      <description><![CDATA[很久很久没有更新blog的技术文章了，正好最近这阵子花了点时间做firefox插件，发现、总结了一些问题记录并分享一下。<br /><br /><b>关于调试</b><br />开启你的extension log功能。<br />打开about:config，通过filter找到：extensions.logging.enabled，将其设置为true。<br />它将使你的extension调试更方便。<br />安装一个<a href="https://addons.mozilla.org/zh-CN/firefox/addon/421" title="https://addons.mozilla.org/zh-CN/firefox/addon/421" target="_blank">mr tech toolkit</a>插件，可以在附加组件内容，选中某个插件右键，直接到插件目录。<br /><br /><b>关于xul布局</b><br />xul就不说了，语法比较简单，也支持CSS，不清楚的话还可以看参考手册，只是制作插件时需要不停的重启firefox。<br />所以有个可视化编辑xul，又不需要重启firefox的工具是很重要的，可以下载<a href="https://developer.mozilla.org/en/XUL_Explorer" title="https://developer.mozilla.org/en/XUL_Explorer" target="_blank">xul explorer</a>。<br />布局里值得说的一点是，vbox、hbox、spacer，这两个元素是XUL布局里重要的组成部分。<ul class="ubb-list" ><li>简单的说就是用vbox包起来的元素，子节点里的所有元素就是垂直的。</li><li>hbox类似，子节点所有都是横向排列。</li><li>spacer就是填入空白（当然，如果你不用它，直接用CSS布局也可）。</li><li><span style="color:Red">firefox extension里相互间没有沙箱。因此，你的各插件样式和脚本是可以相互影响的。比如脚本，你用$命名全局的，十之八九会挂。而样式如果用a{text-decoration:underline}，会影响一大片的插件，所以。一定要注意呀。 </span></li></ul>了解这几个以后，基本你可以手写XUL代码了，当然心里也基本知道布局是什么样的了。<br /><br /><b>鼠标右键菜单</b><br />知道这些之后，如果你要写一个右键菜单。例如：<div class="code-op"><a href="javascript:NS_code.copy('codeFragment1')" title="拷贝代码(Copy Code)">Copy Code(拷贝代码)</a>-<a href="javascript:NS_code.runHTML('codeFragment1')" title="运行代码(Run HTML Code)">Run HTML(运行代码)</a>-<a href="javascript:NS_code.saveAs('codeFragment1')" title="另存代码(Save Code)">Save Code(另存代码)</a></div><div class="code" id="codeFragment1">&nbsp;&nbsp;&lt;popup id=&quot;contentAreaContextMenu&quot;&gt;<br />&nbsp;&nbsp;&nbsp;&nbsp;&lt;menuseparator /&gt;<br />&nbsp;&nbsp;&nbsp;&nbsp;&lt;menuitem id=&quot;kb-context-menu&quot; label=&quot;右键菜单&quot; oncommand=&quot;nsNamespace.method();&quot; image=&quot;chrome&#58;//kb/content/new.png&quot;/&gt;<br />&nbsp;&nbsp;&lt;/popup&gt;</div><span style="color:Red"> popup的ID一定要是contentAreaContextMenu，否则你的右键菜单(contextmenu）死活是出不来滴。(如果不清楚这条，相信你会不停的去看是不是自己的脚本出问题了)</span><br />另外，我原来想偷懒，想在xul里嵌一个iframe解决所有问题，但貌似嵌入进去后里面的textarea无法使用，完全被disabled掉了，所以后来放弃使用iframe。老老实实的用xul的textbox来做UI。<br /><br /><b>不一致性的奇怪现象</b><br />如果要给某个元素加css text-decoration:underline下划线，文本必须在attribute里才能加上，例如&lt;label value=&quot;test&quot; style=&quot;text-decoration:underline&quot;&gt;就正常出现下划线，而如果你要是&lt;label style=&quot;text-decoration:underline&quot;&gt;test&lt;/label&gt;则无效。<br />而text元素又恰与上描述相反，看demo吧。<div class="code-op"><a href="javascript:NS_code.copy('codeFragment2')" title="拷贝代码(Copy Code)">Copy Code(拷贝代码)</a>-<a href="javascript:NS_code.runHTML('codeFragment2')" title="运行代码(Run HTML Code)">Run HTML(运行代码)</a>-<a href="javascript:NS_code.saveAs('codeFragment2')" title="另存代码(Save Code)">Save Code(另存代码)</a></div><div class="code" id="codeFragment2">&lt;?xml version=&quot;1.0&quot;?&gt;<br />&lt;?xml-stylesheet href=&quot;chrome&#58;//global/skin&quot; type=&quot;text/css&quot;?&gt;<br />&lt;?xml-stylesheet href=&quot;mycss.css&quot; type=&quot;text/css&quot;?&gt;<br />&lt;window title=&quot;test01.xul&quot; xmlns=&quot;http&#58;//www.mozilla.org/keymaster/gatekeeper/there.is.only.xul&quot;&gt;<br />&nbsp;&lt;groupbox&gt;<br />&nbsp;&lt;caption label=&quot;Underline problem&quot;/&gt;<br />&nbsp;&lt;label style=&quot;color: red;text-decoration: underline&quot;&gt;Text as element content: underline doesn&#39;t work.&lt;/label&gt;<br />&nbsp;&lt;label style=&quot;color: red;text-decoration: underline&quot; value=&quot;Text as an element attibute: underline works!&quot;/&gt;<br />&nbsp;&lt;/groupbox&gt;<br /><br />&nbsp;&lt;groupbox&gt;<br />&nbsp;&lt;caption label=&quot;Blink problem&quot;/&gt;<br />&nbsp;&lt;label style=&quot;color: red;text-decoration: blink&quot;&gt;Text as element content: blink works!&lt;/label&gt;<br />&nbsp;&lt;label style=&quot;color: red;text-decoration: blink&quot; value=&quot;Text as an element attribute: blink doesn&#39;t work.&quot;/&gt;<br />&nbsp;&lt;/groupbox&gt;<br />&lt;/window&gt;</div><br /><b>值得copy的一些代码</b><br />读取、存储用户配置信息<div class="code-op"><a href="javascript:NS_code.copy('codeFragment3')" title="拷贝代码(Copy Code)">Copy Code(拷贝代码)</a>-<a href="javascript:NS_code.runHTML('codeFragment3')" title="运行代码(Run HTML Code)">Run HTML(运行代码)</a>-<a href="javascript:NS_code.saveAs('codeFragment3')" title="另存代码(Save Code)">Save Code(另存代码)</a></div><div class="code" id="codeFragment3">//从conf里读取存储的信息<br />var prefs = Components.classes[&quot;@mozilla.org/preferences-service;1&quot;].getService(Components.interfaces.nsIPrefBranch).getBranch(&quot;extensions.pluginname.&quot;);<br />var username = prefs.getCharPref(&#39;username&#39;)||&#39;&#39;;<br />var password = prefs.getCharPref(&#39;password&#39;)||&#39;&#39;;<br /><br />//存储用户信息到config<br />var prefs = Components.classes[&quot;@mozilla.org/preferences-service;1&quot;].getService(Components.interfaces.nsIPrefBranch);<br />prefs.setCharPref(&quot;username&quot;, user.value); //以字符串形式存储<br />prefs.setCharPref(&quot;password&quot;, pass.value); //以字符串形式存储</div><br />在新tab里打开一个URL<div class="code-op"><a href="javascript:NS_code.copy('codeFragment4')" title="拷贝代码(Copy Code)">Copy Code(拷贝代码)</a>-<a href="javascript:NS_code.runHTML('codeFragment4')" title="运行代码(Run HTML Code)">Run HTML(运行代码)</a>-<a href="javascript:NS_code.saveAs('codeFragment4')" title="另存代码(Save Code)">Save Code(另存代码)</a></div><div class="code" id="codeFragment4">var openUrl = function(url) {<br />&nbsp;&nbsp;var wnd = window.top.getBrowser().selectedBrowser.contentWindow;<br />&nbsp;&nbsp;wnd.open(url);<br />};<br />openUrl(&#39;http&#58;//www.never-online.net&#39;);</div><br /><b>关于打包发布，及自动更新</b><br />extension更新有大概三种方式：<ul class="ubb-list" ><li>到addon上官方注册，这个对于个人来说不用去想什么了，没什么可操作性。——略过。</li><li>更新协议用https，然后到CA买证书，不知道CA的同学点<a href="http://baike.baidu.com/view/565507.html" title="http://baike.baidu.com/view/565507.html" target="_blank">这里</a>——要银子。</li><li>可以用http协议，第一次打包时将install.rdf安装文件签名，每次更新包时，用该签名来生成update.rdf文件，然后用sha1算法保证XPI安装包的正确性。——靠谱。</li></ul>在windows里，打包你需要用到两个工具，一个mcCoy，一个sha1sum.exe，说下两个的用途：<ul class="ubb-list" ><li>mcCoy，一个mozilla develop网上推荐的签名工具。可以点<a href="https://developer.mozilla.org/en/McCoy" title="https://developer.mozilla.org/en/McCoy" target="_blank">这里下载</a>，如上所述，是用来签名你的XPI安装包的。</li><li>sha1sum.exe，一个命令行下的执行文件，用sha1算法来算XPI安装包的程序（注意，命令行下有效）。<a href="ftp://ftp.gnupg.org/gcrypt/binary/sha1sum.exe" title="ftp://ftp.gnupg.org/gcrypt/binary/sha1sum.exe" target="_blank">点这里下载</a></li></ul><b>签名发布xpi安装包 及 更新插件流程</b><ul class="ubb-list" ><li>mcCoy创建一个新key。</li><li>点击install按钮找到install.rdf，使之签名。</li>如果你的install.rdf格式正确，mcCoy程序会自动将该文件写入签名。<br />如果不知道写install.rdf格式的同学看文末，我会给出template。<br />（注意：如果该文件格式不对，或损坏，firefox安装时会提示该文件有误的）。<br /><li>签名好install.rdf之后，就可以发布了，但发布之前提醒最好先测试一下自动更新的过程是否有问题。</li><li>接下来用sha1sum.exe来算你要更新的XPI更新包，算好之后，把值放到em:updateHash属性里。</li><li>最后，就要用现在这个key去签名你的update.rdf文件。</li>即点击sign按钮找到update.rdf文件进行签名。<br />这个步骤和签install.rdf一样，如果你的update.rdf文件格式无误，mcCoy也会自动将update.rdf文件写入签名。<br />如果不知道写update.rdf格式的同学看文末，我会给出template。<br /><b>需要注意的是：如果你的update.rdf文件有误，是会提示验签失败的</b>，也不知道firefox会不会优化这个提示，很囧。<br /><li>OK，退出mcCoy吧。</li></ul>特别提醒一下，请自己备份好mcCoy生成的密钥。虽然你不重装系统，它不会丢，但妨万无一失，还是备份在服务器上好。<br />它的密钥在哪？——答案：开始菜单-&gt;运行 %appdata%/mozilla/mcCoy。<br />丢了之后重装mcCoy直接将原来的配置覆盖即可。<br /><br /><b>最后，给install.rdf的template及update.rdf的template</b><br />install.rdf<div class="code-op"><a href="javascript:NS_code.copy('codeFragment5')" title="拷贝代码(Copy Code)">Copy Code(拷贝代码)</a>-<a href="javascript:NS_code.runHTML('codeFragment5')" title="运行代码(Run HTML Code)">Run HTML(运行代码)</a>-<a href="javascript:NS_code.saveAs('codeFragment5')" title="另存代码(Save Code)">Save Code(另存代码)</a></div><div class="code" id="codeFragment5">&lt;?xml version=&quot;1.0&quot;?&gt;<br />&lt;RDF:RDF xmlns:em=&quot;http&#58;//www.mozilla.org/2004/em-rdf#&quot;<br />&nbsp;xmlns:NC=&quot;http&#58;//home.netscape.com/NC-rdf#&quot;<br />&nbsp;xmlns:RDF=&quot;http&#58;//www.w3.org/1999/02/22-rdf-syntax-ns#&quot;&gt;<br />&nbsp;&lt;RDF:Description RDF:about=&quot;rdf:#$amFd91&quot;<br />&nbsp;em:id=&quot;{ec8030f7-c20a-464f-9b0e-13a3a9e97384}&quot;<br />&nbsp;em:minVersion=&quot;3.0.0&quot;<br />&nbsp;em:maxVersion=&quot;4.0.0&quot; /&gt;<br />&nbsp;&lt;RDF:Description RDF:about=&quot;urn:mozilla:install-manifest&quot;<br />&nbsp;em:id=&quot;test@test.com&quot;<br />&nbsp;em:name=&quot;插件的名字&quot;<br />&nbsp;em:version=&quot;插件的版本，例如1.0.0&quot;<br />&nbsp;em:description=&quot;插件的描述&quot;<br />&nbsp;em:creator=&quot;插件作者&quot;<br />&nbsp;em:homepageURL=&quot;插件首页&quot;<br />&nbsp;em:updateURL=&quot;自动更新的update.rdf文件地址。如：http&#58;//test.com/yourURL/update.rdf&quot;<br />&nbsp;em:iconURL=&quot;插件icon，如chrome&#58;//yourplugin/skin/icon.png&quot;<br />&nbsp;em:updateKey=&quot;mcCoy自动生成&quot;&gt;<br />&nbsp;&lt;em:targetApplication RDF:resource=&quot;rdf:#$amFd91&quot;/&gt;<br />&nbsp;&lt;/RDF:Description&gt;<br />&lt;/RDF:RDF&gt;</div><br />update.rdf文件<div class="code-op"><a href="javascript:NS_code.copy('codeFragment6')" title="拷贝代码(Copy Code)">Copy Code(拷贝代码)</a>-<a href="javascript:NS_code.runHTML('codeFragment6')" title="运行代码(Run HTML Code)">Run HTML(运行代码)</a>-<a href="javascript:NS_code.saveAs('codeFragment6')" title="另存代码(Save Code)">Save Code(另存代码)</a></div><div class="code" id="codeFragment6">&lt;?xml version=&quot;1.0&quot;?&gt;<br />&lt;RDF:RDF xmlns:em=&quot;http&#58;//www.mozilla.org/2004/em-rdf#&quot;<br />&nbsp;xmlns:NC=&quot;http&#58;//home.netscape.com/NC-rdf#&quot;<br />&nbsp;xmlns:RDF=&quot;http&#58;//www.w3.org/1999/02/22-rdf-syntax-ns#&quot;&gt;<br />&nbsp;&lt;RDF:Description RDF:about=&quot;rdf:#$s+0Qr2&quot;<br />&nbsp;em:version=&quot;1.0.0&quot;&gt;<br />&nbsp;&lt;em:targetApplication RDF:resource=&quot;rdf:#$v+0Qr2&quot;/&gt;<br />&nbsp;&lt;/RDF:Description&gt;<br />&nbsp;&lt;RDF:Description RDF:about=&quot;rdf:#$v+0Qr2&quot;<br />&nbsp;em:id=&quot;{ec8030f7-c20a-464f-9b0e-13a3a9e97384}&quot;<br />&nbsp;em:minVersion=&quot;3.0&quot;<br />&nbsp;em:maxVersion=&quot;4.*&quot;<br />&nbsp;em:updateLink=&quot;xpi更新包地址：如：http&#58;//xpurl/my.xpi&quot;<br />&nbsp;em:updateHash=&quot;放入算好的sha1码，如：sha1:65b163165d2117d01ee7004f47666c236a7bae4b&quot;<br />&nbsp;em:updateInfoURL=&quot;更新信息URL，如：http&#58;//never-online.net/blog/update_info.html&quot; /&gt;<br />&nbsp;&lt;RDF:Seq RDF:about=&quot;rdf:#$r+0Qr2&quot;&gt;<br />&nbsp;&lt;RDF:li RDF:resource=&quot;rdf:#$s+0Qr2&quot;/&gt;<br />&nbsp;&lt;/RDF:Seq&gt;<br />&nbsp;&lt;RDF:Description RDF:about=&quot;urn:mozilla:extension:my@test.com&quot;<br />&nbsp;em:signature=&quot;此处的签名由mcCoy自动生成&quot;&gt;<br /><br />&nbsp;&lt;em:updates RDF:resource=&quot;rdf:#$r+0Qr2&quot;/&gt;<br />&nbsp;&lt;/RDF:Description&gt;<br />&lt;/RDF:RDF&gt;</div>]]></description>
      <wfw:commentRss><![CDATA[http://www.never-online.net/blog/feed.asp?q=comment&id=287]]></wfw:commentRss>
    </item>
      
    <item>
      <title><![CDATA[虎年台历]]></title> 
      <link><![CDATA[http://www.never-online.net/blog/article.asp?id=283]]></link> 
      <category><![CDATA[Design]]></category> 
      <author><![CDATA[Rank <null@null.com>]]></author> 
      <pubDate>Fri, 15 Jan 2010 00:44:10 +0800</pubDate> 
      <description><![CDATA[<div style="width: 100%;overflow-x : auto;"><a href="http://home.blueidea.com/attachment/201001/4/201603_1262577683wYk6.jpg " target="_blank" rel="lightbox"><img src="http://home.blueidea.com/attachment/201001/4/201603_1262577683wYk6.jpg " alt="http://home.blueidea.com/attachment/201001/4/201603_1262577683wYk6.jpg " class="imgBorder"/></a></div><br /><a href="http://youa.baidu.com/item/41a44020cadf1c1f24af0919" title="http://youa.baidu.com/item/41a44020cadf1c1f24af0919" target="_blank"><span style="font-size:16pt">http://youa.baidu.com/item/41a44020cadf1c1f24af0919</span></a><br /><br />做的台历印刷量少，所以价格比普通批量印刷的小台历稍贵些，但当你看到台历后，会发现我们是用心作台历，不是敷衍了事。<br />看blueidea的星级及评论你就会明白了。<br /><a href="http://home.blueidea.com/apps.php?do=case&amp;ac=lists&amp;uid=201603&amp;picid=48123&amp;oid=0" title="http://home.blueidea.com/apps.php?do=case&amp;ac=lists&amp;uid=201603&amp;picid=48123&amp;oid=0" target="_blank">http://home.blueidea.com/apps.php?do=case&amp;ac=lists&amp;uid=201603&amp;picid=48123&amp;oid=0</a><br /><br />另外，也有个性卡通头像制作，例如自己的照片定制成QQ头象，具体有需求请联系我。]]></description>
      <wfw:commentRss><![CDATA[http://www.never-online.net/blog/feed.asp?q=comment&id=283]]></wfw:commentRss>
    </item>
      
    <item>
      <title><![CDATA[firefox里 rowspan+border+border-collapse的bug]]></title> 
      <link><![CDATA[http://www.never-online.net/blog/article.asp?id=282]]></link> 
      <category><![CDATA[Web Dev]]></category> 
      <author><![CDATA[Rank <null@null.com>]]></author> 
      <pubDate>Mon, 14 Dec 2009 21:12:23 +0800</pubDate> 
      <description><![CDATA[好久没有发相关浏览器的坑了。今天同事cy发现，在firefox里rowspan不生效...<br />后查具体情况概述为：firefox+table rowspan+border+border-collapse:collapse;<br />表现情况是：第一行与最后一行正常，其余的中间行，全部都与预期的border不同。<br />先看示例吧：<div class="code-op"><a href="javascript:NS_code.copy('codeFragment1')" title="拷贝代码(Copy Code)">Copy Code(拷贝代码)</a>-<a href="javascript:NS_code.runHTML('codeFragment1')" title="运行代码(Run HTML Code)">Run HTML(运行代码)</a>-<a href="javascript:NS_code.saveAs('codeFragment1')" title="另存代码(Save Code)">Save Code(另存代码)</a></div><div class="code" id="codeFragment1">&lt;!DOCTYPE HTML PUBLIC &quot;-//W3C//DTD HTML 4.01//EN&quot; <br />&quot;http&#58;//www.w3.org/TR/html4/strict.dtd&quot;&gt;<br />&lt;html&gt;<br />&lt;head&gt;<br />&lt;title&gt;Rank&#39;s HTML document&lt;/title&gt;<br />&lt;meta http-equiv=&quot;Content-Type&quot; content=&quot;text/html; charset=gb2312&quot;&gt;<br />&lt;meta http-equiv=&quot;Pragma&quot; content=&quot;no-cache&quot;&gt;<br />&lt;meta http-equiv=&quot;Cache-Control&quot; content=&quot;no-cache&quot;&gt;<br />&lt;meta http-equiv=&quot;Expires&quot; content=&quot;0&quot;&gt;<br />&lt;meta http-equiv=&quot;ImageToolbar&quot; content=&quot;no&quot;&gt;<br />&lt;meta http-equiv=&quot;Creator.name&quot; content=&quot;rank&quot;&gt;<br />&lt;style type=&quot;text/css&quot; title=&quot;default&quot; media=&quot;screen&quot;&gt;&lt;/style&gt;<br />&lt;/head&gt;<br />&lt;body&gt;<br />&lt;style&gt;<br />* {font-size:15px;text-decoration:none;}<br />td {border-top:1px solid #000}<br />&lt;/style&gt;<br />&lt;table width=&quot;50%&quot; border=&quot;0&quot; style=&quot;border:1px solid #000;border-collapse:collapse;width:100%;&quot;&gt;<br />&nbsp;&nbsp;&lt;tr&gt;<br />&nbsp;&nbsp;&nbsp;&nbsp;&lt;th width=&quot;49%&quot;&gt;第一列&lt;/th&gt;<br />&nbsp;&nbsp;&nbsp;&nbsp;&lt;th width=&quot;50%&quot;&gt;第二列&lt;/th&gt;<br />&nbsp;&nbsp;&lt;/tr&gt;<br />&nbsp;&nbsp;&lt;tr class=&quot;&quot;&gt;<br />&nbsp;&nbsp;&nbsp;&nbsp;&lt;td&gt; test &lt;/td&gt;<br />&nbsp;&nbsp;&nbsp;&nbsp;&lt;td rowspan=&quot;2&quot;&gt;&lt;a href=&quot;#&quot;&gt;第一条中间没有横线&lt;/a&gt; &lt;/td&gt;<br />&nbsp;&nbsp;&lt;/tr&gt;<br />&nbsp;&nbsp;&lt;tr class=&quot;&quot;&gt;<br />&nbsp;&nbsp;&nbsp;&nbsp;&lt;td&gt;test&lt;/td&gt;<br />&nbsp;&nbsp;&lt;/tr&gt;<br />&nbsp;&nbsp;&lt;tr class=&quot;zebra&quot;&gt;<br />&nbsp;&nbsp;&nbsp;&nbsp;&lt;td&gt; test &lt;/td&gt;<br />&nbsp;&nbsp;&nbsp;&nbsp;&lt;td rowspan=&quot;2&quot;&gt;&lt;a href=&quot;#&quot;&gt;可爱的firefox让我们看到了两条线&lt;/a&gt; &lt;/td&gt;<br />&nbsp;&nbsp;&lt;/tr&gt;<br />&nbsp;&nbsp;&lt;tr class=&quot;zebra&quot;&gt;<br />&nbsp;&nbsp;&nbsp;&nbsp;&lt;td&gt;test&lt;/td&gt;<br />&nbsp;&nbsp;&lt;/tr&gt;<br />&nbsp;&nbsp;&lt;tr class=&quot;&quot;&gt;<br />&nbsp;&nbsp;&nbsp;&nbsp;&lt;td&gt; test &lt;/td&gt;<br />&nbsp;&nbsp;&nbsp;&nbsp;&lt;td rowspan=&quot;2&quot;&gt;&lt;a href=&quot;#&quot;&gt;可爱的firefox让我们看到了两条线&lt;/a&gt; &lt;/td&gt;<br />&nbsp;&nbsp;&lt;/tr&gt;<br />&nbsp;&nbsp;&lt;tr class=&quot;&quot;&gt;<br />&nbsp;&nbsp;&nbsp;&nbsp;&lt;td&gt;test&lt;/td&gt;<br />&nbsp;&nbsp;&lt;/tr&gt;<br />&nbsp;&nbsp;&lt;tr class=&quot;zebra&quot;&gt;<br />&nbsp;&nbsp;&nbsp;&nbsp;&lt;td&gt; test &lt;/td&gt;<br />&nbsp;&nbsp;&nbsp;&nbsp;&lt;td rowspan=&quot;2&quot;&gt;&lt;a href=&quot;#&quot;&gt;可爱的firefox让我们看到了两条线&lt;/a&gt; &lt;/td&gt;<br />&nbsp;&nbsp;&lt;/tr&gt;<br />&nbsp;&nbsp;&lt;tr class=&quot;zebra&quot;&gt;<br />&nbsp;&nbsp;&nbsp;&nbsp;&lt;td&gt;test&lt;/td&gt;<br />&nbsp;&nbsp;&lt;/tr&gt;<br />&nbsp;&nbsp;&lt;tr class=&quot;&quot;&gt;<br />&nbsp;&nbsp;&nbsp;&nbsp;&lt;td&gt; test &lt;/td&gt;<br />&nbsp;&nbsp;&nbsp;&nbsp;&lt;td rowspan=&quot;2&quot;&gt;&lt;a href=&quot;#&quot;&gt;最后一条中间没有横线&lt;/a&gt; &lt;/td&gt;<br />&nbsp;&nbsp;&lt;/tr&gt;<br />&nbsp;&nbsp;&lt;tr class=&quot;&quot;&gt;<br />&nbsp;&nbsp;&nbsp;&nbsp;&lt;td&gt;test&lt;/td&gt;<br />&nbsp;&nbsp;&lt;/tr&gt;<br />&lt;/table&gt;<br />&lt;/body&gt;<br />&lt;/html&gt;</div>经过验证，两种解决方法。<ul class="ubb-list" ><li>去除border-collapse</li><li>加上一个border-left或者border-right</li></ul>无独有偶，后来搜索了一下，也有前人踩到了这个坑里，它的解决方法也是：border-left:1px solid #999 important;border-left:none的方法来解决。<br />(see detail:<a href="http://www.experts-exchange.com/Web_Development/Web_Languages-Standards/CSS/Q_23698654.html" title="http://www.experts-exchange.com/Web_Development/Web_Languages-Standards/CSS/Q_23698654.html" target="_blank">http://www.experts-exchange.com/Web_Development/Web_Languages-Standards/CSS/Q_23698654.html</a>)<br />好在可以通过border的错觉及颜色来解决这个问题。为了偷懒，我直接用上了对方的e.g。看解决前的代码：<div class="code-op"><a href="javascript:NS_code.copy('codeFragment2')" title="拷贝代码(Copy Code)">Copy Code(拷贝代码)</a>-<a href="javascript:NS_code.runHTML('codeFragment2')" title="运行代码(Run HTML Code)">Run HTML(运行代码)</a>-<a href="javascript:NS_code.saveAs('codeFragment2')" title="另存代码(Save Code)">Save Code(另存代码)</a></div><div class="code" id="codeFragment2">&lt;html&gt;<br />&lt;head&gt;<br />&nbsp;<br />&lt;style type=&quot;text/css&quot;&gt;<br />table {<br />&nbsp;&nbsp;border-collapse:collapse;<br />}<br />th, td {<br />&nbsp;&nbsp;border: 1px black solid;<br />}<br />th {<br />&nbsp;&nbsp;background-color: #A9AE7B;<br />}<br />td.right_user_img {<br /><br />&nbsp;&nbsp;border-left:none;<br />&nbsp;&nbsp;background-color: #999999;<br />&nbsp;&nbsp;text-align: center;<br />&nbsp;&nbsp;padding: 15px;<br />}<br /><br />td.left_user_img {<br />&nbsp;&nbsp;border-right: none;<br />&nbsp;&nbsp;background-color: #CCCCCC;<br />&nbsp;&nbsp;text-align: center;<br />&nbsp;&nbsp;padding: 15px;<br />}<br />td.left_image_join {<br />&nbsp;&nbsp;background-color: #CCCCCC;<br />&nbsp;&nbsp;border-left: none;<br />}<br />td.right_image_join {<br />&nbsp;&nbsp;background-color: #999999;<br />&nbsp;&nbsp;border-right: none;<br />}<br />img {<br />&nbsp;&nbsp;border: none;<br />}<br />&lt;/style&gt;<br />&nbsp;<br />&lt;/head&gt;<br />&lt;body&gt;<br />&nbsp;<br />&nbsp;&lt;table cellspacing=&quot;0px&quot; cellpadding=&quot;5px&quot;&gt;<br />&nbsp;&lt;thead&gt;<br />&nbsp;&lt;tr&gt;<br />&nbsp;&lt;th&gt;&lt;/th&gt;<br />&nbsp;&lt;th&gt;Image&lt;/th&gt;<br />&nbsp;&nbsp;&nbsp;&nbsp;  &lt;th&gt;Insert Heading Here&lt;/th&gt;<br />&nbsp;&nbsp;    &lt;th&gt;Image&lt;/th&gt;<br />&nbsp;&nbsp;  &lt;/tr&gt;<br />&nbsp;&lt;/thead&gt;<br />&nbsp;<br />&nbsp;&lt;tbody&gt;<br />&nbsp;<br />&nbsp;&lt;tr&gt;<br />&nbsp;&lt;th&gt;1&lt;/th&gt;<br />&nbsp;&lt;td rowspan=&quot;2&quot; class=&quot;left_user_img&quot;&gt;&lt;img src=&quot;http&#58;//msn.mess.be/data/thumbnails/16/arnie.png&quot;&gt;&lt;/td&gt;<br />&nbsp;&nbsp;    &lt;td class=&quot;left_image_join&quot;&gt;Data&lt;/td&gt;<br />&nbsp;&nbsp;    &lt;td rowspan=&quot;2&quot; class=&quot;right_user_img&quot;&gt;&lt;img src=&quot;http&#58;//msn.mess.be/data/thumbnails/16/arnie.png&quot;&gt;&lt;/td&gt;<br />&nbsp;&lt;/tr&gt;<br />&nbsp;<br />&nbsp;<br />&nbsp;&lt;tr&gt;<br />&nbsp;&lt;th&gt;2&lt;/th&gt;<br />&nbsp;&lt;td class=&quot;right_image_join&quot;&gt;Data&lt;/td&gt;<br />&nbsp;&lt;/tr&gt;<br />&nbsp;<br />&nbsp;&lt;tr&gt;<br />&nbsp;&lt;th&gt;3&lt;/th&gt;<br />&nbsp;&lt;td rowspan=&quot;2&quot; class=&quot;left_user_img&quot;&gt;&lt;img src=&quot;http&#58;//msn.mess.be/data/thumbnails/16/arnie.png&quot;&gt;&lt;/td&gt;<br />&nbsp;&nbsp;    &lt;td class=&quot;left_image_join&quot;&gt;Data&lt;/td&gt;<br />&nbsp;&nbsp;    &lt;td rowspan=&quot;2&quot; class=&quot;right_user_img&quot;&gt;&lt;img src=&quot;http&#58;//msn.mess.be/data/thumbnails/16/arnie.png&quot;&gt;&lt;/td&gt;<br />&nbsp;&lt;/tr&gt;<br />&nbsp;<br />&nbsp;&lt;tr&gt;<br />&nbsp;&lt;th&gt;4&lt;/th&gt;<br />&nbsp;&lt;td class=&quot;right_image_join&quot;&gt;Data&lt;/td&gt;<br />&nbsp;&lt;/tr&gt;<br />&nbsp;<br />&nbsp;&lt;tr&gt;<br />&nbsp;&lt;th&gt;5&lt;/th&gt;<br />&nbsp;&lt;td rowspan=&quot;2&quot; class=&quot;left_user_img&quot;&gt;&lt;img src=&quot;http&#58;//msn.mess.be/data/thumbnails/16/arnie.png&quot;&gt;&lt;/td&gt;<br />&nbsp;&nbsp;    &lt;td class=&quot;left_image_join&quot;&gt;Data&lt;/td&gt;<br />&nbsp;&nbsp;    &lt;td rowspan=&quot;2&quot; class=&quot;right_user_img&quot;&gt;&lt;img src=&quot;http&#58;//msn.mess.be/data/thumbnails/16/arnie.png&quot;&gt;&lt;/td&gt;<br />&nbsp;&lt;/tr&gt;<br />&nbsp;<br />&nbsp;&lt;tr&gt;<br />&nbsp;&lt;th&gt;6&lt;/th&gt;<br />&nbsp;&lt;td class=&quot;right_image_join&quot;&gt;Data&lt;/td&gt;<br />&nbsp;&lt;/tr&gt;<br />&nbsp;<br />&nbsp;&lt;tr&gt;<br />&nbsp;&lt;th&gt;7&lt;/th&gt;<br />&nbsp;&lt;td rowspan=&quot;2&quot; class=&quot;left_user_img&quot;&gt;&lt;img src=&quot;http&#58;//msn.mess.be/data/thumbnails/16/arnie.png&quot;&gt;&lt;/td&gt;<br />&nbsp;&nbsp;    &lt;td class=&quot;left_image_join&quot;&gt;Data&lt;/td&gt;<br />&nbsp;&nbsp;    &lt;td rowspan=&quot;2&quot; class=&quot;right_user_img&quot;&gt;&lt;img src=&quot;http&#58;//msn.mess.be/data/thumbnails/16/arnie.png&quot;&gt;&lt;/td&gt;<br />&nbsp;&lt;/tr&gt;<br />&nbsp;<br />&nbsp;&lt;tr&gt;<br />&nbsp;&lt;th&gt;8&lt;/th&gt;<br />&nbsp;&lt;td class=&quot;right_image_join&quot;&gt;Data&lt;/td&gt;<br />&nbsp;&lt;/tr&gt;<br />&nbsp;<br />&nbsp;&lt;tr&gt;<br />&nbsp;&lt;th&gt;9&lt;/th&gt;<br />&nbsp;&lt;td rowspan=&quot;2&quot; class=&quot;left_user_img&quot;&gt;&lt;img src=&quot;http&#58;//msn.mess.be/data/thumbnails/16/arnie.png&quot;&gt;&lt;/td&gt;<br />&nbsp;&nbsp;    &lt;td class=&quot;left_image_join&quot;&gt;Data&lt;/td&gt;<br />&nbsp;&nbsp;    &lt;td rowspan=&quot;2&quot; class=&quot;right_user_img&quot;&gt;&lt;img src=&quot;http&#58;//msn.mess.be/data/thumbnails/16/arnie.png&quot;&gt;&lt;/td&gt;<br />&nbsp;&lt;/tr&gt;<br />&nbsp;<br />&nbsp;&lt;tr&gt;<br />&nbsp;&lt;th&gt;10&lt;/th&gt;<br />&nbsp;&lt;td class=&quot;right_image_join&quot;&gt;Data&lt;/td&gt;<br />&nbsp;&lt;/tr&gt;<br />&nbsp;&lt;/tbody&gt;<br />&nbsp;&lt;/table&gt;<br />&nbsp;<br />&lt;/body&gt;<br />&lt;/html&gt;</div><br />解决后的代码：<div class="code-op"><a href="javascript:NS_code.copy('codeFragment3')" title="拷贝代码(Copy Code)">Copy Code(拷贝代码)</a>-<a href="javascript:NS_code.runHTML('codeFragment3')" title="运行代码(Run HTML Code)">Run HTML(运行代码)</a>-<a href="javascript:NS_code.saveAs('codeFragment3')" title="另存代码(Save Code)">Save Code(另存代码)</a></div><div class="code" id="codeFragment3">&lt;html&gt;<br />&lt;head&gt;<br />&nbsp;<br />&lt;style type=&quot;text/css&quot;&gt;<br />table {<br />&nbsp;&nbsp;border-collapse:collapse;<br />}<br />th, td {<br />&nbsp;&nbsp;border: 1px black solid;<br />}<br />th {<br />&nbsp;&nbsp;background-color: #A9AE7B;<br />}<br />td.right_user_img {<br />&nbsp;&nbsp;border-left:1px solid #999999 !important; /*this solves border-collapse/rowspan bug in firefox 3  */<br />&nbsp;&nbsp;border-left:none;<br />&nbsp;&nbsp;background-color: #999999;<br />&nbsp;&nbsp;text-align: center;<br />&nbsp;&nbsp;padding: 15px;<br />}<br /><br />td.left_user_img {<br />&nbsp;&nbsp;border-right: none;<br />&nbsp;&nbsp;background-color: #CCCCCC;<br />&nbsp;&nbsp;text-align: center;<br />&nbsp;&nbsp;padding: 15px;<br />}<br />td.left_image_join {<br />&nbsp;&nbsp;background-color: #CCCCCC;<br />&nbsp;&nbsp;border-left: none;<br />}<br />td.right_image_join {<br />&nbsp;&nbsp;background-color: #999999;<br />&nbsp;&nbsp;border-right: none;<br />}<br />img {<br />&nbsp;&nbsp;border: none;<br />}<br />&lt;/style&gt;<br />&nbsp;<br />&lt;/head&gt;<br />&lt;body&gt;<br />&nbsp;<br />&nbsp;&lt;table cellspacing=&quot;0px&quot; cellpadding=&quot;5px&quot;&gt;<br />&nbsp;&lt;thead&gt;<br />&nbsp;&lt;tr&gt;<br />&nbsp;&lt;th&gt;&lt;/th&gt;<br />&nbsp;&lt;th&gt;Image&lt;/th&gt;<br />&nbsp;&nbsp;&nbsp;&nbsp;  &lt;th&gt;Insert Heading Here&lt;/th&gt;<br />&nbsp;&nbsp;    &lt;th&gt;Image&lt;/th&gt;<br />&nbsp;&nbsp;  &lt;/tr&gt;<br />&nbsp;&lt;/thead&gt;<br />&nbsp;<br />&nbsp;&lt;tbody&gt;<br />&nbsp;<br />&nbsp;&lt;tr&gt;<br />&nbsp;&lt;th&gt;1&lt;/th&gt;<br />&nbsp;&lt;td rowspan=&quot;2&quot; class=&quot;left_user_img&quot;&gt;&lt;img src=&quot;http&#58;//msn.mess.be/data/thumbnails/16/arnie.png&quot;&gt;&lt;/td&gt;<br />&nbsp;&nbsp;    &lt;td class=&quot;left_image_join&quot;&gt;Data&lt;/td&gt;<br />&nbsp;&nbsp;    &lt;td rowspan=&quot;2&quot; class=&quot;right_user_img&quot;&gt;&lt;img src=&quot;http&#58;//msn.mess.be/data/thumbnails/16/arnie.png&quot;&gt;&lt;/td&gt;<br />&nbsp;&lt;/tr&gt;<br />&nbsp;<br />&nbsp;<br />&nbsp;&lt;tr&gt;<br />&nbsp;&lt;th&gt;2&lt;/th&gt;<br />&nbsp;&lt;td class=&quot;right_image_join&quot;&gt;Data&lt;/td&gt;<br />&nbsp;&lt;/tr&gt;<br />&nbsp;<br />&nbsp;&lt;tr&gt;<br />&nbsp;&lt;th&gt;3&lt;/th&gt;<br />&nbsp;&lt;td rowspan=&quot;2&quot; class=&quot;left_user_img&quot;&gt;&lt;img src=&quot;http&#58;//msn.mess.be/data/thumbnails/16/arnie.png&quot;&gt;&lt;/td&gt;<br />&nbsp;&nbsp;    &lt;td class=&quot;left_image_join&quot;&gt;Data&lt;/td&gt;<br />&nbsp;&nbsp;    &lt;td rowspan=&quot;2&quot; class=&quot;right_user_img&quot;&gt;&lt;img src=&quot;http&#58;//msn.mess.be/data/thumbnails/16/arnie.png&quot;&gt;&lt;/td&gt;<br />&nbsp;&lt;/tr&gt;<br />&nbsp;<br />&nbsp;&lt;tr&gt;<br />&nbsp;&lt;th&gt;4&lt;/th&gt;<br />&nbsp;&lt;td class=&quot;right_image_join&quot;&gt;Data&lt;/td&gt;<br />&nbsp;&lt;/tr&gt;<br />&nbsp;<br />&nbsp;&lt;tr&gt;<br />&nbsp;&lt;th&gt;5&lt;/th&gt;<br />&nbsp;&lt;td rowspan=&quot;2&quot; class=&quot;left_user_img&quot;&gt;&lt;img src=&quot;http&#58;//msn.mess.be/data/thumbnails/16/arnie.png&quot;&gt;&lt;/td&gt;<br />&nbsp;&nbsp;    &lt;td class=&quot;left_image_join&quot;&gt;Data&lt;/td&gt;<br />&nbsp;&nbsp;    &lt;td rowspan=&quot;2&quot; class=&quot;right_user_img&quot;&gt;&lt;img src=&quot;http&#58;//msn.mess.be/data/thumbnails/16/arnie.png&quot;&gt;&lt;/td&gt;<br />&nbsp;&lt;/tr&gt;<br />&nbsp;<br />&nbsp;&lt;tr&gt;<br />&nbsp;&lt;th&gt;6&lt;/th&gt;<br />&nbsp;&lt;td class=&quot;right_image_join&quot;&gt;Data&lt;/td&gt;<br />&nbsp;&lt;/tr&gt;<br />&nbsp;<br />&nbsp;&lt;tr&gt;<br />&nbsp;&lt;th&gt;7&lt;/th&gt;<br />&nbsp;&lt;td rowspan=&quot;2&quot; class=&quot;left_user_img&quot;&gt;&lt;img src=&quot;http&#58;//msn.mess.be/data/thumbnails/16/arnie.png&quot;&gt;&lt;/td&gt;<br />&nbsp;&nbsp;    &lt;td class=&quot;left_image_join&quot;&gt;Data&lt;/td&gt;<br />&nbsp;&nbsp;    &lt;td rowspan=&quot;2&quot; class=&quot;right_user_img&quot;&gt;&lt;img src=&quot;http&#58;//msn.mess.be/data/thumbnails/16/arnie.png&quot;&gt;&lt;/td&gt;<br />&nbsp;&lt;/tr&gt;<br />&nbsp;<br />&nbsp;&lt;tr&gt;<br />&nbsp;&lt;th&gt;8&lt;/th&gt;<br />&nbsp;&lt;td class=&quot;right_image_join&quot;&gt;Data&lt;/td&gt;<br />&nbsp;&lt;/tr&gt;<br />&nbsp;<br />&nbsp;&lt;tr&gt;<br />&nbsp;&lt;th&gt;9&lt;/th&gt;<br />&nbsp;&lt;td rowspan=&quot;2&quot; class=&quot;left_user_img&quot;&gt;&lt;img src=&quot;http&#58;//msn.mess.be/data/thumbnails/16/arnie.png&quot;&gt;&lt;/td&gt;<br />&nbsp;&nbsp;    &lt;td class=&quot;left_image_join&quot;&gt;Data&lt;/td&gt;<br />&nbsp;&nbsp;    &lt;td rowspan=&quot;2&quot; class=&quot;right_user_img&quot;&gt;&lt;img src=&quot;http&#58;//msn.mess.be/data/thumbnails/16/arnie.png&quot;&gt;&lt;/td&gt;<br />&nbsp;&lt;/tr&gt;<br />&nbsp;<br />&nbsp;&lt;tr&gt;<br />&nbsp;&lt;th&gt;10&lt;/th&gt;<br />&nbsp;&lt;td class=&quot;right_image_join&quot;&gt;Data&lt;/td&gt;<br />&nbsp;&lt;/tr&gt;<br />&nbsp;&lt;/tbody&gt;<br />&nbsp;&lt;/table&gt;<br />&nbsp;<br />&lt;/body&gt;<br />&lt;/html&gt;</div><br />PS.好象firefox 一直以来就有这个bug。问多久前有的？至少flock就有了 <img src="http://www.never-online.net/blog/styles/g/images/smilies/icon_stun.gif" border="0" alt="[stun]" />]]></description>
      <wfw:commentRss><![CDATA[http://www.never-online.net/blog/feed.asp?q=comment&id=282]]></wfw:commentRss>
    </item>
      
    <item>
      <title><![CDATA[htc hero刷机流水帐]]></title> 
      <link><![CDATA[http://www.never-online.net/blog/article.asp?id=281]]></link> 
      <category><![CDATA[Android]]></category> 
      <author><![CDATA[Rank <null@null.com>]]></author> 
      <pubDate>Fri, 11 Dec 2009 11:08:13 +0800</pubDate> 
      <description><![CDATA[<div style="width: 100%;overflow-x : auto;"><a href="http://t3.gstatic.cn/images?q=tbn:AATHpkttucE0DM: " target="_blank" rel="lightbox"><img src="http://t3.gstatic.cn/images?q=tbn:AATHpkttucE0DM: " alt="http://t3.gstatic.cn/images?q=tbn:AATHpkttucE0DM: " class="imgBorder"/></a></div><br /><br />首先，提醒各位，刷root要小心。<br /><br />接下来流水帐开始：<br /><b><span style="font-size:16pt">刷root</span></b><br /><br />前阵子狠下心买了<a href="http://youa.baidu.com/std/c9fa3e420036378bc2f278f4#/detail" title="http://youa.baidu.com/std/c9fa3e420036378bc2f278f4#/detail" target="_blank">htc hero</a>。<br />自己手痒~<br />想刷机，看网上的报道说刷机要拿到root权限。<br />至于我为什么要刷机呢，是因为我想体验一把<a href="http://news.google.cn/news?hl=zh-CN&amp;q=goggles&amp;um=1&amp;ie=UTF-8&amp;sa=N&amp;tab=wn" title="http://news.google.cn/news?hl=zh-CN&amp;q=goggles&amp;um=1&amp;ie=UTF-8&amp;sa=N&amp;tab=wn" target="_blank">goggles</a>的可视化搜索。该程序固件1.6才可用。<br /><br />刷机开始，先找了一个贴子<br /><a href="http://sjbbs.zol.com.cn/frmView.php?frameon=yes&amp;subcatid=33080&amp;bookid=6794&amp;ref0=http://www.google.cn/search?hl=zh-CN&amp;newwindow=1&amp;q=update-hero-signed.zip+g3+adb&amp;btnG=Google+%E6%90%9C%E7%B4%A2&amp;aq=f&amp;oq=" title="http://sjbbs.zol.com.cn/frmView.php?frameon=yes&amp;subcatid=33080&amp;bookid=6794&amp;ref0=http://www.google.cn/search?hl=zh-CN&amp;newwindow=1&amp;q=update-hero-signed.zip+g3+adb&amp;btnG=Google+%E6%90%9C%E7%B4%A2&amp;aq=f&amp;oq=" target="_blank">点这里打开原贴页面</a><br />照着刷，还果然是可以正常开机，开始还蛮开心的。以后刷成功不会有什么其它的影响，后来一开wifi，结果显示无法打开wifi网络。这回囧了~水货机变行货机了。 <img src="http://www.never-online.net/blog/styles/g/images/smilies/icon_cry.gif" border="0" alt="[cry]" /> <br /><br /><b><span style="font-size:16pt">刷rom</span></b><br />在网上搜索了很久，有人遇到相同的情况，但是对于解决此类问题的解决方法，除了再刷rom没有更好的解决方法...<br /><br />没有wifi的一天那是相当的不爽呀，在网上查了一些刷机相关资料。刷机到处都是贴子，但刷的步骤也是很繁琐，到后面终于找到一个靠谱的了：<br /><a href="http://www.androidin.net/bbs/thread-23700-1-2.html（这个网站可能被墙了，看不到，用代理可上，如果觉得麻烦，本文最后会附上贴子内容）。" title="http://www.androidin.net/bbs/thread-23700-1-2.html（这个网站可能被墙了，看不到，用代理可上，如果觉得麻烦，本文最后会附上贴子内容）。" target="_blank">http://www.androidin.net/bbs/thread-23700-1-2.html（这个网站可能被墙了，看不到，用代理可上，如果觉得麻烦，本文最后会附上贴子内容）。</a><br /><br />确定了不刷官方rom，改刷mocado的rom，下面这条信息就有价值了：<div class="quote"><div class="quote-title">引用 <u></u></div><div class="quote-content">八、如何刷modaco的rom？<br />     首先从 <a href="http://android.modaco.com/conten" title="http://android.modaco.com/conten" target="_blank">http://android.modaco.com/conten</a> ... aturing-wavesecure/ 下载你选择的rom，下载下来是一个zip文件，你可以把这个文件改名成update.zip，然后复制到你的sd卡上（不要放在任何文件夹里），关机，用home键+开机键开机进入recovery,选择用这个zip文件升级，等待片刻即可。</div></div>rom的下载地址可用这个（此rom应该是被rooted了的，但请注意文章后面的注意事项）：<br />HTC Generic 2.73.405.38 <a href="http://content.modaco.net/hero/update-hero-generic-2.73.405.38-rooted-signed.zip" title="http://content.modaco.net/hero/update-hero-generic-2.73.405.38-rooted-signed.zip" target="_blank">http://content.modaco.net/hero/update-hero-generic-2.73.405.38-rooted-signed.zip</a> <br />步骤很简单:<br />把这个文件改名成update.zip，然后复制到你的sd卡上（不要放在任何文件夹里），关机，用home键+开机键开机进入recovery,选择用这个zip文件升级，等待片刻即可。<br />方法经验证，有效可行，这个rom是英文的，如果要换成中文，请在market里下载more locale软件，打开拉到最下面就是简体中文。<br /><br /><b><span style="font-size:16pt">必装软件</span></b><br />刚买此款手机的朋友如果装软件，建议首先装下下面的软件:<ul class="ubb-list" ><li>app control(安卓网上有破解版）----用于程序进程管理，软件安装与删除等功能</li><li>google sky map(market上有) --- google星空结合gps的功能让你惊喜不已（相关资料可以在网上搜，不多描述）</li><li>places directory (market上有）---gps定位你的位置及查找附件的酒店，茶馆，饭馆等功能</li><li>google pinyin(market上有) -- 比sougou好用，至少在g3上比sougou好用。</li><li>aQQ(安卓网上有）-- 手机上的qq(非官方版）。开启群消息时进程容易挂掉。</li></ul><b><span style="font-size:16pt">注意事项</span></b><br /><br />另外，从上面贴子里也找到了一个信息:<div class="quote"><div class="quote-title">引用 <u></u></div><div class="quote-content">二十二、怎么获取root权限呢？<br />      <b> 论坛提供了方法来获取hero的root权限，但是升级rom到2.73这后这个方法就变得没用了，就算获取成功，也会让你的wifi失效</b>，而且这个方法获取的root不能用root explorer或者sufbs来修改系统文件，只能用于一些简单的root权限，比如使用marketenabler，所以我推荐都是刷带root权限的rom来实现，这类rom可以在 <a href="http://android.modaco.com/conten" title="http://android.modaco.com/conten" target="_blank">http://android.modaco.com/conten</a> ... -update-zip-format/ 找到。<br /><br />使用的modaco的rom有较强的功能（上个问题已经提及），但是它的自制rom（不是他们提供的官方rom或者官方+root权限的rom）<b>会造成彩信接收/发送不正常</b>，参考 <a href="http://www.androidin.net/bbs/thread-21525-1-1.html" title="http://www.androidin.net/bbs/thread-21525-1-1.html" target="_blank">http://www.androidin.net/bbs/thread-21525-1-1.html</a> </div></div><b><span style="font-size:16pt">附android的Q&amp;A:</span></b><div class="quote"><div class="quote-title">引用 <u></u></div><div class="quote-content">      不得不说，臭屁洋也有累的时候，最近解答了很多朋友的问题，真的有些烦的感觉，想想花多一点时间给大家写一个问题集中帖，方便大家参考解决问题，也方便我给大家解答问题！（本人基本不用usb线，所以我的方法大多数是用读卡器和sd卡的，关于usb连接的问题我可能无法解答）<br /><br />——————————————————————————————————————————<br /><br />一、什么是ROM？什么是RUU？<br />        大家都说有些东西太专业了，看不懂，我决定有通俗的语言来解释<br />        如果把你的手机看做一个房子，那么rom就是房子里的装修和家私，我们刷rom就是给房子重新装修，让你的房子更漂亮更好用（偶尔也会有装修让你很失望的情况）。<br />        RUU又是什么呢？RUU工具相当于专业装修队，他是你手机的厂商派来负责给你装修房子的，而且他可不仅仅是给你的房子粉粉墙或者添加几个家具，它是给你的房子彻底整一遍，把一些墙拆了，改大或者改小一些房间，家具也要重新换一遍，完全变成一个新房子，你进来还要重新买衣服窗帘和一些家具（数据肯定会丢失）。<br /><br />二、我怎么知道我手机的rom版本？这个版本是高还是低？<br />      进入设置，关于手机，内部版本就是你手机的rom版本，格式一般为1.23.456.7或者1.23.456.78，其中1.23为大版本号，目前最新的版本号是2.73，7或者78为小版本号（姑且这么说吧），版本号数字越大越新，456感觉为区域号。比如说目前官方提供的通用rom是 2.73.405.5，而最新的通用rom版本是2.73.405.61，其中405就是通用区域号。<br />      另外也有部分是一些自制版本，比如modaco或者drizzy等，他们会在内部版本或者软件版本那儿把自己的大名写进去，比如modaco 2.9,大家可以去<a href="http://android.modaco.com/category/409/htc-hero-hero-modaco-com/" title="http://android.modaco.com/category/409/htc-hero-hero-modaco-com/" target="_blank">http://android.modaco.com/category/409/htc-hero-hero-modaco-com/</a> 或者 <a href="http://forum.xda-developers.com/forumdisplay.php?f=508" title="http://forum.xda-developers.com/forumdisplay.php?f=508" target="_blank">http://forum.xda-developers.com/forumdisplay.php?f=508</a> 或者在论坛搜索最新的版本情况。<br /><br />三、我的手机需要刷rom吗？刷rom有风险吗？<br />      hero在最新的官方版本，2.73版做了很多重要的更新，参考：<a href="http://www.androidin.net/bbs/thread-16107-1-1.html" title="http://www.androidin.net/bbs/thread-16107-1-1.html" target="_blank">http://www.androidin.net/bbs/thread-16107-1-1.html</a> ，如果你的手机版本低于这个版本，建议刷取新的rom。许多自制的rom也会不断增加新的软件和功能，比如modaco的rom有的会带root权限或者可以自动app2sd，一般都装好了java，你可以直接下载论坛里的java版的QQ安装，大家根据自己的需要来选择是否升级。                       <br />      个人觉得hero刷rom是我玩机八年来最简单最安全的，基本不会出现变砖的可能，虽然我不能打包票，不过目前还么有人说自己刷机失败成砖的帖子吧！？<br /><br />四、我该选什么rom呢？<br />      官方自带的rom目前看起来最稳定，但是最新的2.73版是无法直接获得root权限（获取root后有可能会wifi失效）和recovery，对于玩手机的朋友来说，这不是好事。<br />      我现在使用的modaco的rom有较强的功能（上个问题已经提及），但是它的自制rom（不是他们提供的官方rom或者官方+root权限的rom）会造成彩信接收/发送不正常，参考 <a href="http://www.androidin.net/bbs/thread-21525-1-1.html" title="http://www.androidin.net/bbs/thread-21525-1-1.html" target="_blank">http://www.androidin.net/bbs/thread-21525-1-1.html</a> <br />      据说drizzy的rom不存在这些问题，不过xda上对这个rom的评价不高，我也一直没有测试，熟悉的朋友可以补充一下。<br /><br />五、刷rom之前我要做什么？<br />      如果选择官方RUU直接升级请直接参考第六个问题，如果刷其他rom，你需要有recovery.img，recovery就是你用home键+开机键开机后能进入的一个界面，在这个界面你可以直接用sd卡上的zip的rom升级或者备份你的系统，老版本的recovery只有三个选项，无法备份系统，只能用update.zip这个文件名的文件升级，不能用任何文件名的zip文件升级。<br />     此外，一般刷rom之后最好wipe一下（wipe只是抹除rom意外的个人数据，不会影响rom本身的东西，比如你新刷的rom是带root的，wipe之后仍有root权限），也就是返回出厂设置一下比较好，但是这样就会丢失你的所有软件，短信彩信，联系人（备份在google上没有关系）和设置等等，备份或者不wipe都可以。<br /><br />六、我没有recovery怎么办？<br />      你可以使用<a href="http://www.androidin.net/bbs/viewthread.php?tid=15941" title="http://www.androidin.net/bbs/viewthread.php?tid=15941" target="_blank">http://www.androidin.net/bbs/viewthread.php?tid=15941</a> 这个方法刷入最新的recovery，有些朋友会出现flash按键变成灰色，没关系的，只要你先点击备份按钮一次，flash按钮就可以用了。有了recovery，你就可以刷其他的rom了。<br />      recovery可以在这儿下载： <a href="http://www.androidin.net/bbs/viewthread.php?tid=21615" title="http://www.androidin.net/bbs/viewthread.php?tid=21615" target="_blank">http://www.androidin.net/bbs/viewthread.php?tid=21615</a> 或者 <a href="http://android.modaco.com/conten" title="http://android.modaco.com/conten" target="_blank">http://android.modaco.com/conten</a> ... device-permanently/ <br />      <br /><br />七、官方的ruu升级rom怎么做？<br />      参考 <a href="http://www.androidin.net/bbs/viewthread.php?tid=15867" title="http://www.androidin.net/bbs/viewthread.php?tid=15867" target="_blank">http://www.androidin.net/bbs/viewthread.php?tid=15867</a> ，大家注意ruu刷机会丢失数据，请自己备份好。<br /><br />八、如何刷modaco的rom？<br />     首先从 <a href="http://android.modaco.com/conten" title="http://android.modaco.com/conten" target="_blank">http://android.modaco.com/conten</a> ... aturing-wavesecure/ 下载你选择的rom，下载下来是一个zip文件，你可以把这个文件改名成update.zip，然后复制到你的sd卡上（不要放在任何文件夹里），关机，用home键+开机键开机进入recovery,选择用这个zip文件升级，等待片刻即可。<br /><br />九、如果我是707或者728的rom？<br />     这些是我们常说的亚太版的rom，它因为cid的问题，不能获取root，不能刷recovery，所以不能直接刷rom，但是现在论坛有方法解决，参考：<a href="http://www.androidin.net/bbs/viewthread.php?tid=22211" title="http://www.androidin.net/bbs/viewthread.php?tid=22211" target="_blank">http://www.androidin.net/bbs/viewthread.php?tid=22211</a> <br /><br />十、为什么我刷完rom没有中文了？<br />      如果你刷的是官方rom或者modaco不带中文支持的rom，刷机之后是没有办法选择出中文来，建议你去市场下载一个叫做morelocale的软件（你也可以事先下载好），用它可以调出中文。<br /><br />十一、modaco为什么有那么多rom？什么意思？<br />      &#39;Core&#39; download: <a href="http://content.modaco.net/hero/2.7-update-...core-signed.zip" title="http://content.modaco.net/hero/2.7-update-...core-signed.zip" target="_blank">http://content.modaco.net/hero/2.7-update-...core-signed.zip</a> 这个是基本的rom<br />      &#39;Core Chinese&#39; download: <a href="http://content.modaco.net/hero/2.7-update-...nese-signed.zip" title="http://content.modaco.net/hero/2.7-update-...nese-signed.zip" target="_blank">http://content.modaco.net/hero/2.7-update-...nese-signed.zip</a>  这个是加了中文支持的rom，可以直接调出中文<br />      &#39;Enhanced&#39; add on pack: <a href="http://content.modaco.net/hero/2.7-update-...nced-signed.zip" title="http://content.modaco.net/hero/2.7-update-...nced-signed.zip" target="_blank">http://content.modaco.net/hero/2.7-update-...nced-signed.zip</a>  这个增加了三个软件的增强版（须先刷前两个rom），三个软件一个是名片扫描，论坛已有，一个是wap浏览器，用处不大，一个是flurk，已经被强，用不了<br />     &#39;Wavesecure&#39; add on pack: <a href="http://content.modaco.net/hero/2.7-update-...cure-signed.zip" title="http://content.modaco.net/hero/2.7-update-...cure-signed.zip" target="_blank">http://content.modaco.net/hero/2.7-update-...cure-signed.zip</a>  这个把手机保护软件wavesecure加到rom里，不能直接删除它，能更好的保护手机<br />      &#39;Boot Sounds&#39; add on pack: <a href="http://content.modaco.net/hero/2.7-update-...unds-signed.zip" title="http://content.modaco.net/hero/2.7-update-...unds-signed.zip" target="_blank">http://content.modaco.net/hero/2.7-update-...unds-signed.zip</a>  modaco的rom现在是无声启动的，刷入这个可以调出声音<br />      首先刷最上面两个rom中任何一个，其他的自行添加，方法和刷rom一样。<br /><br />十二、刷完的rom我想删除不要的软件可以吗？<br />     其实那些不用的软件很容易删除的，它们都放在system/app文件夹下，如果你有root权限，只要进去文件夹，打开读写，把不要的软件移动出来到就好了。比如，如果你不要youtube，就把system/app文件夹下的youtube.apk移动到sd卡上就好了，它就消失在你的所有程序里了。当然，有些文件放在system/lib下，你找到文件名相同的删除就好了。     root explorer的使用方法参考：<a href="http://www.androidin.net/bbs/viewthread.php?tid=6892&amp;highlight=root%2Bexplorer" title="http://www.androidin.net/bbs/viewthread.php?tid=6892&amp;highlight=root%2Bexplorer" target="_blank">http://www.androidin.net/bbs/viewthread.php?tid=6892&amp;highlight=root%2Bexplorer</a><br /><br />十三、刷完mocado2.7之后，usb连接手机，sd卡会报错，为什么？<br />      这应该是2.7自带的一个叫做swapper的软件，此软件本来是在sd卡上制作一个缓存文件，用于程序运行的文件交换（相当于windows下的缓存，我是这么认为的），但是它会让你的sd卡报错，如果造成不便，你可以运行这个软件，swap off它，然后再settings里禁止它随机启动就好了，或者你可以用11条的方法直接删除它。（86417046已测试可行）<br /><br />十四、刷完mocado2.9之后，出现手机不断启动，为什么？<br />      这是因为2.9rom和之前版本的一些软件有冲突，比如你手机里有装swapper这个软件，要在把它卸载掉才可以，或者你之前做了app2sd，并分出了第三个swap分区，这样就必须要把这个分区清空才行。<br /><br />十五、我刷新rom之后，我已经有的root权限还在吗？<br />      除非你新刷的rom是已经有root权限的，否则刷完之后需要重新获取root权限。<br /><br />十六、用update.zip压缩包刷机和用fastboot刷机的区别？<br />(update.zip)签名刷机相当于正常安装系统，fastboot刷相当于ghost镜像。Update的包比起fastboot的镜像更容易修改，且容易刷，签名作用是防止刷错包，fastboot其实属于维修或者技术人士用的，自然没有那么严格的签名认证。<br />killerking 发表于 2009-4-17 01:10 <br />      update刷机是要检查签名的。而fastboot可以刷自己编译的系统。<br /><br />十七、modaco的rom带app2sd，我改怎么操作？      <br />      modaco的自制rom可以自动app2sd，但需要你自己先将你的sd卡分出一个ext的分区，并且是第二分区，也就是在你以后文件的分区后面，用读卡器操作比较好，可以无损分区，分区可参考 <a href="http://www.androidin.net/bbs/viewthread.php?tid=821" title="http://www.androidin.net/bbs/viewthread.php?tid=821" target="_blank">http://www.androidin.net/bbs/viewthread.php?tid=821</a><br />      分区之后再刷rom便可以自动app2sd，有朋友在刷完rom之后分区，重启后hero自动变成了app2sd。<br />      想查看是否app2sd成功需要你有root权限，用root explorer之类的软件到system/sd/app文件夹下看你安装的软件是否在这个文件夹下，如果在下面，则app2sd成功。<br /><br />十八、我的手机是心机开机界面，怎么刷？      <br />      请参考此帖：<a href="http://www.androidin.net/bbs/thread-24879-1-1.html，也可以试试看这个http://forum.xda-developers.com/showthread.php?t=582336" title="http://www.androidin.net/bbs/thread-24879-1-1.html，也可以试试看这个http://forum.xda-developers.com/showthread.php?t=582336" target="_blank">http://www.androidin.net/bbs/thread-24879-1-1.html，也可以试试看这个http://forum.xda-developers.com/showthread.php?t=582336</a> （没测试，可能风险，刷入前请用recovery备份系统）<br /><br />十九、什么是radio，怎么刷radio？    <br />这个Radio指代的是通讯模块，就是手机里面负责信号部分的模块，PDA类型的手机，基本都强调这么个概念。一个是PDA，一个是手机（貌似是句废话- -），举个很简单的例子，以三星的PPC手机为例，比如i718.比如i908，他们在刷机的时候（所谓刷机就是重装系统）一般都是分两部分，第一部分刷手机部分，第二部分刷PDA部分，而且两部分基本不相干。<br />axela 发表于 2009-5-7 10:47 <br />刷radio和刷rom的操作基本相同，radio可以在 <a href="http://android.modaco.com/conten" title="http://android.modaco.com/conten" target="_blank">http://android.modaco.com/conten</a> ... -update-zip-format/ 下载，同样也是zip包，放到sd卡下，用home+挂机键 开机进入recovery，刷入这个zip文件，中间会要你重启一次（第一个选项重启），刷完后，下方会提示“fomating cache.......”，这个时候就是已经刷完了！<br />       radio可以在设置-&gt;关于手机里查看到，baseband版本就是。<br /><br />二十、什么是app2sd，为什么要做这个？<br />       google手机的软件为了安全性和稳定性都是默认安装到手机内存里，但是手机内存有限，所以我们会做app2sd操作，来让我们安装的软件放到sd卡上，而google的android系统是基于linux的，所以sd卡上本身的fat格式是不会被识别的，所以我们要分区（第二分区）出来，格式成linux认识的ext2或3或4格式，在用链接命令，把这个分区映射成一个系统文件夹system/sd（大概这个意思），把所有的软件装到这个“文件夹”下，这就是app2sd的操作。<br />app2sd的操作其实是牺牲了一部分软件的速度和稳定性来换取更多的手机内存安装更多的软件。另外，app2sd只是把软件放到了sd卡上，运行软件还是需要占用手机的内存的，所以，你装了软件之后，一般手机内存还是会减少一些。你如果安装的软件在70个以内，个人觉得没有必要，呵呵，如果很多游戏软件除外，此外，使用app2sd最大的好处就是，刷一个带app2sd的rom之后，以后升级这个rom（依然带app2sd）的时候，你的软件都会完整保存（个别除外，比如htc input chinese需要重新添加几个文件到system/lib下）。<br /><br />二十一、什么是root？我需要它做什么？<br />       root就是你手机的boss，它可以访问和修改你手机几乎所有的文件，这些东西可能是制作手机的人不愿意你修改和触碰的东西，因为他们有可能影响到手机的稳定，还容易被一些hacker有机会入侵你的手机（ms还没有出来这类黑客）。<br />       既然root这么危险，我们为什么还要去获取它？其实用root的权限主要是因为我们生在天朝，我们很多东西是受限制的，我们只能利用这些权限来做我们被限制的去做的事情，比如google禁止我们看到市场里很多免费或付费软件，我们可以用marketenabler来进去看；再比如国庆以来GFW把我们的市场干掉了，很多朋友只能看不能下，不能绑定gmail，我们可以修改hosts来搞定他们，但这些都需要root权限。<br /><br />二十二、怎么获取root权限呢？<br />       论坛提供了方法来获取hero的root权限，但是升级rom到2.73这后这个方法就变得没用了，就算获取成功，也会让你的wifi失效，而且这个方法获取的root不能用root explorer或者sufbs来修改系统文件，只能用于一些简单的root权限，比如使用marketenabler，所以我推荐都是刷带root权限的rom来实现，这类rom可以在 <a href="http://android.modaco.com/conten" title="http://android.modaco.com/conten" target="_blank">http://android.modaco.com/conten</a> ... -update-zip-format/ 找到。</div></div>]]></description>
      <wfw:commentRss><![CDATA[http://www.never-online.net/blog/feed.asp?q=comment&id=281]]></wfw:commentRss>
    </item>
      
    <item>
      <title><![CDATA[去天津拍的几张照片]]></title> 
      <link><![CDATA[http://www.never-online.net/blog/article.asp?id=280]]></link> 
      <category><![CDATA[Diary & Misc]]></category> 
      <author><![CDATA[Rank <null@null.com>]]></author> 
      <pubDate>Thu, 22 Oct 2009 21:54:15 +0800</pubDate> 
      <description><![CDATA[UV镜脏了。。。<br /><div style="width: 100%;overflow-x : auto;"><a href="http://farm3.static.flickr.com/2520/4034076613_c37ab4b978.jpg" target="_blank" rel="lightbox"><img src="http://farm3.static.flickr.com/2520/4034076613_c37ab4b978.jpg" alt="http://farm3.static.flickr.com/2520/4034076613_c37ab4b978.jpg" class="imgBorder"/></a></div><br /><div style="width: 100%;overflow-x : auto;"><a href="http://farm3.static.flickr.com/2678/4034832026_b5f8f253cb.jpg" target="_blank" rel="lightbox"><img src="http://farm3.static.flickr.com/2678/4034832026_b5f8f253cb.jpg" alt="http://farm3.static.flickr.com/2678/4034832026_b5f8f253cb.jpg" class="imgBorder"/></a></div><br /><div style="width: 100%;overflow-x : auto;"><a href="http://farm4.static.flickr.com/3501/4034839198_c68b3f4e4f.jpg" target="_blank" rel="lightbox"><img src="http://farm4.static.flickr.com/3501/4034839198_c68b3f4e4f.jpg" alt="http://farm4.static.flickr.com/3501/4034839198_c68b3f4e4f.jpg" class="imgBorder"/></a></div><br /><div style="width: 100%;overflow-x : auto;"><a href="http://farm3.static.flickr.com/2703/4034079315_bf242bdbab.jpg" target="_blank" rel="lightbox"><img src="http://farm3.static.flickr.com/2703/4034079315_bf242bdbab.jpg" alt="http://farm3.static.flickr.com/2703/4034079315_bf242bdbab.jpg" class="imgBorder"/></a></div>]]></description>
      <wfw:commentRss><![CDATA[http://www.never-online.net/blog/feed.asp?q=comment&id=280]]></wfw:commentRss>
    </item>
      
    <item>
      <title><![CDATA[雍和宫]]></title> 
      <link><![CDATA[http://www.never-online.net/blog/article.asp?id=279]]></link> 
      <category><![CDATA[Diary & Misc]]></category> 
      <author><![CDATA[Rank <null@null.com>]]></author> 
      <pubDate>Mon, 05 Oct 2009 02:31:16 +0800</pubDate> 
      <description><![CDATA[估计再过几天我的blog要变成相册了 <img src="http://www.never-online.net/blog/styles/g/images/smilies/icon_rolleyes.gif" border="0" alt="[rolleyes]" /> <br /><div style="width: 100%;overflow-x : auto;"><a href="http://farm3.static.flickr.com/2483/3980307371_3860bfb563.jpg" target="_blank" rel="lightbox"><img src="http://farm3.static.flickr.com/2483/3980307371_3860bfb563.jpg" alt="http://farm3.static.flickr.com/2483/3980307371_3860bfb563.jpg" class="imgBorder"/></a></div><br /><div style="width: 100%;overflow-x : auto;"><a href="http://farm4.static.flickr.com/3513/3981053990_ce87d9800d.jpg" target="_blank" rel="lightbox"><img src="http://farm4.static.flickr.com/3513/3981053990_ce87d9800d.jpg" alt="http://farm4.static.flickr.com/3513/3981053990_ce87d9800d.jpg" class="imgBorder"/></a></div><br /><div style="width: 100%;overflow-x : auto;"><a href="http://farm3.static.flickr.com/2652/3981071112_6078069ba3.jpg" target="_blank" rel="lightbox"><img src="http://farm3.static.flickr.com/2652/3981071112_6078069ba3.jpg" alt="http://farm3.static.flickr.com/2652/3981071112_6078069ba3.jpg" class="imgBorder"/></a></div><br /><div style="width: 100%;overflow-x : auto;"><a href="http://farm3.static.flickr.com/2464/3981074268_88283e6ab6.jpg" target="_blank" rel="lightbox"><img src="http://farm3.static.flickr.com/2464/3981074268_88283e6ab6.jpg" alt="http://farm3.static.flickr.com/2464/3981074268_88283e6ab6.jpg" class="imgBorder"/></a></div><br /><div style="width: 100%;overflow-x : auto;"><a href="http://farm3.static.flickr.com/2528/3980317333_1b261cbd4e.jpg" target="_blank" rel="lightbox"><img src="http://farm3.static.flickr.com/2528/3980317333_1b261cbd4e.jpg" alt="http://farm3.static.flickr.com/2528/3980317333_1b261cbd4e.jpg" class="imgBorder"/></a></div>]]></description>
      <wfw:commentRss><![CDATA[http://www.never-online.net/blog/feed.asp?q=comment&id=279]]></wfw:commentRss>
    </item>
      
    <item>
      <title><![CDATA[live]]></title> 
      <link><![CDATA[http://www.never-online.net/blog/article.asp?id=278]]></link> 
      <category><![CDATA[Diary & Misc]]></category> 
      <author><![CDATA[Rank <null@null.com>]]></author> 
      <pubDate>Fri, 02 Oct 2009 23:19:46 +0800</pubDate> 
      <description><![CDATA[<div style="width: 100%;overflow-x : auto;"><a href="http://farm3.static.flickr.com/2526/3973999333_68ee81ef85.jpg" target="_blank" rel="lightbox"><img src="http://farm3.static.flickr.com/2526/3973999333_68ee81ef85.jpg" alt="http://farm3.static.flickr.com/2526/3973999333_68ee81ef85.jpg" class="imgBorder"/></a></div><br /><div style="width: 100%;overflow-x : auto;"><a href="http://farm4.static.flickr.com/3526/3974756038_3573d9bfa1.jpg" target="_blank" rel="lightbox"><img src="http://farm4.static.flickr.com/3526/3974756038_3573d9bfa1.jpg" alt="http://farm4.static.flickr.com/3526/3974756038_3573d9bfa1.jpg" class="imgBorder"/></a></div><br /><div style="width: 100%;overflow-x : auto;"><a href="http://farm3.static.flickr.com/2594/3974763928_ce12eff153.jpg" target="_blank" rel="lightbox"><img src="http://farm3.static.flickr.com/2594/3974763928_ce12eff153.jpg" alt="http://farm3.static.flickr.com/2594/3974763928_ce12eff153.jpg" class="imgBorder"/></a></div><br /><div style="width: 100%;overflow-x : auto;"><a href="http://farm4.static.flickr.com/3501/3974795966_b8cdb41c31.jpg" target="_blank" rel="lightbox"><img src="http://farm4.static.flickr.com/3501/3974795966_b8cdb41c31.jpg" alt="http://farm4.static.flickr.com/3501/3974795966_b8cdb41c31.jpg" class="imgBorder"/></a></div><br /><div style="width: 100%;overflow-x : auto;"><a href="http://farm3.static.flickr.com/2427/3974083989_a266f73d56.jpg" target="_blank" rel="lightbox"><img src="http://farm3.static.flickr.com/2427/3974083989_a266f73d56.jpg" alt="http://farm3.static.flickr.com/2427/3974083989_a266f73d56.jpg" class="imgBorder"/></a></div><br /><div style="width: 100%;overflow-x : auto;"><a href="http://farm3.static.flickr.com/2473/3847757952_9c40867335.jpg" target="_blank" rel="lightbox"><img src="http://farm3.static.flickr.com/2473/3847757952_9c40867335.jpg" alt="http://farm3.static.flickr.com/2473/3847757952_9c40867335.jpg" class="imgBorder"/></a></div>]]></description>
      <wfw:commentRss><![CDATA[http://www.never-online.net/blog/feed.asp?q=comment&id=278]]></wfw:commentRss>
    </item>
      
    <item>
      <title><![CDATA[第一次用raw格式拍照]]></title> 
      <link><![CDATA[http://www.never-online.net/blog/article.asp?id=277]]></link> 
      <category><![CDATA[Diary & Misc]]></category> 
      <author><![CDATA[Rank <null@null.com>]]></author> 
      <pubDate>Wed, 30 Sep 2009 00:05:28 +0800</pubDate> 
      <description><![CDATA[iphoto很强大，直接导入即可用，还可以直接编辑raw格式。<img src="http://www.never-online.net/blog/styles/g/images/smilies/icon_lol.gif" border="0" alt="[lol]" /> ，但有个比较麻烦的事就是mac机器的颜色显示与windows不一致。真是麻烦的事情。。。<br /><div style="width: 100%;overflow-x : auto;"><a href="http://farm3.static.flickr.com/2533/3966449470_3a261dda9c.jpg" target="_blank" rel="lightbox"><img src="http://farm3.static.flickr.com/2533/3966449470_3a261dda9c.jpg" alt="http://farm3.static.flickr.com/2533/3966449470_3a261dda9c.jpg" class="imgBorder"/></a></div><br /><div style="width: 100%;overflow-x : auto;"><a href="http://farm4.static.flickr.com/3463/3966492366_073b35aa00.jpg" target="_blank" rel="lightbox"><img src="http://farm4.static.flickr.com/3463/3966492366_073b35aa00.jpg" alt="http://farm4.static.flickr.com/3463/3966492366_073b35aa00.jpg" class="imgBorder"/></a></div><br /><div style="width: 100%;overflow-x : auto;"><a href="http://farm3.static.flickr.com/2509/3965700455_34c3a316ed.jpg" target="_blank" rel="lightbox"><img src="http://farm3.static.flickr.com/2509/3965700455_34c3a316ed.jpg" alt="http://farm3.static.flickr.com/2509/3965700455_34c3a316ed.jpg" class="imgBorder"/></a></div><br /><div style="width: 100%;overflow-x : auto;"><a href="http://farm3.static.flickr.com/2599/3965672205_c70ac527e0.jpg" target="_blank" rel="lightbox"><img src="http://farm3.static.flickr.com/2599/3965672205_c70ac527e0.jpg" alt="http://farm3.static.flickr.com/2599/3965672205_c70ac527e0.jpg" class="imgBorder"/></a></div>]]></description>
      <wfw:commentRss><![CDATA[http://www.never-online.net/blog/feed.asp?q=comment&id=277]]></wfw:commentRss>
    </item>
      
  </channel>
</rss>
