假设参数els是一个DOM对象。一个功能完备的DOM库应该能处理节点(node)或节点序列(nodelist),但现在我们不作要求。首先遍历需要被添加进的元素 (父元素),再在这个循环中遍历将被添加的元素 (子元素)。
如果将一个子元素添加至多个父元素,需要克隆子元素(避免最后一次操作会移除上一次添加操作)。可是,没必要在初次添加的时候就克隆,只需要在其它循环中克隆就可以了。因此处理如下:
if (i > 0) { childEl = childEl.cloneNode(true); }
变量i来自外层forEach循环:它表示父级元素的序列号。第一个父元素添加的是子元素本身,而其他父元素添加的都是目标子元素的克隆。因为作为参数传入的子元素是未被克隆的,所以,当将单个子元素添加至单个父元素时,所有的节点都是可响应的。
最后,真正的添加元素操作:
parEl.appendChild(childEl);
因此,组合起来,我们得到以下实现:
Dome.prototype.append = function (els) { return this.forEach(function (parEl, i) { els.forEach(function (childEl) { if (i > 0) { childEl = childEl.cloneNode(true); } parEl.appendChild(childEl); }); }); };
prepend方法
我们按照相同的逻辑实现prepend方法,其实也相当简单。
Dome.prototype.prepend = function (els) { return this.forEach(function (parEl, i) { for (var j = els.length -1; j > -1; j--) { childEl = (i > 0) ? els[j].cloneNode(true) : els[j]; parEl.insertBefore(childEl, parEl.firstChild); } }); };
不同点在于添加多个元素时,添加后的顺序会被反转。所以不能采用forEach循环,而是用倒序的for循环代替。同样的,在添加至非第一个父元素时需克隆目标子元素。
第十一步: 删除节点
对于我们最后一个节点的操作方法,从dom中删除这些节点,很简单,只需要:
Dome.prototype.remove = function () { return this.forEach(function (el) { return el.parentNode.removeChild(el); }); };
只需要通过节点的迭代和在他们的父节点调用删除子节点方法。比较好的是这个dom对象依然正常工作(感谢文档对象模型吧)。我们可以在它上面使用我们想使用的方法,包括插入,预插回DOM,很漂亮,不是吗?
第12步:事件处理
最后,却是最重要的一环,我们要写几个事件处理函数。
如你所知,IE8依然使用旧的IE事件,因此我们需要为此作检测。同时,我们也要做好使用DOM 0 级事件的准备。
查看下面的方法,我们稍后会讨论:
Dome.prototype.on = (function () { if (document.addEventListener) { return function (evt, fn) { return this.forEach(function (el) { el.addEventListener(evt, fn, false); }); }; } else if (document.attachEvent) { return function (evt, fn) { return this.forEach(function (el) { el.attachEvent("on" + evt, fn); }); }; } else { return function (evt, fn) { return this.forEach(function (el) { el["on" + evt] = fn; }); }; } }());
在这里,我们用到了立即执行函数(IIFE),在函数内我们做了特性检测。如果document.addEventListener方法存在,我们就使用它;另外我们也检测document.attachEvent,如果没有就使用DOM 0级方法。请注意我们如何从立即执行函数中返回最终函数:其最后会被分配到Dome.prototype.on。在做特性检测时,与每次运行函数时检测相比,这样的方式分配适合的方法更加方便。
事件解绑方法off与on方法类似:.
Dome.prototype.off = (function () { if (document.removeEventListener) { return function (evt, fn) { return this.forEach(function (el) { el.removeEventListener(evt, fn, false); }); }; } else if (document.detachEvent) { return function (evt, fn) { return this.forEach(function (el) { el.detachEvent("on" + evt, fn); }); }; } else { return function (evt, fn) { return this.forEach(function (el) { el["on" + evt] = null; }); }; } }());
您可能感兴趣的文章: