返回jQuery插件中的正确元素

问题描述:

我正在将库转换为jQuery插件以使其更容易初始化。这个想法是,插件的行为有所不同,取决于它所运行的元素的类型。返回jQuery插件中的正确元素

如果元素是一个<p>然后我正确初始化。但是,如果元素是另一个块元素,我会在其前面加上<p>。如果元素是内联元素,则需要从列表中删除。这工作得很好,数据被附加到适当的元素(<p>)。对于连锁能力,我想每次都返回<p>

如果我从$('p').Plugin({...data...})开始,它确实会保留<p>。但是,如果我以$('div).Plugin({...data...})开始链接,则返回<div>。这是必需的,因为插件可能只适用于特定的元素。

这是导致我有些迷茫代码:

(function($) { 
    var methods = { 
     init: function(options) { 
     // Maintain chainability 
      return this.each(function() { 
       var me; 
       if($(this).prop('tagName') != 'P') 
       { $(this).append('<p></p>'); 
        me = $(this).children('p'); 
       } 
       else me = $(p); 
      // The following 2 lines error (I was desperate) 
       $(this) = me; 
       this = me; 
      // The following line does nothing (that I can tell) 
       return me; 
      }); 
     }, 
     ... other methods ... 
    }; 
    $.fn.Plugin = function (method) { 
     if (methods[method]) { 
      return methods[method].apply(this, Array.prototype.slice.call(arguments, 1)); 
     } else if (typeof method === 'object' || !method) { 
     // Run Init 
      return methods.init.apply(this, arguments); 
     } else { 
      $.error('Method ' + method + ' does not exist on jQuery Plugin'); 
     } 
    }; 
} 
(jQuery)); 

我也曾尝试初始化函数中重新创建列表,以便它只抓住新创建<p>秒。有没有人有一个有效的工作建议来引导我走向正确的方向?

注意:我知道上面的代码可以更有效率......为了解决这个问题,为了清晰起见,我们将其分解。

this.each的回报始终为this,这是不可修改的,在您的情况下是您调用.Plugin()的所选元素的列表。在你的情况下,你不想简单地返回被选择的元素列表...但是改变了列表。 (你是100%正确的,你在.each循环内的返回没有做任何事情来影响返回this.each本身。)

如果你在this.each循环之外定义你的变量来收集你的新dom列表元素,add循环内部正确的dom元素(见注1),然后返回循环外部的新元素列表,你会看到你想要的结果。但是,这里有几个陷阱。

注1:我们使用this.each进行插件处理的原因是因为选择器可以返回多个元素。您需要收集一个新的元素列表,因为您基本上要返回一个不同于选择器的元素集合,只要包含非-p标签即可。要考虑的情况是$('div.myDiv, p.myP').Plugin(),它选择具有不同标签类型的多个元素。

其中一个主要问题是,我们经常在我们选择的元素上设置样式,或者甚至使用id来帮助识别插件所连接的dom元素。通过改变作为插件根部的dom元素,需要解决或者至少需要考虑的css或id的位置可能存在很多问题。

(我并不是说它无法完成,特别是如果您只是将已在使用的内容转换为与其他人共同使用的插件 - 只是会带来很多棘手的问题。 )

(function($) { 
    var methods = { 
     init: function(options) { 
      var mes; 
      this.each(function() { 
       var me; 
       if($(this).prop('tagName') != 'P') 
       { $(this).append('<p></p>'); 
        me = $(this).children('p'); 
       } 
       else me = $(p); 
      } 
      mes.push(me); 
      return mes; 
     }, 
     ... other methods ... 
    }; 
    $.fn.Plugin = function (method) { 
     if (methods[method]) { 
      return methods[method].apply(this, Array.prototype.slice.call(arguments, 1)); 
     } else if (typeof method === 'object' || !method) { 
     // Run Init 
      return methods.init.apply(this, arguments); 
     } else { 
      $.error('Method ' + method + ' does not exist on jQuery Plugin'); 
     } 
    }; 
} 
(jQuery)); 
+0

我确实碰巧解决了这个问题。谈到你的笔记,我当然明白涉及到棘手的问题。这个插件根本不修改根元素。此外,它创建的元素的性质是它们是非常临时的动画。现在我已经提出了3个解决方案......我不得不在外面回想这个。每个盒子 – 2013-03-15 14:56:34

+0

由于您的解决方案当然是我想出的解决方案之一,您应该得到“接受的答案”。之后我也会补充我自己的答案。 – 2013-03-15 15:06:51

+0

谢谢,我感谢澄清。我相信我对你现在正在做的事情有一些了解。祝你好运,我期待着看到你的完整解决方案。 – purgatory101 2013-03-15 15:10:34

如前所述purgatory101,这里有真正的两个问题。首先要明白$().each()有它自己的返回值。其次是可链接性。克服$().each()的返回值相当简单。一个只需要提供一个不同的$().each()或jQuery对象数组。可链接性归结于您/您的用户需要/期望的内容。

jQuery和Chainability

由于对$().each()是如何经常使用的性质,大多数人认为这些chainability指的是返回原来的jQuery对象。但是,jQuery内核中有几种情况可能会由不同的元素继承链。这一切都归结为最有可能使用您的插件。下面是两种最常见的链,jQuery使用:

实施例1:面向结果的链接(ROL)

.add()允许链从结果继续,而不是从原点。假设是用户需要修改他们新添加的元素。更常见的例子是.parent().children(),虽然这些都是不言自明的,自然的期望是,人们会想要使用适当命名的元素。

实施例2:面向来源链接(OOL)

.append()返回原来的对象。这是与.add()直接对应的,它完成了类似的结果,但返回了不同的值。这是大多数数据,样式和元素更改方法所使用的。

OOL解决方案

由于插件往往有很多方法,它能够链的方法是很重要的。在OOL中,解决方案提出了一个程序,每次都会持续生成一组子代码<p>。这是像这样做:

(function($) { 
// Search function 
    var findP = function(obj) { 
     // ... Search function for your <p> in THIS object 
     return p; 
    }; 
    var methods = { 
     init: function(options) { 
     // Maintain chainability 
      return this.each(function() { 
       var me; 
       if($(this).prop('tagName') != 'P') 
       { $(this).append('<p></p>'); 
        me = $(this).children('p'); 
       } 
       else me = $(p); 

       // ... other functionality... 
      }); 
     }, 
     other1: function() { 
      var searchMe = findP; 
      return this.each(function() { 
       var me = searchMe($(this)); 
      }); 
     } 
    }; 
    $.fn.Plugin = function (method) { 
     ... Route to method ... 
    }; 
} 
(jQuery)); 

问题本是起源对象可能已经在方法调用之间改变,使他们可能不存在的机会,必须考虑。这是一个更多的处理器密集型,但可能更安全,适合预期的行为。

ROL解决方案(S)

ROLS只应如果结果要马上行动上使用。这与jQuery的.add,.children.parent一样。有几种方法可以实现这一点。这里的担忧是,虽然这可能以多种方式完成,但purgatory101的解决方案是最安全的。必须提到它,因为使用不同的$()列表的快捷方式可能很有吸引力,但有抓住你不想采取行动的元素的危险。

var methods = { 
     init: function(options) { 
     // Option 1) Build new list 
      return newlist.each(function() { 
       var me; 
       if($(this).prop('tagName') != 'P') 
       { $(this).append('<p></p>'); 
        me = $(this).children('p'); 
       } 
       else me = $(p); 

       // ... other functionality... 
      }); 
     }, 
     // ... other methods ... 
    }; 
    $.fn.Plugin = function (method) { 
     if (methods[method]) { 
      return methods[method].apply(this, Array.prototype.slice.call(arguments, 1)); 
     } else if (typeof method === 'object' || !method) { 
     // ... OR Option 2) build new list ... 
      return methods.init.apply(newlist, arguments); 
     } else { 
      $.error('Method ' + method + ' does not exist on jQuery Plugin'); 
     }    
    }; 

应该指出,我不确定两种选择之间的差异是否存在。