jQuery插件的创建和公共方法

4
我已经创建了一个插件,将HTML选择框转换为使用DIV的自定义下拉菜单。

一切正常,但我想让它更好一点。请查看我的jsFiddle

在插件的末尾,我有两个方法,slideDownOptions和slideUpOptions,我希望这些方法可以在插件之外使用,以便其他事件可以触发这些动作。

我开始有点困惑如何做到这一点,更具体地说,如何从插件内部和插件外部调用这些方法。

任何帮助总是受欢迎的。

2个回答

13

考虑使用面向对象的代码重构你的插件。这样可以像jQuery UI API一样为你的插件创建API。这样,您可以访问插件方法,例如:

$('select').customSelect(); // apply plugin to elements
$('select').customSelect('resetOpacity'); // call method resetOpacity();
$('select').customSelect('setOpacity', 0.5); // call method with arguments

创建此类插件的基本模板如下:

// plugin example
(function($){
    // custom select class
    function CustomSelect(item, options) {
        this.options = $.extend({
            foo: 'bar'
        }, options);
        this.item = $(item);
        this.init();
    }
    CustomSelect.prototype = {
        init: function() {
            this.item.css({opacity:0.5});
        },
        resetOpacity: function() {
            this.setOpacity('');
        },
        setOpacity: function(opacity) {
            this.item.css({opacity:opacity});
        }
    }

    // jQuery plugin interface
    $.fn.customSelect = function(opt) {
        // slice arguments to leave only arguments after function name
        var args = Array.prototype.slice.call(arguments, 1);
        return this.each(function() {
            var item = $(this), instance = item.data('CustomSelect');
            if(!instance) {
                // create plugin instance and save it in data
                item.data('CustomSelect', new CustomSelect(this, opt));
            } else {
                // if instance already created call method
                if(typeof opt === 'string') {
                    instance[opt].apply(instance, args);
                }
            }
        });
    }

}(jQuery));

// plugin testing
$('select').customSelect();

这里有一个可用的 JS fiddle: http://jsfiddle.net/XsZ3Z/


1
喜欢这个模板。干得好!虽然Javascript本身不提供受保护的方法和属性,但使用您的模板很容易实现。一种广泛的约定是以下划线“_”开头的方式来定义受保护的方法 - 这很容易实现,以防止从插件外部调用这些方法: // 如果已经创建了实例,则调用方法 if(typeof opt === 'string' && opt.charAt(0) !== '_') { instance[opt].apply(instance, args); } - Liquinaut
这太棒了。喜欢这种方法! - Aaron Lozier

4
你需要重构代码才能使其正常工作。考虑使用jQuery Boilerplate
;(function ( $, window, undefined ) {

  var pluginName = 'convertSelect',
  document = window.document,
  defaults = {
    propertyName: "value"
  };

  function Plugin( element, options ) {
    this.element = element;
    this.options = $.extend( {}, defaults, options) ;

    this._defaults = defaults;
    this._name = pluginName;

    this.init();
  }

  Plugin.prototype = {

    // Private methods start with underscore
    _generateMarkup: function() {

      // you can access 'this' which refers to the constructor
      // so you have access the all the properties an methods
      // of the prototype, for example:
      var o = this.options

    },

    // Public methods
    slideDownOptions: function() { ... }

  }

  $.fn[ pluginName ] = function ( options ) {
    return this.each(function () {
      if (!$.data( this, 'plugin_' + pluginName ) ) {
        $.data( this, 'plugin_' + pluginName, new Plugin( this, options ) );
      }
    });
  };

}(jQuery, window));

然后,您可以这样调用公共方法:
var $select = $('select').convertSelect().data('plugin_convertSelect');
$select.slideDownOptions();

我曾经遇到一个和我的项目类似的问题,最近我不得不重构整个项目,因为我在jQuery名称空间中使用了太多的方法。 jQuery样板很好用,它基于官方jQuery指南,但也有一些变化。如果您想看这种插件模式的实现,请查看https://github.com/elclanrs/jq-idealforms/tree/master/js/src


同意使用jQuery Boilerplate作为起点,但我对我的进行了改进,以允许使用此公共函数(在boilerplate代码末尾进行了非常简单的更改):https://github.com/jquery-boilerplate/jquery-boilerplate/wiki/Extending-jQuery-Boilerplate - jackocnr
再给你一个。在我看来,这是最好的方法。 - Marek Fajkus
使用这种方法,jQuery的链式调用完全失效了。 - Alex G

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接