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

<channel>
	<title>西红柿爱番茄 &#187; DOM</title>
	<atom:link href="http://www.ilovejs.net/archives/tag/dom/feed" rel="self" type="application/rss+xml" />
	<link>http://www.ilovejs.net</link>
	<description>到了创造为主的阶段，不忘继续学习</description>
	<lastBuildDate>Thu, 15 Dec 2011 06:18:39 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.3</generator>
		<item>
		<title>无聊哥的代码 &#8212; “鸡”查询</title>
		<link>http://www.ilovejs.net/archives/1085</link>
		<comments>http://www.ilovejs.net/archives/1085#comments</comments>
		<pubDate>Mon, 02 Aug 2010 16:35:45 +0000</pubDate>
		<dc:creator>Supersha</dc:creator>
				<category><![CDATA[Javascript]]></category>
		<category><![CDATA[CSS]]></category>
		<category><![CDATA[DOM]]></category>
		<category><![CDATA[query]]></category>
		<category><![CDATA[querySelectorAll]]></category>

		<guid isPermaLink="false">http://www.ilovejs.net/?p=1085</guid>
		<description><![CDATA[刚上班，首先是文档哥，之后就是无聊哥了，真杯具。但是杯具下就好了，人不杯具。消遣的最好方式就是练练脑，写代码，query就是杯具下的产物。先出土个雏形，有时间还成无聊哥了再来扩展下。 query根据CSS规则来查询DOM，提供了基础的CSS选择符： tag,.class,#id,[attr],tag[attr],tag[attr=&#34;value&#34;]... 在测试跟jquery的查询速度比较的时候，再添加了对querySelectorAll（语法是：baseElement.querySelectorAll(selector)，这里的baseElement其实是可以为除了文本节点和空节点之外的任何的DOM节点的，别以为只是document而已）的支持。编写的代码中加入了本人认为不错的编写方式，如果你对阅读代码有兴趣，那就看看吧，欢迎提出更好的方式(如果这里显得难看了，就自己下载来看：query.js)： [javascript] ;(function(g){ var D = document, _tag = function(tag,p){ return p.getElementsByTagName(tag &#124;&#124; &#34;*&#34;); }; var _queryMethod &#8230; <a href="http://www.ilovejs.net/archives/1085" class="more-link">了解更多</a>]]></description>
			<content:encoded><![CDATA[<p>
刚上班，首先是文档哥，之后就是无聊哥了，真杯具。但是杯具下就好了，人不杯具。消遣的最好方式就是练练脑，写代码，query就是杯具下的产物。先出土个雏形，有时间还成无聊哥了再来扩展下。
</p>
<p>
query根据CSS规则来查询DOM，提供了基础的CSS选择符：
</p>
<pre class="wp-code-highlight prettyprint">
tag,.class,#id,[attr],tag[attr],tag[attr=&quot;value&quot;]...
</pre>
<p>在测试跟jquery的查询速度比较的时候，再添加了对querySelectorAll（语法是：baseElement.querySelectorAll(selector)，这里的baseElement其实是可以为除了文本节点和空节点之外的任何的DOM节点的，别以为只是document而已）的支持。编写的代码中加入了本人认为不错的编写方式，如果你对阅读代码有兴趣，那就看看吧，欢迎提出更好的方式(如果这里显得难看了，就自己下载来看：<a  href="/lab/query/query.js">query.js</a>)：<br />
<span id="more-1085"></span><br />
[javascript]<br />
;(function(g){<br />
	var D = document,<br />
		  _tag = function(tag,p){<br />
		    return p.getElementsByTagName(tag || &quot;*&quot;);<br />
	    };<br />
  var _queryMethod = {<br />
		&quot;#&quot;:function(q){<br />
			var bits = q.split(&quot;#&quot;),<br />
				  tagName = bits[0],<br />
				  id = bits[1],<br />
				  element = D.getElementById(id);<br />
			return tagName &amp;&amp; element.tagName.toLowerCase() != tagName ? [] : [element];<br />
		},<br />
		&quot;.&quot;:function(q,p){<br />
			var bits = q.split(&quot;.&quot;),<br />
				  tagName = bits[0],<br />
				  cn=bits[1],<br />
				  elems = null,<br />
				  returnEl = [],<br />
				  index = 0;<br />
		  for(var i=0,l = p.length;i&lt;l;i++){<br />
				elems = _tag(tagName,p[i]);<br />
				var tmp = null;<br />
				for(var j =0,m = elems.length;j&lt;m;j++){<br />
					if(!/\S/.test((tmp = elems[j]).nodeValue)) continue;<br />
					if(new RegExp(&quot;\\b&quot;+cn+&quot;\\b&quot;).test(tmp.className)){<br />
						returnEl[index++] = tmp;<br />
					}<br />
				}<br />
			}<br />
			return returnEl;<br />
		},<br />
		&quot;tag&quot;:function(q,p){<br />
			var found,returnEl = [],index=0;<br />
			q = q;<br />
			for(var i=0,l=p.length;i&lt;l;i++){<br />
				found = _tag(q,p[i]);<br />
				for(var j =0,m=found.length;j&lt;m;j++){<br />
					returnEl[index++] = found[j];<br />
				}<br />
			}<br />
			return returnEl;<br />
		},<br />
		&quot;attr&quot;:function(operation,tag,attr,attrValue,p){<br />
			var found =[],returnEl = [],index=fIndex=0;</p>
<p>			for(var i=0,l=p.length;i&lt;l;i++){<br />
				var tmp = _tag(tag,p[i]);<br />
				for(var j=0,m=tmp.length;j&lt;m;j++){<br />
					found[index++]=tmp[j];<br />
				}<br />
			}</p>
<p>			//不错吧？ ^_^<br />
			var checkFn = {<br />
				&#8216;=&#8217;:function(e) { return (e.getAttribute(attr) == attrValue); },<br />
		    &#8216;~&#8217;:function(e) { return (e.getAttribute(attr).match(new RegExp(&#8216;\\b&#8217;+attrValue+&#8217;\\b&#8217;))); },<br />
		    &#8216;|&#8217;:function(e) { return (e.getAttribute(attr).match(new RegExp(&#8216;^&#8217;+attrValue+&#8217;-?&#8217;))); },<br />
		    &#8216;^&#8217;:function(e) { return (e.getAttribute(attr).indexOf(attrValue) == 0); },<br />
		    &#8216;$&#8217;:function(e) { return (e.getAttribute(attr).lastIndexOf(attrValue) == e.getAttribute(attr).length &#8211; attrValue.length); },<br />
		    &#8216;*&#8217;:function(e) { return (e.getAttribute(attr).indexOf(attrValue) &gt; -1); },<br />
		    &#8216;a&#8217;:function(e) { return e.getAttribute(attr);}<br />
			}[operation];</p>
<p>			for(var i=0,l=found.length;i&lt;l;i++){<br />
				if(checkFn(found[i])){<br />
					returnEl[fIndex++] = found[i];<br />
				}<br />
			}<br />
			return returnEl;<br />
		}<br />
  }</p>
<p>	//处理每一个token<br />
	var _querySelector = function(q,p){<br />
		var elements = /#/.test(q) ? _queryMethod[&quot;#&quot;](q) : /\./.test(q) ? _queryMethod[&quot;.&quot;](q,p) : [];<br />
		if(elements.length) return elements;<br />
		if(!elements.length &amp;&amp; q.match(/^(\w*)\[(\w+)([=~\|\^\$\*]?)=?&quot;?([^\]&quot;]*)&quot;?\]$/)){<br />
			return _queryMethod[&quot;attr&quot;](RegExp.$3 || &quot;a&quot;,RegExp.$1,RegExp.$2,RegExp.$4,p);<br />
	  }<br />
		if(!elements.length){<br />
			return _queryMethod[&quot;tag&quot;](q,p);<br />
		}<br />
		return elements;<br />
	}</p>
<p>	var _query = function(q){<br />
		if(document.querySelectorAll){return document.querySelectorAll(q);}<br />
		var tokens = q.split(&#8216; &#8216;),token,elems=[D];<br />
		for(var i=0,l=tokens.length;i&lt;l;i++){<br />
			elems=_querySelector( tokens[i],elems);<br />
		}<br />
		return elems;<br />
	}<br />
	g.query=_query || {};<br />
})(this);<br />
[/javascript]<br />
我很经得起批的……《<a  href="/lab/query/">测试示例</a>》</p>
]]></content:encoded>
			<wfw:commentRss>http://www.ilovejs.net/archives/1085/feed</wfw:commentRss>
		<slash:comments>5</slash:comments>
		</item>
		<item>
		<title>图片导航设计方案</title>
		<link>http://www.ilovejs.net/archives/1055</link>
		<comments>http://www.ilovejs.net/archives/1055#comments</comments>
		<pubDate>Tue, 27 Jul 2010 09:18:43 +0000</pubDate>
		<dc:creator>Supersha</dc:creator>
				<category><![CDATA[Javascript]]></category>
		<category><![CDATA[DOM]]></category>
		<category><![CDATA[event]]></category>
		<category><![CDATA[图片导航]]></category>

		<guid isPermaLink="false">http://www.ilovejs.net/?p=1055</guid>
		<description><![CDATA[2010-7-29 Update: 在第一种实现方案中，如果图片的父元素设置了padding、margin之后，就会使得FF、Chrome等逻辑判断失误，而IE还完好。 &#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;-纠错分界线&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8211; 说“图片导航”或许很迷糊，我也迷糊不知道怎么描述，就是类似于Google、QQ空间、百度图片搜索中的在图片中出现上下箭头或者左右箭头来指示下一个和上一个图片的功能。昨天同事问到我这方面的实现方式，也就暂时想了两种。 之前查看过Google的方法是在图片上添加两个HTML元素作为逻辑操作对象（包括切换鼠标样式、点击事件等），这样就显得比较复杂了，需要确定图片的在页面中的位置、图片的宽高、之后还要判断鼠标的位置……QQ空间的相册导航，是在图片本身来操作逻辑的，这同我第一种方案很类似，而百度图片搜索结果页中图片导航是在图片的父元素中做逻辑的，这样就避免了图片大小对导航的干扰的问题（主要是如果图片太小，在图片上做导航就显得迷糊了，特别是鼠标的样式切换）。下面来说说我的方法。 第一种，直接在图片上做逻辑。事件参数e有这么两个参数，在FF等浏览器下是layerX,layerY，在IE下是offsetX,offsetY，用于在一个DOM元素触发事件的时候，鼠标在该元素上的偏移量。这个是好方法啊，在结合offsetHeight和offsetWidth，就可以直接在图片上做判断了，给图片添加mousemove、onclick事件来处理鼠标样式切换、点击事件逻辑等等。《测试用例1》，可是这种方法的一个缺点是：在IE6下，当鼠标移动到鼠标的时候，会默认的弹出一个框，很杯具。 第二中方式就是根据上面的技巧，在图片上覆盖一个div（或者其他的能覆盖的元素都成），覆盖就得获取到图片在页面中的坐标以及宽高了，通过offsetLeft和offsetTop可以方便的得到，兼容性也还好，对于不是非常复杂的DOM结构和CSS布局，应该都是没啥问题的。《测试用例》，这样就避免了IE6下弹出框的问题。不过这样代码就得写多几行了。 具体的实现方式可以查看上面给出了两个实例。]]></description>
			<content:encoded><![CDATA[<p>
<em>2010-7-29 Update:</em>
</p>
<p>
在第一种实现方案中，如果图片的父元素设置了padding、margin之后，就会使得FF、Chrome等逻辑判断失误，而IE还完好。
</p>
<p>&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;-纠错分界线&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8211;</p>
<p>
说“图片导航”或许很迷糊，我也迷糊不知道怎么描述，就是类似于Google、QQ空间、百度图片搜索中的在图片中出现上下箭头或者左右箭头来指示下一个和上一个图片的功能。昨天同事问到我这方面的实现方式，也就暂时想了两种。
</p>
<p>
之前查看过Google的方法是在图片上添加两个HTML元素作为逻辑操作对象（包括切换鼠标样式、点击事件等），这样就显得比较复杂了，需要确定图片的在页面中的位置、图片的宽高、之后还要判断鼠标的位置……QQ空间的相册导航，是在图片本身来操作逻辑的，这同我第一种方案很类似，而百度图片搜索结果页中图片导航是在图片的父元素中做逻辑的，这样就避免了图片大小对导航的干扰的问题（主要是如果图片太小，在图片上做导航就显得迷糊了，特别是鼠标的样式切换）。下面来说说我的方法。
</p>
<p>
第一种，直接在图片上做逻辑。事件参数e有这么两个参数，在FF等浏览器下是layerX,layerY，在IE下是offsetX,offsetY，用于在一个DOM元素触发事件的时候，鼠标在该元素上的偏移量。这个是好方法啊，在结合offsetHeight和offsetWidth，就可以直接在图片上做判断了，给图片添加mousemove、onclick事件来处理鼠标样式切换、点击事件逻辑等等。《<a  href="http://www.ilovejs.net/lab/img/index1.html">测试用例1</a>》，可是这种方法的一个缺点是：在IE6下，当鼠标移动到鼠标的时候，会默认的弹出一个框，很杯具。
</p>
<p>
第二中方式就是根据上面的技巧，在图片上覆盖一个div（或者其他的能覆盖的元素都成），覆盖就得获取到图片在页面中的坐标以及宽高了，通过offsetLeft和offsetTop可以方便的得到，兼容性也还好，对于不是非常复杂的DOM结构和CSS布局，应该都是没啥问题的。《<a  href="http://www.ilovejs.net/lab/img/index2.html">测试用例</a>》，这样就避免了IE6下弹出框的问题。不过这样代码就得写多几行了。
</p>
<p>具体的实现方式可以查看上面给出了两个实例。</p>
]]></content:encoded>
			<wfw:commentRss>http://www.ilovejs.net/archives/1055/feed</wfw:commentRss>
		<slash:comments>5</slash:comments>
		</item>
		<item>
		<title>随便写的一个Node代码</title>
		<link>http://www.ilovejs.net/archives/997</link>
		<comments>http://www.ilovejs.net/archives/997#comments</comments>
		<pubDate>Sun, 27 Jun 2010 06:41:32 +0000</pubDate>
		<dc:creator>Supersha</dc:creator>
				<category><![CDATA[Javascript]]></category>
		<category><![CDATA[DOM]]></category>
		<category><![CDATA[Node]]></category>
		<category><![CDATA[setAttribute]]></category>

		<guid isPermaLink="false">http://www.ilovejs.net/?p=997</guid>
		<description><![CDATA[2010-6-29 update 判断是IE6、7浏览器的方法还可以通过检测：document.documentElement.hasAttribute这个方法是否存在来判断。IE6、7下document.documentElement是不支持hasAttribute方法的；IE8、FF、Chrome、Opera等都支持。这样就可以避免丑陋的@cc_on判断方式了，不过在性能上，或许还是会@cc_on比较好。 &#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8211;完美的分界线&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;- 昨天想起了之前在口碑的时候就想写的一个代码：把HTML标签名作为方法来连缀性的插入元素，比如下面的操作方式： [javascript] var root=Node(&#34;div&#34;,&#34;&#34;,{&#34;id&#34;:&#34;test&#34;,&#34;class&#34;:&#34;div&#34;,&#34;onclick&#34;:&#34;alert(this.innerHTML);&#34;, &#34;style&#34;:&#34;background-color:#f00;&#34;}) .h1(&#34;P Element in DIV Element&#34;,{&#34;class&#34;:&#34;p&#34;}) .em(&#34;EM Element&#34;,{&#34;class&#34;:&#34;em&#34;}).appendTo(document.body); //========================================== Node(&#34;div&#34;,&#34;&#34;,{&#34;class&#34;:&#34;div&#34;,&#34;onclick&#34;:&#34;alert(this.innerHTML);&#34;}) .h1(&#34;P Element &#8230; <a href="http://www.ilovejs.net/archives/997" class="more-link">了解更多</a>]]></description>
			<content:encoded><![CDATA[<p><strong><em>2010-6-29 update</em></strong></p>
<p>
判断是IE6、7浏览器的方法还可以通过检测：document.documentElement.hasAttribute这个方法是否存在来判断。IE6、7下document.documentElement是不支持hasAttribute方法的；IE8、FF、Chrome、Opera等都支持。这样就可以避免丑陋的@cc_on判断方式了，不过在性能上，或许还是会@cc_on比较好。
</p>
<p>&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8211;完美的分界线&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;-<br />
昨天想起了之前在口碑的时候就想写的一个代码：把HTML标签名作为方法来连缀性的插入元素，比如下面的操作方式：<br />
[javascript]<br />
var root=Node(&quot;div&quot;,&quot;&quot;,{&quot;id&quot;:&quot;test&quot;,&quot;class&quot;:&quot;div&quot;,&quot;onclick&quot;:&quot;alert(this.innerHTML);&quot;,<br />
&quot;style&quot;:&quot;background-color:#f00;&quot;})<br />
.h1(&quot;P Element in DIV Element&quot;,{&quot;class&quot;:&quot;p&quot;})<br />
.em(&quot;EM Element&quot;,{&quot;class&quot;:&quot;em&quot;}).appendTo(document.body);<br />
//==========================================<br />
Node(&quot;div&quot;,&quot;&quot;,{&quot;class&quot;:&quot;div&quot;,&quot;onclick&quot;:&quot;alert(this.innerHTML);&quot;})<br />
.h1(&quot;P Element in DIV Element&quot;,{&quot;class&quot;:&quot;p&quot;})<br />
.em(&quot;EM Element&quot;,{&quot;class&quot;:&quot;em&quot;}).appendTo(root);<br />
[/javascript]</p>
<p>
如上代码所示，将HTML的标签名作为方法，在Node方法执行的时候就动态生成一个DOM元素，之后调用的HTML标签名形式的方法会一步一步的appendChild到前面的一个DOM元素中，调用每一个HTML标签名形式的方法都会动态生成一个相应的DOM元素，最后调用appendTo或者beforeTo方法将Node方法动态生成的DOM元素插入到这两个方法参数指定的父元素中。同时，还可以设置DOM元素的attribute、style、text。是不是有点意思呢？^_^
</p>
<p>
但是在写这个代码的时候，遇到的最大困难，就是setAttribute了，一来IE6、7对一些属性使用了不同的DOM属性名，在设置style的时候，也存在cssText和直接setAttribute style的差别，这些都是比较纠结的。幸好，下面的几个知识点可以解决大部分的冲突：
</p>
<ol>
<li>利用IE下setAttribute方法的第三个参数，可以解决IE6、7下对于一些属性大小写的差别。《<a  href="http://msdn.microsoft.com/en-us/library/ms536739(VS.85).aspx">setAttribute Method</a>》、《<a  href="http://www.yigle.net/2008/11/setattribute%E6%96%B9%E6%B3%95%E5%8F%82%E6%95%B0%E9%97%AE%E9%A2%98.html">setAttribute()方法参数问题</a>》</li>
<li>对于一些IE6、7跟其他浏览器的属性名完全不同（比如：class、for、checked、selected），这可以通过一个字面量对象来纠正，可以看下面我写的源码的解决办法。</li>
<li>IE6、7无法给onxxx属性（事件）直接赋值为字符串，需要赋给它函数才行。这个就需要做判断了，本人使用了@cc_on来判断IE的版本，并通过new Function的方式给IE6、7设置onxxx这样的属性。</li>
<li>同时，还有一个小陷阱，在HTML标签中直接声明onxxx属性的时候，不能够使用匿名函数的方式，比如:onclick=”function(){alert(&#8216;hello&#8217;);}”，这将会造成语法错误。</li>
</ol>
<p><span id="more-997"></span><br />
下面是本人写的Node代码，《<a  href="/lab/node/">测试示例</a>》^_^:<br />
[javascript]<br />
;(function(w) {<br />
  var D = document,_node = null,_root = null,<br />
     special = {<br />
       &quot;class&quot;: &quot;className&quot;,<br />
       &quot;checked&quot;: &quot;defaultChecked&quot;,<br />
       &quot;selected&quot;: &quot;defaultSelected&quot;,<br />
       &quot;for&quot;: &quot;htmlFor&quot;<br />
     },<br />
     flag =/*@cc_on @if (@_jscript_version &lt;= 5.7)!@end @*/false;</p>
<p>  var setStyle = function(elem, s) {<br />
    var styles = [];<br />
    if (typeof s === &quot;object&quot;) {<br />
      for (var k in s) {<br />
        styles.push(k + &quot;:&quot; + s[k]);<br />
      }<br />
      s = styles.join(&quot;;&quot;);<br />
    }<br />
    return elem.setAttribute(&quot;style&quot;, s) || (elem.style.cssText = s);<br />
  }</p>
<p>  var setAttr = function(el, attr) {<br />
    var val = &quot;&quot;;<br />
    for (var key in attr) {<br />
      val = attr[key];<br />
      if (flag &amp;&amp; /on/.test(key)) {<br />
        val = new Function(val);<br />
      }<br />
      key === &quot;style&quot; ? setStyle(el, attr[key]) : el.setAttribute(flag &amp;&amp; special[key] || key, val, 0);<br />
    }<br />
  }</p>
<p>  var _HTMLTagMethod = (function(arr) {<br />
    var o = {},el = null;<br />
    for (var i = 0,l = arr.length; i &lt; l; i++) {<br />
      (function(a) {<br />
        o[a] = function(t, attr) {<br />
          el = D.createElement(a);<br />
          setAttr(el, attr || {});<br />
          t ? (el.innerHTML = t) : null;<br />
          _node.appendChild(el);<br />
          _node = el;<br />
          return _HTMLTagMethod;<br />
        }<br />
      })(arr[i]);<br />
    }<br />
    o.appendTo = function(parent) {<br />
	  (parent || D.body).appendChild(_root);<br />
      return _root;<br />
    }<br />
    o.beforeTo = function(parent) {<br />
      var first = parent.firstChild;<br />
      first ? parent.insertBefore(_root, first) : this.appendTo(parent);<br />
      return _root;<br />
    }<br />
    return o;<br />
  })([&quot;p&quot;, &quot;span&quot;, &quot;div&quot;, &quot;input&quot;, &quot;select&quot;, &quot;h1&quot;, &quot;h2&quot;, &quot;h3&quot;, &quot;h4&quot;, &quot;h5&quot;, &quot;h6&quot;, &quot;em&quot;, &quot;strong&quot;, &quot;small&quot;, &quot;iframe&quot;, &quot;a&quot;, &quot;button&quot;, &quot;code&quot;, , &quot;li&quot;, &quot;ul&quot;, &quot;ol&quot;, &quot;dl&quot;, &quot;dt&quot;, &quot;dd&quot;, &quot;input&quot;, &quot;link&quot;, &quot;script&quot;, &quot;legend&quot;, &quot;form&quot;, &quot;table&quot;, &quot;tr&quot;, &quot;td&quot;, &quot;style&quot;, &quot;sub&quot;, &quot;sup&quot;, &quot;pre&quot;, &quot;del&quot;, &quot;fieldset&quot;, &quot;label&quot;, &quot;img&quot;, &quot;option&quot;]);<br />
/////<br />
//////////////////////////////////////////////////<br />
  w.Node = function(tag, t, attr) {<br />
    var el = D.createElement(tag);<br />
    t ? (el.innerHTML = t) : null;<br />
    setAttr(el, attr || {});<br />
    _root = el;<br />
    _node = el;<br />
    return _HTMLTagMethod;<br />
  }<br />
})(this);<br />
[/javascript]</p>
]]></content:encoded>
			<wfw:commentRss>http://www.ilovejs.net/archives/997/feed</wfw:commentRss>
		<slash:comments>3</slash:comments>
		</item>
		<item>
		<title>javascript代码性能优化</title>
		<link>http://www.ilovejs.net/archives/878</link>
		<comments>http://www.ilovejs.net/archives/878#comments</comments>
		<pubDate>Fri, 11 Jun 2010 19:35:59 +0000</pubDate>
		<dc:creator>Supersha</dc:creator>
				<category><![CDATA[Javascript]]></category>
		<category><![CDATA[性能优化]]></category>
		<category><![CDATA[code]]></category>
		<category><![CDATA[DOM]]></category>
		<category><![CDATA[性能]]></category>
		<category><![CDATA[闭包]]></category>

		<guid isPermaLink="false">http://www.ilovejs.net/?p=878</guid>
		<description><![CDATA[在这篇文章叙述的关于Javascript代码优化，其实并没有什么新意，关于这方面的优化，一直都是Nicholas C. Zakas的专利。我在这里将要说的是对当前众多关于Javascript代码优化的方式一个小总结，并尝试去归类各种不同的优化方式，方便于记忆众说纷纭的优化技巧。本人归类的结果如下图所示： Javascript代码优化无非主要围绕：DOM操作、循环、闭包、对象重复出现、对象的声明方式、作用域链、字符串操作、类的声明方式等等。循环、闭包、对象重复出现是从作用域链的角度去优化的；DOM操作主要围绕HTMLCollection、NodeList等来优化；对象的声明方式主要是对象（Object）、数组（Array）、字符串（String）、函数（Function）、正则（RegExp）等内置的对象使用字面量的方式来声明，这个比使用new来实例化相应的对象在性能上要强很多；字符串操作的优化方式主要是通过数组的push和join方法；类的声明方式优化方式主要是分清属性和方法的声明的方式，方法使用prototype的方式来声明；Javascript语言本身的流程操作语句的优化（if、switch、with、eval等等）。 因此，我将Javascript代码优化主要分为六类：DOM“真空”空间、缩短作用域链、字面量声明方式、字符串操作、类声明方式、流程操作语句。下面将逐个叙述： DOM“真空”空间 DOM“真空”空间这个词或许有些迷惑，举个例子就明白了：当使用removeChild将一个DOM元素从DOM树中删除之后，这个DOM元素并没有彻底消失，它就存在于DOM“真空”空间中，可以通过引用重新调用这个元素，并且对它的操作不会影响DOM文档树。 所以很多对DOM的HTMLCollection、NodeList操作的优化，都是利用了这个“真空”空间，先将元素从DOM树中剥离开来，再对这个元素进行一系列的操作之后，最后再通过appendChild或者insertBefore插入原来位置的DOM树中。这样就使得页面的reflow的次数最小化。比如下面优化的例子： [javascript] /** * Remove an element and provide a function that inserts &#8230; <a href="http://www.ilovejs.net/archives/878" class="more-link">了解更多</a>]]></description>
			<content:encoded><![CDATA[<p>
在这篇文章叙述的关于Javascript代码优化，其实并没有什么新意，关于这方面的优化，一直都是<a  href="http://www.nczonline.net/">Nicholas C. Zakas</a>的专利。我在这里将要说的是对当前众多关于Javascript代码优化的方式一个小总结，并尝试去归类各种不同的优化方式，方便于记忆众说纷纭的优化技巧。本人归类的结果如下图所示：
</p>
<p>
<img src="http://www.ilovejs.net/wp-content/uploads/2010/06/performance.png" title="performance catagroy" width="652" height="162" />
</p>
<p>
Javascript代码优化无非主要围绕：DOM操作、循环、闭包、对象重复出现、对象的声明方式、作用域链、字符串操作、类的声明方式等等。循环、闭包、对象重复出现是从作用域链的角度去优化的；DOM操作主要围绕HTMLCollection、NodeList等来优化；对象的声明方式主要是对象（Object）、数组（Array）、字符串（String）、函数（Function）、正则（RegExp）等内置的对象使用字面量的方式来声明，这个比使用new来实例化相应的对象在性能上要强很多；字符串操作的优化方式主要是通过数组的push和join方法；类的声明方式优化方式主要是分清属性和方法的声明的方式，方法使用prototype的方式来声明；Javascript语言本身的流程操作语句的优化（if、switch、with、eval等等）。
</p>
<p>
因此，我将Javascript代码优化主要分为六类：<em>DOM“真空”空间</em>、<em>缩短作用域链</em>、<em>字面量声明方式</em>、<em>字符串操作</em>、<em>类声明方式</em>、<em>流程操作语句</em>。下面将逐个叙述：
</p>
<p><span id="more-878"></span></p>
<p><strong>DOM“真空”空间</strong><br />
DOM“真空”空间这个词或许有些迷惑，举个例子就明白了：当使用removeChild将一个DOM元素从DOM树中删除之后，这个DOM元素并没有彻底消失，它就存在于DOM“真空”空间中，可以通过引用重新调用这个元素，并且对它的操作不会影响DOM文档树。
</p>
<p>
所以很多对DOM的HTMLCollection、NodeList操作的优化，都是利用了这个“真空”空间，先将元素从DOM树中剥离开来，再对这个元素进行一系列的操作之后，最后再通过appendChild或者insertBefore插入原来位置的DOM树中。这样就使得页面的reflow的次数最小化。比如下面优化的例子：
</p>
<p>[javascript]<br />
/**<br />
 * Remove an element and provide a function that inserts it into its original position<br />
 * @param element {Element} The element to be temporarily removed<br />
 * @return {Function} A function that inserts the element into its original position<br />
 **/<br />
//removeToInsertLater函数的作用是将element从DOM树中删除，保存于DOM“真空”空间里，同时返回一个闭包函数，用于在对element操作之后将其插回原来的位置。<br />
function removeToInsertLater(element) {<br />
  var parentNode = element.parentNode;<br />
  var nextSibling = element.nextSibling;<br />
  parentNode.removeChild(element);<br />
  return function() {<br />
    if (nextSibling) {<br />
      parentNode.insertBefore(element, nextSibling);<br />
    } else {<br />
      parentNode.appendChild(element);<br />
    }<br />
    nextSibling=null; //因为处于闭包中，需要设置为null，断开作用域链，下同。<br />
    parentNode=null;<br />
  };<br />
}<br />
//接下来我们就可以对element进行一系列的操作，最后插回去<br />
function updateAllAnchors(element, anchorClass) {<br />
  var insertFunction = removeToInsertLater(element);<br />
  var anchors = element.getElementsByTagName(&#8216;a&#8217;);<br />
  for (var i = 0, length = anchors.length; i &lt; length; i ++) {<br />
    anchors[i].className = anchorClass;<br />
  }<br />
  insertFunction();<br />
}<br />
[/javascript]</p>
<p>
如果所示，将需要操作的DOM元素先从DOM树中剥离开来，对其进行操作，再安插回去，减少了页面reflow的次数，还有一种方式是将HTMLCollection、NodeList对象转换成数组的形式来进行操作，这都是不错的优化方式，可以应用在很多类似的优化案例中。当然了，对DOM的操作，DOM本身提供的API方法也都存在性能问题，使用nextSibling比childNodes快多了、使用item比使用普通的索引慢多了、不同的循环的方式对操作HTMLCollection、NodeList也都存在不同的性能：《<a  href="http://www.ilovejs.net/archives/248">雷人的优化HTMLCollection对象的循环操作技巧</a>》，这个将会在下面的循环里叙述。
</p>
<p><strong>缩短作用域链</strong><br />
缩短作用域链，说简单点就是尽量使用局部变量来储存外部的对象。对于在循环中重复出现的对象，这个尤其具有优化效果；对于在闭包函数外的对象，当需要在闭包内使用的时候，可以在闭包内声明一个局部变量来储存该对象；还有对DOM元素的length属性、或者在DOM操作的循环中单个DOM元素使用局部变量来储存，也十分具有优化效果。目的就是使得在数据存取的过程中从作用域链中能最快的取出来，而最快的取出来的前提就是需要对象或者变量在作用域链的顶部。经过测试表明：局部变量的存取速度是最快的。所以将作用域外的对象局部引用化，也是不错的优化方式。循环也算是缩短作用域链的一个方面，但是某些方面也不全是，这个跟循环内部的比较和判断有关，具体请浏览《<a  href="http://www.ilovejs.net/archives/180">对循环操作的几种优化</a>》。下面举几个例子：
</p>
<p>[javascript]<br />
//例子一：将NodeList的length属性缓存起来，这样就可以避免每次重新计算length属性，重新查询一遍DOM树。<br />
var d = document.getElementsByTagName(&quot;div&quot;);<br />
for(var i=0, l = d.length; i&lt;l; i++){<br />
   //code here&#8230;<br />
}<br />
//=====================================<br />
//例子二：将每一个DOM元素局部化，因为对每一个DOM元素的操作，都需要在NodeList中去查询这个DOM元素。<br />
var d = document.getElementsByTagName(&quot;div&quot;);<br />
for(var i=0, l = d.length; i&lt;l; i++){<br />
   var item = d[i];<br />
   item.className=&quot;active&quot;;<br />
   item.title = &quot;active item&quot;;<br />
   //&#8230;&#8230;<br />
}<br />
//=====================================<br />
//例子三：储存重复出现的对象或者方法，特别是在循环中。将document.body缓存起来，这样在循环里读取的速度就非常快了。<br />
var b = document.body;<br />
for(var i=0;i&lt;10;i++){<br />
  b.appendChild(document.createTextNode(&quot;some text&quot;));<br />
}<br />
//=====================================<br />
//例子四：对闭包外的对象或者变量在闭包内局部化。<br />
//msg在setTimeout闭包参数的作用域外<br />
function setupAlertTimeout() {<br />
  var msg = &#8216;Message to alert&#8217;;<br />
  window.setTimeout(function() { alert(msg); }, 100);<br />
}<br />
//下面这个更快，将变量声明放到闭包内，使得读取速度更快。<br />
function setupAlertTimeout() {<br />
  window.setTimeout(function() {<br />
    var msg = &#8216;Message to alert&#8217;;<br />
    alert(msg);<br />
  }, 100);<br />
}<br />
//再来个更快的，这下避免使用闭包来作为setTimeout的参数，使得程序运行更快。<br />
function alertMsg() {<br />
  var msg = &#8216;Message to alert&#8217;;<br />
  alert(msg);<br />
}<br />
function setupAlertTimeout() {<br />
  window.setTimeout(alertMsg, 100);<br />
}<br />
[/javascript]</p>
<p>
对于上面例子四中关于闭包的使用，在这里解释一下：闭包非常强大而且使用，但是它也有很多缺陷，比如：是造成很多内存泄漏的罪魁祸首；声明一个闭包比声明一个不是闭包的内部函数更慢，比声明一个静态函数就更慢了。因此得出了上面的结论。
</p>
<p>
还有，对于缩短作用域链的一个更直白的解释例子如下：
</p>
<p>[javascript]<br />
var a = &#8216;a&#8217;;<br />
function createFunctionWithClosure() {<br />
  var b = &#8216;b&#8217;;<br />
  return function () {<br />
    var c = &#8216;c&#8217;;<br />
    a;<br />
    b;<br />
    c;<br />
  };<br />
}<br />
var f = createFunctionWithClosure();<br />
f();<br />
[/javascript]</p>
<p>
如上所示：当函数f调用的时候，读取a比读取b慢，比读取c又更慢。这就是作用域链的存取速度导致的性能问题，在HTMLCollection、NodeList中更甚。
</p>
<p><strong>字面量声明方式</strong><br />
这个字面量的声明方式的优化方式比较简单易懂，就是使用Javascript这门语言所独有的可以使用字面量的形式来声明对象的特点，这些比使用new来实例化响应的内置的对象将消耗更多的性能和时间，而且也不够灵活。比如下面的声明方式：
</p>
<p>[javascript]<br />
var obj = {};<br />
var obj2 = {<br />
        &quot;name&quot;:&quot;supersha&quot;<br />
}<br />
var arr = [];<br />
var arr2 = [1,2];<br />
var reg = /abc/gi;<br />
var fn = function(){<br />
  alert(&quot;传说中的Hello world&quot;);<br />
}<br />
[/javascript]</p>
<p><strong>字符串操作</strong><br />
字符串中的优化已经算是不值得多说了，主要使用数组的push、join方法来时优化。现在来说说使用传统的“+”或者“+=”运算符为啥低效：当使用“+”或者“+=”运算符的时候，内存中先会创建一个变量副本来储存这个连接的结果，之后把结果赋值给“=”号左边的变量或者对象属性，最后销毁这个变量副本，当在循环中通过“+”或者“+=”来连接字符串的时候，就不得不忍受副本变量的创建、赋值、销毁这一连串的操作，如果需要连接的两个字符串比较大的时候，就更难以忍受了。所以，对它的优化，就被无可奈何的提出来了。举个例子：
</p>
<p>[javascript]<br />
//例子一：<br />
var veryLongMessage = [<br />
'This is a long string that due to our strict line length limit of',<br />
' characters per line must be wrapped. ',<br />
'% of engineers dislike this rule. The line length limit is for ',<br />
' style purposes, but we do not want it to have a performance impact.',<br />
' So the question is how should we do the wrapping?'<br />
].join();<br />
//=====================================<br />
//例子二：<br />
var strBuilder = ['First 20 fibonacci numbers:'];<br />
for (var i = 0; i &lt; 20; i++) {<br />
  strBuilder.push(i, &#8216; = &#8216;, fibonacci(i));<br />
}<br />
var fibonacciStr = strBuilder.join(”);<br />
[/javascript]</p>
<p><strong>类声明方式</strong><br />
类声明方式的优化，主要是利用了prototype原型链的优点，使得类在实例化的时候不需要给每一个实例都声明相同名称的方法或者属性，而是通过prototype原型链来声明方法或者属性，使得每一个类的实例都从原型链共享这个方法或者属性（有些不知道怎么表达，暂且这样吧）。比如下面的例子：
</p>
<p>[javascript]<br />
//下面声明类的方式比较糟糕<br />
var Car = function(color,model,owner){<br />
  this.color=color;<br />
  this.model=model;<br />
  this.owner=owner;<br />
  this.setColor=function(c){<br />
    this.color=c;<br />
  }<br />
  //&#8230;.<br />
}<br />
//改进一下下，好多了……<br />
var Car = function(color,model,owner){<br />
  this.color=color;<br />
  this.model=model;<br />
  this.owner=owner;<br />
}<br />
Car.prototype.setColor=function(c){<br />
  this.color=c;<br />
}<br />
[/javascript]</p>
<p>
<strong>流程操作语句</strong><br />
这里所说的流程操作语句主要是if、switch、do while、while、for、try catch，也有with、eval等等。if语句和switch语句之间的衡量是经常会碰到的优化问题：《<a  href="http://www.ilovejs.net/archives/577">对Duff策略优化数组操作的疑虑</a>》；循环的优化在上面已经叙述过了；我相信很多叙述有关Javascript性能的文章都建议避免使用with、eval，甚至是try catch语句，因为catch语句会增加作用域链的深度，造成数据读取速度下降的性能问题，更多的细节可以阅读《<a  href="http://www.ilovejs.net/archives/509">高性能网站建设进阶指南</a>》和<a  href="http://www.nczonline.net/">Nicholas C.Zakas</a>著的《<a  href="http://www.amazon.com/Performance-JavaScript-Faster-Application-Interfaces/dp/059680279X">High Performance JavaScript</a>》中更详细的叙述。
</p>
<p>
<strong>总结：</strong>上面例举了Javascript代码优化的五个基本类别的方式。当然了，Javascript代码优化还远不止上面例子中出现的情况，大到设计模式、Ajax应用，小到还有对if、switch、with、eval等等的优化等等，无处不存在着代码性能优化这些细节问题，但是细化下来，也基本在上面五个类别里了。案例是丰富多彩的，但是本质不变。目的只有一个：<strong>让你的代码跑的更快</strong>。
</p>
<p>
延伸阅读：《<a  href="http://blogs.msdn.com/b/ie/archive/2006/08/28/728654.aspx">IE + JavaScript Performance Recommendations &#8211; Part 1</a>》，《<a  href="http://blogs.msdn.com/b/ie/archive/2006/11/16/ie-javascript-performance-recommendations-part-2-javascript-code-inefficiencies.aspx">IE+JavaScript Performance Recommendations Part 2: JavaScript Code Inefficiencies</a>》，《<a  href="http://blogs.msdn.com/b/ie/archive/2007/01/04/ie-jscript-performance-recommendations-part-3-javascript-code-inefficiencies.aspx">IE+JScript Performance Recommendations Part 3: JavaScript Code Inefficiencies</a>》，《<a  href="http://code.google.com/speed/articles/optimizing-javascript.html">Optimizing JavaScript code</a>》，《<a  href="http://code.google.com/speed/articles/javascript-dom.html">Speeding up JavaScript: Working with the DOM</a>》</p>
]]></content:encoded>
			<wfw:commentRss>http://www.ilovejs.net/archives/878/feed</wfw:commentRss>
		<slash:comments>8</slash:comments>
		</item>
		<item>
		<title>fireTest&#8212;类似于firebug查看元素padding、margin等等的方法</title>
		<link>http://www.ilovejs.net/archives/304</link>
		<comments>http://www.ilovejs.net/archives/304#comments</comments>
		<pubDate>Fri, 26 Feb 2010 12:40:45 +0000</pubDate>
		<dc:creator>Supersha</dc:creator>
				<category><![CDATA[Javascript]]></category>
		<category><![CDATA[DOM]]></category>
		<category><![CDATA[fireTest]]></category>

		<guid isPermaLink="false">http://www.ilovejs.net/?p=304</guid>
		<description><![CDATA[//////////////////// 2010-2-27 update ////////////////// 根据需要，增加了使用和禁用开关模式(右下角)，在页面中直接加载fireTest.js文件即可： [javascript] &#60;script src=&#34;fireTest.js&#34; type=&#34;text/javascript&#34;&#62;&#60;/script&#62; [/javascript] 或者直接链接到本站fireTest.js文件：http://www.ilovejs.net/lab/fireTest/fireTest.js 《点击查看测试页面》 /////////////////////////////////////////////////////////////////// 昨晚睡觉的时候脑子突然想实现这么个东东 &#8212; 类似于firebug的查看DOM元素padding、margin的情况。虽然firebug已经发布了Lite版本，可以在非火狐的浏览器下测试网页的各种信息，但是由于Lite版本是用js实现的，在某些浏览器下（特别是IE下），影响了整体的性能，使用上也不太方便查看。目前各主流浏览器都内置了这项功能，Google Chrome，Safari，Opera，IE8等等都已经有非常强大的开发人员测试工具。 写这个工具一方面是为了方便自己在非火狐浏览器下类似于firebug的查看DOM元素的padding，margin的情况（除了IE6），但是目前还不支持IE6（fuck 框模型hack），日后有时间完善这个。 《点击查看测试页面》]]></description>
			<content:encoded><![CDATA[<p>
//////////////////// <em>2010-2-27 update</em> //////////////////
</p>
<p>根据需要，增加了使用和禁用开关模式(右下角)，在页面中直接加载fireTest.js文件即可：<br />
[javascript]<br />
&lt;script src=&quot;fireTest.js&quot; type=&quot;text/javascript&quot;&gt;&lt;/script&gt;<br />
[/javascript]</p>
<p>
或者直接链接到本站fireTest.js文件：<a  href="http://www.ilovejs.net/lab/fireTest/fireTest.js">http://www.ilovejs.net/lab/fireTest/fireTest.js</a><br />
《<a  href="http://www.ilovejs.net/lab/fireTest/">点击查看测试页面</a>》
</p>
<p>///////////////////////////////////////////////////////////////////</p>
<p>
昨晚睡觉的时候脑子突然想实现这么个东东 &#8212; 类似于firebug的查看DOM元素padding、margin的情况。虽然firebug已经发布了Lite版本，可以在非火狐的浏览器下测试网页的各种信息，但是由于Lite版本是用js实现的，在某些浏览器下（特别是IE下），影响了整体的性能，使用上也不太方便查看。目前各主流浏览器都内置了这项功能，Google Chrome，Safari，Opera，IE8等等都已经有非常强大的开发人员测试工具。
</p>
<p>
写这个工具一方面是为了方便自己在非火狐浏览器下类似于firebug的查看DOM元素的padding，margin的情况（除了IE6），但是目前还不支持IE6（fuck 框模型hack），日后有时间完善这个。
</p>
<p>《<a  href="http://www.ilovejs.net/lab/fireTest/">点击查看测试页面</a>》</p>
]]></content:encoded>
			<wfw:commentRss>http://www.ilovejs.net/archives/304/feed</wfw:commentRss>
		<slash:comments>9</slash:comments>
		</item>
		<item>
		<title>获取DOM元素的真实高度和宽度</title>
		<link>http://www.ilovejs.net/archives/108</link>
		<comments>http://www.ilovejs.net/archives/108#comments</comments>
		<pubDate>Fri, 01 Jan 2010 06:03:21 +0000</pubDate>
		<dc:creator>Supersha</dc:creator>
				<category><![CDATA[Javascript]]></category>
		<category><![CDATA[display]]></category>
		<category><![CDATA[DOM]]></category>

		<guid isPermaLink="false">http://www.ilovejs.net/?p=108</guid>
		<description><![CDATA[以前在做动画脚本的时候，遇到过这样的一个问题：当DOM元素display:none;之后，你将得不到它的实际高度和宽度。这个在fadein等类似效果的时候就有些问题了。这个问题困扰了一些时间，最后觉得还是元素隐藏导致的结果，因此采用了这样的方法：将隐藏的元素的display暂时设置为block，获取到真实的高度和宽度之后，再还原隐藏元素。下面是我封装好的获取元素的真实高度和宽度的对象： [javascript] var Style = { //获取元素最终的样式 getFinalStyle: function(elem, css){ if (window.getComputedStyle) { return window.getComputedStyle(elem, null)[css]; } else if (elem.currentStyle) &#8230; <a href="http://www.ilovejs.net/archives/108" class="more-link">了解更多</a>]]></description>
			<content:encoded><![CDATA[<p>
以前在做动画脚本的时候，遇到过这样的一个问题：当DOM元素display:none;之后，你将得不到它的实际高度和宽度。这个在fadein等类似效果的时候就有些问题了。这个问题困扰了一些时间，最后觉得还是元素隐藏导致的结果，因此采用了这样的方法：将隐藏的元素的display暂时设置为block，获取到真实的高度和宽度之后，再还原隐藏元素。下面是我封装好的获取元素的真实高度和宽度的对象：
</p>
<p>[javascript]<br />
var Style = {<br />
    //获取元素最终的样式<br />
    getFinalStyle: function(elem, css){<br />
        if (window.getComputedStyle) {<br />
            return window.getComputedStyle(elem, null)[css];<br />
        } else if (elem.currentStyle) {<br />
            return elem.currentStyle[css];<br />
        } else {<br />
            return elem.style[css];<br />
        }<br />
    },<br />
    height: function(elem){<br />
        if (this.getFinalStyle(elem, &quot;display&quot;) !== &quot;none&quot;) {<br />
            return elem.offsetHeight || elem.clientHeight;<br />
        } else {<br />
            //获取隐藏掉的函数的高度，先让它显示，获取到高度之后再隐藏，下同<br />
            elem.style.display = &quot;block&quot;;<br />
            var h = elem.offsetHeight || elem.clientHeight;<br />
            elem.style.display = &quot;none&quot;;<br />
            return h;<br />
        }<br />
    },<br />
    width: function(elem){<br />
        if (this.getFinalStyle(elem, &quot;display&quot;) !== &quot;none&quot;) {<br />
            return elem.offsetWidth || elem.clientWidth;<br />
        } else {<br />
            elem.style.display = &quot;block&quot;;<br />
            var w = elem.offsetWidth || elem.clientWidth;<br />
            elem.style.display = &quot;none&quot;;<br />
            return w;<br />
        }<br />
    }<br />
};</p>
<p>//Usage：<br />
onload = function(){<br />
     alert(Style.height(document.getElementById(&quot;div&quot;)));<br />
}<br />
[/javascript]</p>
]]></content:encoded>
			<wfw:commentRss>http://www.ilovejs.net/archives/108/feed</wfw:commentRss>
		<slash:comments>4</slash:comments>
		</item>
		<item>
		<title>获得DOM元素X/Y坐标的几个函数</title>
		<link>http://www.ilovejs.net/archives/63</link>
		<comments>http://www.ilovejs.net/archives/63#comments</comments>
		<pubDate>Wed, 23 Dec 2009 16:30:00 +0000</pubDate>
		<dc:creator>Supersha</dc:creator>
				<category><![CDATA[Javascript]]></category>
		<category><![CDATA[DOM]]></category>
		<category><![CDATA[style]]></category>

		<guid isPermaLink="false">http://www.ilovejs.net/?p=63</guid>
		<description><![CDATA[今天看到了口碑UED中Zhusun的一篇关于获取DOM元素在文档中的位置的文章，《获取Dom元素的X/Y坐标》，第一次知道了DOM元素还有一个getBoundingClientRect()方法可以使用来返回DOM元素的Top,Left,Right,Bottom。这个方法的具体用法和含义推荐看Zhusun的那篇文章。据他所说这个方法在某些浏览器还不兼容（FF2、Safari），所以本人从offsetParent这个方法出发，来获取DOM元素的X/Y坐标。 offsetParent有四个方法是比较常用的：offsetLeft，offsetTop，offsetWidth，offsetHeight。下面我来说明offsetLeft和offsetTop方法的含义。 offsetTop和offsetLeft分别是元素在offsetParent上下文中的水平和垂直偏移量，它在现代浏览器中都比较准确。但是ie6,ie7在计算的时候会多出2个像素的长度,大家可以使用下面提供的函数来测试。下面是封装的几个函数： [javascript] //获取DOM元素在可见区域的X坐标 function pageX(elem){ //如果当前元素还存在offsetParent，就递归叠加，下面的同理 return elem.offsetParent ? elem.offsetLeft + pageX(elem.offsetParent) : elem.offsetLeft; } //获取DOM元素在可见区域的Y坐标 function pageY(elem){ &#8230; <a href="http://www.ilovejs.net/archives/63" class="more-link">了解更多</a>]]></description>
			<content:encoded><![CDATA[<p>今天看到了<a href="http://ued.koubei.com">口碑UED</a>中Zhusun的一篇关于获取DOM元素在文档中的位置的文章，《<a href="http://ued.koubei.com/?p=948">获取Dom元素的X/Y坐标</a>》，第一次知道了DOM元素还有一个getBoundingClientRect()方法可以使用来返回DOM元素的Top,Left,Right,Bottom。这个方法的具体用法和含义推荐看Zhusun的那篇文章。据他所说这个方法在某些浏览器还不兼容（FF2、Safari），所以本人从offsetParent这个方法出发，来获取DOM元素的X/Y坐标。</p>
<p>
offsetParent有四个方法是比较常用的：offsetLeft，offsetTop，offsetWidth，offsetHeight。下面我来说明offsetLeft和offsetTop方法的含义。
</p>
<p><span id="more-63"></span></p>
<p>
offsetTop和offsetLeft分别是元素在offsetParent上下文中的水平和垂直偏移量，它在现代浏览器中都比较准确。但是ie6,ie7在计算的时候会多出2个像素的长度,大家可以使用下面提供的函数来测试。下面是封装的几个函数：
</p>
<p>[javascript]<br />
//获取DOM元素在可见区域的X坐标<br />
function pageX(elem){<br />
    //如果当前元素还存在offsetParent，就递归叠加，下面的同理<br />
    return elem.offsetParent ? elem.offsetLeft + pageX(elem.offsetParent) : elem.offsetLeft;<br />
}<br />
//获取DOM元素在可见区域的Y坐标<br />
function pageY(elem){<br />
    return elem.offsetParent ? elem.offsetTop + pageY(elem.offsetParent) : elem.offsetTop;<br />
}<br />
//获取DOM元素相对于parentNode的X坐标<br />
function parentX(elem){<br />
    //鉴于有些浏览器对于offsetParent指向不准确的进行判断是否跟元素的parentNode相等，下同。<br />
    return elem.offsetParent == elem.parentNode ? elem.offsetLeft : pageX(elem) &#8211; pageX(elem.parentNode);<br />
}<br />
//获取DOM元素相对于parentNode的Y坐标<br />
function parentY(elem){<br />
    return elem.offsetParent == elem.parentNode ? elem.offsetTop : pageY(elem) &#8211; pageY(elem.parentNode);<br />
}<br />
[/javascript]</p>
<p>上面的几个函数在table里面测试在各个浏览器都基本相同（FF，Chrome，Safari，Opera，IE8），可是ie6和ie7会多出2个像素的长度。大家可以自己测试一下：<a href="http://www.ilovejs.net/lab/xy.html">测试页面</a>。</p>
<p>
offsetHeight和offsetWidth主要用于获取DOM元素潜在的高度和宽度，比如图片或者一些没有显示声明高度和宽度的DOM元素等等就非常适合。
</p>
<p>
同时附带一个非常有用的函数，就是用于获取DOM元素的最终样式的getStyle函数，它通过IE的currentStyle以及FF等浏览器的getComputedStyle方法来获取最终样式：
</p>
<p>[javascript]<br />
//注意：样式属性的书写格式必须是骆驼型，比如:font-size要写成fontSize<br />
var getStyle = function(el, c){<br />
    if (el.currentStyle) { //IE<br />
        return el.currentStyle[c];<br />
    } else if (window.getComputedStyle) {  //W3C<br />
        return window.getComputedStyle(el, null)[c];<br />
    } else {<br />
        return el.style[c];<br />
    }<br />
}<br />
[/javascript]</p>
]]></content:encoded>
			<wfw:commentRss>http://www.ilovejs.net/archives/63/feed</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>检查DOM是否加载完成的一种方式</title>
		<link>http://www.ilovejs.net/archives/51</link>
		<comments>http://www.ilovejs.net/archives/51#comments</comments>
		<pubDate>Tue, 22 Dec 2009 04:56:57 +0000</pubDate>
		<dc:creator>Supersha</dc:creator>
				<category><![CDATA[Javascript]]></category>
		<category><![CDATA[DOM]]></category>

		<guid isPermaLink="false">http://www.ilovejs.net/?p=51</guid>
		<description><![CDATA[2010-10-19 updates 今天有网友说下面简化的版本在IE6下会触发IE6的“终止操作”的bug，测试了一下，确实存在这个问题（问题页面），所以对简化版的DOMReady进行了重构了，使用setInterval代替setTimeout就没事了，很奇怪的问题： [javascript] var DOMReady = { ready: function(){ var that = DOMReady,done = false,init,args = arguments; //ready之后统一处理函数 init &#8230; <a href="http://www.ilovejs.net/archives/51" class="more-link">了解更多</a>]]></description>
			<content:encoded><![CDATA[<p>
<strong>2010-10-19 updates</strong>
</p>
<p>
今天有网友说下面简化的版本在IE6下会触发IE6的“终止操作”的bug，测试了一下，确实存在这个问题（<a  href="/lab/domready.html">问题页面</a>），所以对简化版的DOMReady进行了重构了，使用setInterval代替setTimeout就没事了，很奇怪的问题：
</p>
<p>[javascript]<br />
var DOMReady = {<br />
  ready: function(){<br />
    var that = DOMReady,done = false,init,args = arguments;<br />
	//ready之后统一处理函数<br />
	init = function(){<br />
	  if(!done){<br />
	    done = true;<br />
		(typeof args[0] === &quot;function&quot; ? args[0] : function(){})();<br />
	  }<br />
	}<br />
	//添加DOMContentLoaded事件的支持<br />
	if (document.addEventListener) {<br />
      document.addEventListener(&quot;DOMContentLoaded&quot;, init, false);<br />
    }<br />
	//使用普通的方式进行检测<br />
	var interval = setInterval(function(){<br />
	  if (document &amp;&amp; document.getElementsByTagName &amp;&amp; document.getElementById &amp;&amp; document.body) {<br />
	    clearInterval(interval);<br />
		init();<br />
	  }<br />
	},20);<br />
  }<br />
};<br />
[/javascript]</p>
<p>
或者再使用更加强健一点的方式：
</p>
<p>[javascript]<br />
var DOMReady = {<br />
  ready: function(){<br />
    var that = DOMReady,<br />
	    done = false,<br />
		init = typeof arguments[0] === &quot;function&quot; ? arguments[0] : function(){},<br />
		u = navigator.userAgent;<br />
	if (/webkit/i.test(u)) {<br />
	  (function(){<br />
        var dr = document.readyState;<br />
        if (dr == &quot;loaded&quot; || dr == &quot;complete&quot;) {<br />
          init();<br />
        } else {<br />
          setTimeout(arguments.callee, 10);<br />
        }<br />
      })();<br />
	}else if (document.addEventListener) { //添加DOMContentLoaded事件的支持<br />
      document.addEventListener(&quot;DOMContentLoaded&quot;, init, false);<br />
    }else{<br />
	  (function(){<br />
         var t = document.createElement(&#8216;doc:rdy&#8217;);<br />
         try {<br />
            t.doScroll(&#8216;left&#8217;);<br />
            init();<br />
            t = null;<br />
         } catch (e) {<br />
            setTimeout(arguments.callee, 0);<br />
         }<br />
      })();<br />
	}<br />
  }<br />
};<br />
[/javascript]</p>
<p>
=================== 就错线 =====================
</p>
<p>在很多javascript库中，检查DOM是否加载完成是非常重要的一个功能模块，它可以被独立出来作为一个模块来供其他对象调用，下面是我提供的一种方式，原理<em>就是使用一个定时器来循环检查document，document.body，document.body.lastChild是否可用，从而证明DOM是否加载完成</em>：
</p>
<p>[javascript]<br />
/**<br />
 * @author Supersha<br />
 * @website http://www.ilovejs.net<br />
 */<br />
var DOMReady = {<br />
    done: false,<br />
    ID: 0,<br />
    fn:null,<br />
    ready: function(){<br />
        this.fn = typeof arguments[0] === &quot;function&quot; ? arguments[0] : function(){<br />
            alert(&quot;Argument should be a function.&quot;);<br />
        };<br />
		//添加对Firefox，Opera等支持DOMContentLoaded事件的支持<br />
        if (document.addEventListener) {<br />
            document.addEventListener(&quot;DOMContentLoaded&quot;, this.fn, false);<br />
            return;<br />
        }<br />
		//持续检查DOM是否加载完成<br />
        this.ID = setInterval(this.check(this), 20);<br />
    },<br />
    check: function(obj){<br />
        return function(){<br />
            if (obj.done) {<br />
                clearInterval(obj.ID);<br />
                obj.fn();<br />
            } else if (document &amp;&amp; document.getElementsByTagName &amp;&amp; document.getElementById &amp;&amp; document.body) {<br />
                obj.done = true;<br />
            }<br />
        }<br />
    }<br />
}<br />
[/javascript]<br />
把DOMReady对象模块添加到其他的功能模块中就可以非常方便的去操作DOM，而无需考虑是否加载完成，比如：<br />
[javascript]<br />
DOMReady.ready(function(){<br />
    alert(document.getElementById(&quot;div&quot;).innerHTML);<br />
});<br />
[/javascript]</p>
<p>################ 即时更新 ####################<br />
利用arguments.callee还能更加精简DOMReady对象的代码：<br />
[javascript]<br />
var DOMReady = {<br />
    ready: function(){<br />
        DOMReady .fn = typeof arguments[0] === &quot;function&quot; ? arguments[0] : function(){};<br />
        (function(){<br />
            if (document &amp;&amp; document.getElementsByTagName &amp;&amp; document.getElementById &amp;&amp; document.body)        {<br />
                DOMReady .fn();<br />
            }<br />
            else {<br />
                //利用arguments.callee获取匿名函数的引用，之后在setTimeout定时器里循环执行<br />
                setTimeout(arguments.callee, 20);<br />
            }<br />
        })();<br />
    }<br />
};<br />
[/javascript]</p>
]]></content:encoded>
			<wfw:commentRss>http://www.ilovejs.net/archives/51/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
	</channel>
</rss>

