#28:构建更复杂的插件

现在我们已经了解了插件开发的基础知识,我们可以更深入地挖掘。因为最终插件是一个函数,它为我们提供了组织所需的范围。还记得我们在学习模板时整理我们的代码吗?我们可以在插件中使用一些相同的概念。

但首先,我认为 jQuery 插件架构可以从一些样板代码中获益。也许您熟悉HTML5 Boilerplate,它提供了一堆智能默认值。jQuery 插件样板是相同类型的东西。节省了一些打字工作,并让您走上一条智能开发的道路。

我偶然发现了一个名为jQuery Boilerplate的项目,我猜想它应该不错。但我还没有深入研究那个。相反,我非常喜欢 Doug Neiner 的Starter。您提供一个名称、一些默认值和一些选择,它将为您生成该样板结构。

我们决定创建一个名为 lodgeSlider 的滑块,并带有一个简单的速度参数,最终得到以下代码

(function($){
    $.lodgeSlider = function(el, options){
        // To avoid scope issues, use 'base' instead of 'this'
        // to reference this class from internal events and functions.
        var base = this;
        
        // Access to jQuery and DOM versions of element
        base.$el = $(el);
        base.el = el;
        
        // Add a reverse reference to the DOM object
        base.$el.data("lodgeSlider", base);
        
        base.init = function(){
            base.options = $.extend({},$.lodgeSlider.defaultOptions, options);
            
            // Put your initialization code here
        };
        
        // Sample Function, Uncomment to use
        // base.functionName = function(paramaters){
        // 
        // };
        
        // Run initializer
        base.init();
    };
    
    $.lodgeSlider.defaultOptions = {
        speed: 300
    };
    
    $.fn.lodgeSlider = function(options){
        return this.each(function(){
            (new $.lodgeSlider(this, options));
        });
    };
    
})(jQuery);

其中很多看起来应该很熟悉。有一个 IIFE 包装插件以确保安全。在 jQuery 对象上创建了一个函数。立即调用了一个名为 init 的函数。在 jQuery 对象上创建了一个方法,该方法返回一个 jQuery 对象。创建了一些变量来缓存我们可能再次使用的引用。大多是我们之前见过的内容。

也许有两件新东西。一个是其中的 options 对象。您可以看到硬编码的 300 值。但也可以看到带有 $.extend() 的行。这是一个 jQuery 函数,用于将两个对象合并为一个,其中一个对象优先于另一个对象。当我们调用插件时,也许像这样

$("#slider-1").lodgeslider();

我们没有传入任何选项,并且该空对象与我们的硬编码对象合并,并且默认值在插件内部可用。但我们也可以这样调用它

$("#slider-1").lodgeslider({
  speed: 500
});

我们在这里将一个对象作为参数传递。该对象与我们的硬编码对象合并,优先于后者,并且我们传递的值成为插件中可用的值。很酷。

另一件新事物是使用 .data() 的那个奇怪的部分。我们创建了 base 变量来引用函数本身,该函数为插件调用的每个元素重新创建。例如,假设我们在 $(".slider") 上调用了插件 - 页面上可能有两个具有类名 slider 的元素。each 循环运行,并且创建了 lodgeSlider 函数的两个实例。在每一个实例中,我们都将对它的引用附加到元素本身。这样,我们可以从我们拥有的该元素的任何引用中调用内部插件方法。

比如也许

$(".the-first-slider").data("lodgeSlider").changeSlide(2);

只是给我们提供了一种在需要时使用插件方法的好方法。

在这次插件构建冒险中,我们并没有取得巨大的进步

查看 CodePen 上 Chris Coyier (@chriscoyier) 的作品 从头开始构建滑块

老实说,世界可能不需要另一个滑块插件。但是,您可以看到它们可能会变得多么复杂。以下是一些想法

  • 可以有回调函数(或自定义事件)用于滑块更改之前和之后、滑块设置之后、滑块拆除之后等。
  • 宽度可以基于百分比,并在浏览器窗口发生变化时重新计算。
  • 导航可以动态构建,而不是在标记中强制要求。
  • ID 和 #hash href 也可以动态创建。
  • 可以添加诸如滑动之类的触摸事件,使滑块更友好(小圆点不友好)。

您执行的这些操作越多,插件的大小就越大。这就是为什么在功能、实用性、性能和大小之间取得平衡如此棘手,并且存在许多最终执行相同操作的不同插件的原因。