`
虚怀若谷
  • 浏览: 9019 次
  • 性别: Icon_minigender_1
  • 来自: 杭州
最近访客 更多访客>>
文章分类
社区版块
存档分类
最新评论

Javascript CloneNode 在IE下面的一个问题

阅读更多
相信大家都用过cloneNode这个方法,这个方法很不错,效率也很高,推荐使用。最近在使用它的时候,发现了一个隐藏的比较深的问题,和大家享一下。这个问题不像clone select来得有名气,先看代码:

<style type='text/css'>
	input.focus{border:1px solid red; background-color:yellow;}
</style>
<input type="text" name="testinput" check="num" id="myinput" />
<script type="text/javascript">
     var originalInput = $('myinput');
	 $E.on(input,'focus',function(){$D.addClass(this,'focus');});
	 $E.on(input,'blur',function(){$D.removeClass(this,'focus');});
	 var clonedInput = originalInput.cloneNode(true);//deep copy
	 clonedInput.removeAttribute('id');//remove id
	 document.body.appendChild(clonedInput);
</script>


注:$,$D,$E等是在YUI库上面封装的一些方法,这里只为书写及说明方便。

好了,运行程序,奇怪的问题出现了,clonedInput 的 focus事件竟然触发了 originalInput 的 focus 事件!!!(注:只在IE有此现象,FF下正常,others没测)。有些人可能会认为这是YUI库的bug,这点我可以很负责任的告诉你这不是YUI库的bug,而是IE自己的bug ? bug : feature。
没辙了吧,看下MSDN的说明:

cloneNode Method
    Copies a reference to the object from the document hierarchy.
Syntax
    oClone = object.cloneNode([bCloneChildren])
Parameters
    bCloneChildren	Optional. Boolean that specifies one of the following values:
    FALSE
       Cloned objects do not include childNodes.
    TRUE
       Cloned objects include childNodes.
Return Value
     Returns a reference to the newly created node.
Remarks
     The cloneNode method copies an object, attributes, and, if specified, the childNodes.
     When you refer to the ID of a cloned element, a collection is returned.
    cloneNodedoes not work on an IFRAME directly. You must call cloneNodethrough the
    all collection.


看完后估计都很失望,没任何迹象。。。
再来看下另外一种写法:

<script type="text/javascript">
     var originalInput = $('myinput');
	 originalInput.onfocus = function(){$D.addClass(this,'focus');};
	 originalInput.onblur = function(){$D.removeClass(this,'focus');};
	 var clonedInput = originalInput.cloneNode(true);//deep copy
	 clonedInput.removeAttribute('id');//remove id
	 document.body.appendChild(clonedInput);
</script>


这种写法不会有问题,事件触发得都很正常。
根据MSDN的解释,深度复制会复制所有子结点,这里直接写originalInput.onfocus = …, 这时的onfucs已经算是originalInput的一个属性了(注:FF并非如此),所以可以正常复制。至于这2种事件绑定的差异,这里就不作解释了,自己搜索吧。

看下例1的问题,问题出在$E.on(input,’focus’,function() {$D.addClass(this,’focus’);}); 的this上面。以下是我的理解:看下YUI的源码可知这是通过IE特有的attachEvent方法添加事件的,绑定的方法不会作为input的一个属性来对待,这个方法只是和focus这个事件绑定了,我把它理解为一个引用指向了这个方法而已,在内存保存着。在复制的时候,这个方法不会被复制,但 focus这个事件被复制了,即复制出来的input的focus事件指向了这个方法,这个方法在内存中只存在一份。但这个方法一开始就被创建了,方法里面的this的context是input,它们已经融为一体了,无法改变。在clonedInput触发focus事件了,的确是触发了绑定的事件,但因为方法里面的this是input,而不是clonedInput,所以出现这个怪异的现象。
(注:以上观点只是本人的猜测,也不知是否完全正确,请读者自行判断。请见后面的mootools的说法)

好了,既然知道是因为this指向不对引起的,解决方法也很简单,如下:

<script type="text/javascript">
     var originalInput = $('myinput');
	 $E.on(input,'focus',function(e){
         $D.addClass($E.getTarget(e),'focus');//use $E.getTarget(e) method to get the correct event obj.
         });
	 $E.on(input,'blur',function(e){$D.removeClass($E.getTarget(e),'focus');});
	 var clonedInput = originalInput.cloneNode(true);//deep copy
	 clonedInput.removeAttribute('id');//remove id
	 document.body.appendChild(clonedInput);
</script>


好了,万事OK了。

最后,请大家参考以下mootools的Daniel Steigerwald(mootools有自己的clone方法)的说法:
https://mootools.lighthouseapp.com/projects/2706/tickets/332-moo-element-clone-patch-fix

jQuery explanation on IE issue:
    IE copies events bound via attachEvent when using cloneNode.
    Calling detachEvent on the clone will also remove the events from
    the orignal. In order to get around this, we use innerHTML. Unfortunately,
    this means some modifications to attributes in IE that are actually only stored as
    properties will not be copied (such as the the name attribute on an input).

clone: function(contents, keepid) {
	    var clone = this.cloneNode(!!contents);
	    function cleanAndFix(cloned, orig) {
	        cloned.uid = null;
	        if (!keepid) cloned.removeAttribute('id');
	        if (Browser.Engine.trident) {
	            var shallowClone = orig.cloneNode(false);
	            cloned.clearAttributes();//关键是这2步
	            cloned.mergeAttributes(shallowClone);//关键是这2步
	        }
	        return cloned;
	    }
	    if (contents) {
	        var cEls = clone.getElementsByTagName('*'),
                tEls = Browser.Engine.trident && this.getElementsByTagName('*');
	        for (var i = cEls.length; i--; ) cleanAndFix(cEls[i], tEls && tEls[i]);
	    }
	    return $(cleanAndFix(clone, this));
}


以前用过mootools的这个方法,一直没发现原来里面有这么多的玄机,可见写代码库是一件多么不容易的事情啊,对他们表示由衷的敬佩!
0
0
分享到:
评论

相关推荐

    IE下使用cloneNode注意事项分享

    在IE浏览器中,特别是IE8及以下版本,克隆一个包含`script`节点的节点时,`script`的脚本内容可能被再次执行。这可能会导致代码冲突、性能问题,甚至可能引发错误。这种情况具体分为两种情况: 1. 直接克隆`script`...

    javascript dom操作之cloneNode文本节点克隆使用技巧

    在JavaScript中,DOM(文档对象模型)操作是实现网页动态交互的基础,而`cloneNode`方法是DOM操作中用于克隆节点的一个重要函数。了解`cloneNode`以及它在克隆文本节点时的使用技巧,对于进行DOM操作的前端开发者来...

    javaScript面试题

    JavaScript 的 `typeof` 操作符可以返回一个变量的数据类型,包括 `string`, `boolean`, `number`, `undefined`, `function`, `object` 和 `symbol`(ES6新增)。需要注意的是,`null` 的类型也是 `object`,这是一...

    JavaScript王者归来part.1 总数2

     10.5.3 构造新的文法--一个在JSVM中实现JSVM2解析器的例子   10.6 高级用法   10.7 用正则表达式处理文本   10.7.1 创建一个计价公式编辑器   10.7.1.1 需求分析--什么是计价公式编辑器   10.7.1.2 系统...

    javascript兼容性总结 转.doc

    五、BOM(浏览器对象模型)1.window.location【分析说明】在 IE 中,`window.location` 可以被赋值为一个 URL 字符串,但在 Firefox 中需要使用 `window.location.href`。 ```javascript // IE window.location = '...

    JavaScript知识点个人总结

    在JavaScript中,DOM(Document Object Model)是一种标准的表示HTML和XML文档的接口,它允许程序和脚本动态更新、添加、删除以及遍历文档结构。DOM的核心是节点树,每个节点都有自己的类型和特性。这里我们将深入...

    Javascript操作XML和HTML

    在示例中,创建了一个XML字符串,并通过JavaScript将其转换为DOM对象,然后使用各种属性和方法来访问和操作DOM树。 - `root.xml`:获取并显示整个根元素的XML文本。 - `root.text`:获取并显示根元素及其子元素的...

    JavaScript_study

    - **cloneNode(deep)**:复制一个节点及其所有子节点。 - **hasChildNodes()**:判断当前节点是否包含子节点。 - **insertBefore(new, ref)**:将一个新节点插入到另一个指定节点之前。 - **removeChild(old)**:...

    一些高性能的Javascript代码.doc

    当我们需要连续添加大量DOM元素时,创建一个DocumentFragment并在最后一次性将其添加到页面上,可以显著提升性能。这是因为DocumentFragment是一个临时的内存结构,不会引起浏览器的即时渲染。在IE和Firefox下,...

    JavaScript执行效率优化及内存管理优化.docx

    在JavaScript中,频繁的字符串拼接会导致性能下降,尤其是IE浏览器。使用Array来存储部分字符串,然后join()合并,可以显著提高效率。 优化前: ```javascript var str = ''; for (var i = 0; i ; i++) { str += '...

    JavaScript执行效率优化与内存管理优化.pdf

    在需要连续添加多个DOM元素时,先将它们添加到`DocumentFragment`对象,最后一次性将`DocumentFragment`添加到文档中。这种方法减少了浏览器重新渲染页面的次数,从而提高性能。例如,当添加1000个元素时,性能可...

    javascript操作XML与HTML

    接下来,我们来看一个简单的示例,用于演示如何使用JavaScript操作XML数据。 ```html &lt;title&gt;JavaScript 操作 XML 示例 &lt;script language="javascript"&gt; function test() { // 创建 DOM 对象 var xmlDoc = ...

    JavaScript Table行定位效果

    第一个问题是fixed的tr在ie7中不能进行定位,而且td在定位后并不能保持在表格中的布局,这样在原表格插tr就没意义了。 ps:fixed的相关应用可参考仿LightBox效果。 最后我用的方法是新建一个table,并把源tr克隆到...

    javascript-cheat-sheet-v1

    - **cloneNode(deep)**: 复制一个节点。 - **createTextRange()**: 创建一个 TextRange 对象。 - **detachEvent(eventType, listener)**: 移除事件监听器(IE)。 - **dispatchEvent(event)**: 触发事件。 - **...

    JavaScript实现清空(重置)文件类型INPUT元素值的方法

    如果这种方法失败(例如,在老版本的IE浏览器中),则可以尝试创建一个新的表单,对这个新表单进行重置,然后再将文件输入元素放回原来的位置。最后,如果这些方法都无法实现或者遇到了其他复杂情况,可以考虑使用...

    javascript下有关dom以及xml节点访问兼容问题

    在Web开发中,浏览器的兼容性问题一直是一个不容忽视的话题。不同的浏览器内核(如IE的Trident、Chrome的Blink、Firefox的Gecko等)对标准的支持程度不一,特别是对于早期的DOM(文档对象模型)操作和XML处理方面,...

    用javascript操作xml方法与技巧

    在Web开发中,XML (Extensible Markup Language) 是一种非常重要的数据交换格式。通过使用JavaScript来操作XML文档,可以实现动态网页的功能,并且能够更好地处理来自服务器的数据。本文将详细介绍如何使用...

    javascript中的nextSibling使用陷(da)阱(keng)

    在JavaScript中,DOM树的节点关系和遍历是开发者经常会使用到的功能,而`nextSibling`属性则是其中经常使用到的属性之一。`nextSibling`属性会返回指定节点的下一个兄弟节点。不过,它的行为在不同浏览器中存在一些...

    js解析XML常用对象、属性、方法

    - `insertBefore(newNode, existingNode)`: 在指定的现有节点之前插入一个新节点。 - `normalize()`: 合并相邻的文本节点,并规范化空白节点。 - `removeChild(node)`: 移除当前节点的一个子节点。 - `replaceChild...

Global site tag (gtag.js) - Google Analytics