2010-04-26 37 views
4

如何创建一个纯JavaScript(不使用任何库)插件,它看起来像:JavaScript的插件创建

document.getElementById('id').myPlugin(); 

像jQuery?

+0

值得注意的是你建议的语法是不是在所有*像jQuery *并有很好的理由,其中一些fredrik详细阐述了 – 2010-04-26 09:06:12

回答

2

您可以创建自己的包装(类似于jQuery),这样做可以避免直接扩展DOM所讨论的所有问题。

myWrapper = (function(){ 

    function NodeList(elems) { 

     this.length = 0; 
     this.merge(this, elems.nodeType ? [elems] : elems); 

    } 

    function myWrapper(elems) { 
     return new NodeList(elems); 
    } 

    myWrapper.NodeList = NodeList; 

    NodeList.prototype = { 
     merge: function(first, second) { 

      var i = first.length, j = 0; 

      for (var l = second.length; j < l; ++j) { 
       first[i++] = second[j]; 
      } 

      first.length = i; 

      return first; 

     }, 
     each: function(fn) { 

      for (var i = -1, l = this.length; ++i < l;) { 
       fn.call(this[i], this[i], i, l, this); 
      } 

      return this; 

     } 
    }; 

    return myWrapper; 

})(); 

,你可以添加你自己的方法,像这样:

myWrapper.NodeList.prototype.myPlugin = function() { 
    return this.each(function(){ 
     // Do something with 'this' (the element) 
    }); 
}; 

用法:

myWrapper(document.getElementById('id')).myPlugin(); 
0

为什么使用这种格式?我认为

myPlugin(document.getElementById('id')) 

可能会更清晰的维护代码的任何人。我不是monkey patching的粉丝。

1

我同意spender。你应该不会搞乱标准的JavaScript元素。最好为它做一个包装(也就是说,像jQuery使用的$)。如果您想简化获取元素,请使用包装器方法并扩展该方法。这将使代码更易于维护。因为如果您修改JavaScript中的标准功能,它可能会干扰标准行为。这可能会导致一些非常困难的调试。最好做一个包装函数,做任何你喜欢的事情。

尽管如此,如果您想要标准化行为,您总是可以使用原型将新方法绑定到标准对象。例如:

Object.prototype.myMethod = function() {} 
3

我毫不犹豫的说你不能。毕竟,Prototype.js确实如此。

为了能够呼叫getElementById('id').someNewMethod(),您将不得不'扩展'getElementById返回类型的原型,这是一个Element。在一些浏览器中,你确实可以这样做:

Element.prototype.someNewMethod= function() { 
    alert('hello from a '+this.tagName); 
}; 

document.body.someNewMethod(); // hello from a BODY 

但是,这是相当有问题的。对原生JavaScript对象(如ObjectString)进行原型化可能会有点不方便,浏览器和库之间会发生名称冲突,但Element和所有其他DOM对象可能是“主机”对象,这些对象不允许进行原型设计。

即使DOM对象是一个完整的原生JavaScript接口来实现的,没有规范指出Element必须叫Element一个window属性/全局变量下露出原型/构造函数。

事实上,这在Firefox,Webkit和Opera以及从版本8开始的IE中起作用。然而,它没有标准化,并非所有的浏览器都可以使用所有相同的名称来提供所有相同的接口,并且它不适用于IE6,IE7或许多较小的浏览器(例如移动浏览器)。

原型对这些浏览器有一个回退:当第一次看到每个元素时,它会试图用新成员来增加每个Element的实例。但是这种副作用非常混乱,许多人认为这是一个错误; Prototype 2.0 won't try to extend DOM interfaces以上。

也许将来有人会把它绑定下来,并使其成为浏览器环境的可靠部分。但是今天情况并非如此,所以你应该继续使用其他更笨拙的方法,比如包装函数。

+0

好的答案。但出于好奇,不应该使用一些真正的恶意JavaScript代码来伪造它。首先保存原始的getElements并覆盖它?真正可怕的解决方案,但应该工作。 :) – fredrik 2010-04-26 09:11:54

+1

是的,你可以:你基本上会在你自己的重新实现中包装整个DOM。问题在于(a)它会很慢,并且(b)很多DOM依赖于属性而不是方法:例如。 'document.body.firstChild'完全不做任何方法调用。在ECMAScript第五版之前,你无法在JavaScript中定义自己的属性getter/setters,所以你不能拥有跨浏览器的动态属性,甚至不能模拟NodeList/array的*属性。 – bobince 2010-04-26 09:41:58

+1

因此,无论是在启动时还是每次文档修改时,您都必须填写所有链接的“firstChild”和“nextSibling”和“parentNode”以及整个DOM的所有其他属性(eek !),或者你必须改变接口,例如。通过要求用户编写'document.getBody()。getFirstChild()'。但是如果你改变了界面,那么无论如何你都会失去原生DOM的优势,所以你不妨只是想出自己的界面(比如jQuery等)。 – bobince 2010-04-26 09:44:02