<?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>welefen &#187; clone</title>
	<atom:link href="http://www.welefen.com/tag/clone/feed" rel="self" type="application/rss+xml" />
	<link>http://www.welefen.com</link>
	<description>风为人世在，在世人为风。</description>
	<lastBuildDate>Thu, 09 Sep 2010 11:29:24 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.0.1</generator>
		<item>
		<title>select节点clone全解析</title>
		<link>http://www.welefen.com/select-clone.html</link>
		<comments>http://www.welefen.com/select-clone.html#comments</comments>
		<pubDate>Fri, 18 Dec 2009 03:01:35 +0000</pubDate>
		<dc:creator>welefen</dc:creator>
				<category><![CDATA[前端开发]]></category>
		<category><![CDATA[clone]]></category>
		<category><![CDATA[cloneNode]]></category>
		<category><![CDATA[select]]></category>

		<guid isPermaLink="false">http://www.welefen.com/?p=177</guid>
		<description><![CDATA[在开发ns-log项目中，统计分类有复制的功能。由于之前的统计分类中的数据是通过JS赋值进去的，之后用户可能又进行了修改，发现进行节点克隆时，出现了 无法复制select下拉框值的怪异现象。本文对这个怪异现象进行解析和给出解决办法。 问题现状 使用节点的cloneNode(true/false)进行克隆时，目前是下面的表现情况： select为设置初始值或者初始值是第一个option。 表现：各大浏览器都没什么问题。 select初始值不是在第一个option。 表现：IE下无法克隆，其他内核的浏览器没什么问题。 select的值被用户或者JS修改。 表现：各个浏览器均无法克隆到真确的值。值结果跟第二条结果相同。 IE的特殊处理 对于上面第二条，初始值不在第一个option时无法克隆的情况，确实是IE的一个Bug，相信不少人都遇到过这样的问题。并且IE下使用cloneNode方法时，还有Event方面的问题，所以差不多可以放弃使用这个方法。 IE下可以使用节点的outerHTML属性解决这个问题，它能够实时的获取节点的内容，哪怕是select的值被用户或者程序改变。下面给出简单的实现。 function clone(node){ var div = document.createElement(&#8216;div&#8217;); div.innerHTML = node.outerHTML; return div.childNodes[0]; } 其他内核浏览器的处理 既然IE内核的浏览器可以通过outerHTML属性来解决这个问题，那FF等浏览器可以通过类似的方法来实现吗？虽然FF等浏览器没有outerHTML属性，但是可以通过innerHTML属性实现，如： function getOuterHTML(node){ var div = document.createElement(&#8216;div&#8217;); div.appendChild(node); try{ return div.innerHTML; }catch(e){ div = null; } } 答案是否定。 为什么会这样呢？难道是FF等浏览器的bug？ 下面还是从W3C中对cloneNode方法,select标签，属性的定义进行说明。 下面引用的资料都是来自HTML5草案，HTML4或者XHTML对这些没有太多详细的定义。虽然是HTML5的，但这些节点跟以前没什么变化。 W3C中的cloneNode 具体链接：http://www.w3.org/TR/DOM-Level-2-Core/core.html 里面有2点比较重要： 克隆时会拷贝节点的所有属性和对应的值。 如果cloneNode方法的参数为true，会通过递归的方法克隆子节点。 W3C中的select节点 具体链接：http://dev.w3.org/html5/spec/forms.html#the-select-element W3C对于属性的定义有2种，一种是内容性属性（Content [...]]]></description>
			<content:encoded><![CDATA[<p>在开发ns-log项目中，统计分类有复制的功能。由于之前的统计分类中的数据是通过JS赋值进去的，之后用户可能又进行了修改，发现进行节点克隆时，出现了 无法复制select下拉框值的怪异现象。本文对这个怪异现象进行解析和给出解决办法。</p>
<h2>问题现状</h2>
<p>使用节点的cloneNode(true/false)进行克隆时，目前是下面的表现情况：</p>
<ol>
<li>select为设置初始值或者初始值是第一个option。<br />
表现：各大浏览器都没什么问题。</li>
<li>select初始值不是在第一个option。<br />
表现：IE下无法克隆，其他内核的浏览器没什么问题。</li>
<li>select的值被用户或者JS修改。<br />
表现：各个浏览器均无法克隆到真确的值。值结果跟第二条结果相同。</li>
</ol>
<p><span id="more-177"></span></p>
<h2>IE的特殊处理</h2>
<p>对于上面第二条，初始值不在第一个option时无法克隆的情况，确实是IE的一个Bug，相信不少人都遇到过这样的问题。并且IE下使用cloneNode方法时，还有Event方面的问题，所以差不多可以放弃使用这个方法。</p>
<p>IE下可以使用节点的outerHTML属性解决这个问题，它能够实时的获取节点的内容，哪怕是select的值被用户或者程序改变。下面给出简单的实现。</p>
<p>function clone(node){<br />
var div = document.createElement(&#8216;div&#8217;);<br />
div.innerHTML = node.outerHTML;<br />
return div.childNodes[0];<br />
}</p>
<h2>其他内核浏览器的处理</h2>
<p>既然IE内核的浏览器可以通过outerHTML属性来解决这个问题，那FF等浏览器可以通过类似的方法来实现吗？虽然FF等浏览器没有outerHTML属性，但是可以通过innerHTML属性实现，如：</p>
<p>function getOuterHTML(node){<br />
var div = document.createElement(&#8216;div&#8217;);<br />
div.appendChild(node);<br />
try{<br />
return div.innerHTML;<br />
}catch(e){<br />
div = null;<br />
}<br />
}</p>
<p>答案是否定。</p>
<p>为什么会这样呢？难道是FF等浏览器的bug？</p>
<p>下面还是从W3C中对cloneNode方法,select标签，属性的定义进行说明。</p>
<p><span style="color: #ff0000;">下面引用的资料都是来自HTML5草案，HTML4或者XHTML对这些没有太多详细的定义。虽然是HTML5的，但这些节点跟以前没什么变化。</span></p>
<h2>W3C中的cloneNode</h2>
<p align="left">具体链接：<a href="http://www.w3.org/TR/DOM-Level-2-Core/core.html" target="_blank">http://www.w3.org/TR/DOM-Level-2-Core/core.html</a></p>
<p align="left">里面有2点比较重要：</p>
<ol>
<li>克隆时会拷贝节点的所有<span style="color: #ff0000;">属性</span>和对应的值。</li>
<li>如果cloneNode方法的参数为true，会通过递归的方法克隆子节点。</li>
</ol>
<h2>W3C中的select节点</h2>
<p>具体链接：<a href="http://dev.w3.org/html5/spec/forms.html#the-select-element" target="_blank">http://dev.w3.org/html5/spec/forms.html#the-select-element</a></p>
<p>W3C对于属性的定义有2种，一种是内容性属性（Content attributes），另一种是操作性属性（未给出具体的命名，这里暂时使用这个名字）。</p>
<p>对于select标签，内容性属性主要有：Global attributes，autofocus，disabled，form，multiple，name，size。其中Global attributes包含一些常用的属性(accesskey,class,contenteditable,contextmenu,dir,draggable,hidden,id,itemid,<br />
itemprop,itemref,itemscope,itemtype,lang,spellcheck,style,tabindex,title)，这些属性是所有标签里都包含的，具体的见<a href="http://dev.w3.org/html5/spec/dom.html#global-attributes" target="_blank">http://dev.w3.org/html5/spec/dom.html#global-attributes </a></p>
<p>而selectedIndex和value都属于操作性属性，这两个属性获取值的方式如下：</p>
<blockquote><dl>
<dt><var>select</var> . <code title="dom-select-selectedIndex"><a href="http://dev.w3.org/html5/spec/forms.html#dom-select-selectedindex">selectedIndex</a></code> [ = <var>value</var> ]</dt>
<dd>Returns the index of the first selected item, if any, or     −1 if there is no selected item.</p>
<p>Can be set, to change the selection.</p>
</dd>
<dt><var>select</var> . <code title="dom-select-value"><a href="http://dev.w3.org/html5/spec/forms.html#dom-select-value">value</a></code> [ = <var>value</var> ]</dt>
<dd>Returns the <a title="concept-fe-value" href="http://dev.w3.org/html5/spec/forms.html#concept-fe-value">value</a> of the     first selected item, if any, or the empty string if there is no     selected item.</p>
<p>Can be set, to change the selection.</p>
</dd>
</dl>
</blockquote>
<h2>内容性属性和操作性属性的区别</h2>
<p>给节点添加属性有两种方式，如下面所示：</p>
<p>var div = document.createElement(&#8216;div&#8217;)<br />
div.id = &#8216;welefen&#8217;; //直接加属性<br />
div.setAttribute(&#8216;id&#8217;,'welefen&#8217;); //通过setAttribute方法添加属性</p>
<p>对于内容性属性，这两种方法是完全相同的。</p>
<p>但对于操作性属性，第一种方式只会将属性添加在操作范围内，当把节点添加到DOM中，属性就失效了。</p>
<p>由于selectedIndex和value都是操作性属性，如果select的值被用户或者程序改变，clone时当前的值是无法带过去的。所以才会出现了无法克隆值的情况。并且也无法使用innerHTML来克隆值，因为innerHTML的原理跟这个是一样的。</p>
<p>innerHTML实现原理请看这里：<a href="http://www.w3.org/TR/2008/WD-html5-20080610/serializing.html#html-fragment" target="_blank">http://www.w3.org/TR/2008/WD-html5-20080610/serializing.html#html-fragment</a></p>
<h2>FF等浏览器解决方案</h2>
<p>目前有2中解决方案，第一种是在select绑定change事件，触发change的时候，改变options里的selected属性，当然这种方法是很不可取的。另一种方案就是在克隆时获取元素的值，然后再赋值到克隆后的对象上去。</p>
<h2>总结</h2>
<p>当前出现这个情况的时候，以为是FF等浏览器的bug。当后来仔细想想，应该不会这样的情况，后来反复查看W3C相关的文档，终于确认了这一问题。下面给出完整的解决方案：</p>
<p>function cloneSelect(select){<br />
if(document.all){<br />
var html = select.outerHTML,<br />
div = document.createElement(&#8216;div&#8217;);<br />
div.innerHTML = html;<br />
return div.childNodes[0];<br />
}<br />
var cloneSelect = select.cloneNode(true);<br />
cloneSelect.selectedIndex = select.selectedIndex;<br />
cloneSelect.value = select.value;<br />
return cloneSelect;<br />
}</p>
]]></content:encoded>
			<wfw:commentRss>http://www.welefen.com/select-clone.html/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
	</channel>
</rss>
<!-- WP Super Cache is installed but broken. The path to wp-cache-phase1.php in wp-content/advanced-cache.php must be fixed! -->