所有类型节点都会有一个方法就是cloneNode,也就是克隆节点。克隆的操作也是我们常常需要使用的,本来就是一个很简单的接口,但是还是有一些细节问题需要处理。
cloneNode不会复制javascript属性,比如事件,这个方法只会复制特性。当然IE有这个BUG它会复制事件处理程序。cloneNode(a)方法接受一个布尔值参数,表示是否深拷贝。
true:表示执行深拷贝,复制本节点以及整个子节点树。
false:浅拷贝,只复制节点本身。
复制后返回的节点副本属于文档所有,但是并没有父节点。除非使用 appendChild,insertChild(),replaceChild()将它添加到文档。
关于事件的处理
IE旧版会克隆原生的事件,所以我们需要做克隆的时候先移除掉,当然2.1.1版本是不再兼容低级版本了。所以我们考虑的是jQuery体系的处理,因为这里还没有涉及到事件的原理,所以我们暂时先初步理解下,jQuery的事件处理是非常nice的,利用了数据缓存的机制,把数据都缓存在内存中而不直接跟dom元素绑定,这样的好处很多,具体我们在事件交互那一章会超详细讲解。
cloneNode(true)的时候是遍历的节点,但是不会把对应的事件与数据给复制,但是jQuery.clone方法克隆的时候,是会把该节点上的事件与数据给一并复制过去的,这样的机制是建立在数据分离的基础上。简单来说,jQuery在DOM上做了一个uuid的标记,然后把与这个dom相关联的所有数据都放到一个内存区域,通过这个uuid映射,这样我们在深度拷贝 dom 的时候自然也可以把内存的数据给复制一份了,当然这里要注意一个问题,事件是不能被复制的,需要重新绑定了。
因为操作都是跟data_priv与data_user挂钩的所以我模拟的话实现的代码量太大了,这里就直接给大概的流程吧。
首先我们elem.cloneNode(true)直接给这个元素克隆一份,我们要做的就是把克隆后的元素加入事件与数据。
jQuery内部的数据都缓存在data_priv中,包括事件,data_user是提供给用户操作的,用户的数据。
所以就需要把这个2个缓存给找出来然后混入到新的克隆节点中,jQuery都是提供接口data_priv.access,data_priv.set。
值得注意的事件的复制是需要重新jQuery.event.add绑定的,如果节点是有嵌套的话,需要遍历每一个元素节点,在每个节点上都要处理事件与数据。