Javascript 有没有更好的方式/模式来编写这个jQuery插件?

Javascript 有没有更好的方式/模式来编写这个jQuery插件?,javascript,jquery,design-patterns,jquery-plugins,Javascript,Jquery,Design Patterns,Jquery Plugins,我有一个相当复杂的搜索插件:它有不同版本的UI和功能,还有一堆相互依赖的组件。该插件的多个实例将同时存在于一个页面上 我使用的是基本的jQuery创作模式: 为了保存选项、相互依赖的事件和跨多个对象的各种dom查找,我将把相关元素传递给每个函数,并将状态/选项/相互依赖性存储在我每次检索的数据属性中。它可以工作,并防止事件发生冲突,但它似乎是一种混乱的代码编写方式 跨多个实例存储状态的最佳方法是什么?我这样做是不是太过分了,我错过了什么?这可能源于我对在jQuery插件模式中创建类对象的误解 (

我有一个相当复杂的搜索插件:它有不同版本的UI和功能,还有一堆相互依赖的组件。该插件的多个实例将同时存在于一个页面上

我使用的是基本的jQuery创作模式:

为了保存选项、相互依赖的事件和跨多个对象的各种dom查找,我将把相关元素传递给每个函数,并将状态/选项/相互依赖性存储在我每次检索的数据属性中。它可以工作,并防止事件发生冲突,但它似乎是一种混乱的代码编写方式

跨多个实例存储状态的最佳方法是什么?我这样做是不是太过分了,我错过了什么?这可能源于我对在jQuery插件模式中创建类对象的误解

(function($) {
var _options = {};

var methods = {
    init: function(options) {
        return this.each(function() {
            if (options) {
                _options = $.extend($.fn.examplePlugin.defaults, options);
            } else {
                _options = $.fn.examplePlugin.defaults;
            }
            $this = $(this);
            var data = $this.data('examplePlugin');
            if (!data) {

                $this.data('examplePlugin', {
                    target: $this
                });
                $.each(_options, function(key, value){
                    $this.data('examplePlugin')[key] = value;
                });
                data = $this.data('examplePlugin');
            }
            //Cache dom fragment plugin is in (if passed)
            if (data.domContextSelector == null || data.domContextSelector == "") {
                data.domContext = $(body);
            } else {
                data.domContext = $(data.domContextSelector);
            }
            init($this);
        });
    }
};
var init = function(element) {
    data = getData(element);
    //Storing dom elements to avoid lookups
    data.relatedElement = $(data.relatedElementSelector, data.domContext);
    element.click(function(event){
        doSomethingCool($(event.currentTarget));
    });
};
var doSomethingCool = function(element) {
    data = getData(element);
    element.slideUp();
    data.relatedElement.slideDown();
};
var adjustHeight = function(element) {
    data = getData(element);
    element.height(data.relatedElement.height());
};
var getData = function(element) {
    return $(element).data('examplePlugin');
};

$.fn.examplePlugin = function(method) {
    if (methods[method]) {
        return methods[method].apply(this, Array.prototype.slice.call(arguments, 1));
    } 
    else if (typeof method === 'object' || !method) {
        return methods.init.apply(this, arguments);
    } 
    else {
        $.error('Method ' + method + ' does not exist on jQuery.examplePlugin');
    }
    return false;
};
$.fn.examplePlugin.defaults = {
    defaultA: 'something',
    relatedElementSelector: '#related',
    domContextSelector: 'header.header'
};})(jQuery);

我在检查我的插件如何保存状态时发现了您的推文,同时学习了本教程中的插件开发:

在这堂课中,我们将深入研究jQuery插件开发。 在此过程中,我们将回顾各种用于 为用户提供最高级别的灵活性 插件


是的,如果您遵循jQuery指南,那么您是根据它应该如何构建并利用它的设计功能(特别是链接)来构建它的

然而,我不一定要走这条路。有很多方法可以实现这些插件,他们为jQuery插件制作了一个样板,这些插件不是基于jQuery的设计,而是基于OOP视角(我更喜欢)。我认为它更干净,但是牺牲了不遵循通常的语法(
元素.myPlugin({options})
和不能链接(直到您修改一点)

同一个人有一篇较老的帖子,这是通常jQuery插件设计的样板。

我个人建议,在插件设计模式方面。它有助于保持一致性,并使您的插件更加社区友好

话虽如此

我遇到了试图保持多个元素状态的问题。我找到的一个解决方案是使用(看起来像:
$(选择器).data(键,值)
)来保持元信息,如元素状态或应用程序状态

使用data()的好处在于,它不是更新/访问DOM,而是使用jQuery的内部元数据,因此它的访问速度比试图存储信息隐藏的输入字段、更改类名或使用开发人员尝试在客户端存储数据的其他鬼把戏要快。(请记住,使用数据API不需要使用HTML5 doctype,但如果需要的话!)

当所有元素都有自己的状态,但当前元素是控制整个插件状态的元素时,这就变得很棘手了。对于这种情况,我使用body标签来存储关于当前元素的数据,类似这样:

    $('body').data('myPluginNameSpace.current', selectorRef );
这样,当我需要检查我的插件/页面/应用程序的状态,或者监听弹出到文档对象的插件特定事件时,我可以快速查找当前/所选元素,并对其应用任何UI更改或行为:

    var currentElementRef = $('body').data('myPluginNameSpace.current');
    doFunStuff( currElementRef );
还有很多其他方法可以做到这一点,例如:

当自定义事件被触发并随后通过回调函数处理时,自定义参数将附加到传递给处理程序的事件对象:

   $( document ).on( 'customEvent.myPluginNameSpace', function( e ){
      doStuff( e.myProp ); //you can access your custom properties attach to the event
    });
您可以通过许多不同的道路到达同一目的地;这就是JavaScript的美妙之处和恐怖之处。

在您的特定情况下,请记住,您不必在
中运行所有内容。插件的methods.init函数的每个({})
部分:

例如,除非您为每个元素设置特定的选项,否则我将取出为每个元素扩展选项对象的部分

var methods = {
    init: function(options) {
        //DO OPTIONS/EVENTLISTENER/etc STUFF OUT HERE
        return this.each(function() {
            //DONT DO THIS
            if (options) {
                _options = $.extend($.fn.examplePlugin.defaults, options);
            } else {
                _options = $.fn.examplePlugin.defaults;
            }
请尝试以下方法:

...
    var methods = {

        init : function( options ){

          //do setup type stuff for the entire Plugin out here
          var _options = $.MyPlugin.options = $.extend( defaults, options );

          //add some listeners to $(document) that will later be handled               
          //but put them in an external function to keep things organized:
          //methods.addListeners() 

          //this refers to the array of elements returned by $(selector).myPlugin();
          //this.each() iterates over, EACH element, and does everything inside (similar to Array.map())
          //if the selector has 100 elements youre gonna do whats in here 100 times
          return this.each(function(){
            //do function calls for individual elements here        
          });

        },

此外,利用自定义事件也会对您有所帮助!向文档对象添加一些事件侦听器,并让事件处理程序使用数据API或自定义事件参数确定要与哪个元素交互。

问题应该转到代码审阅。我喜欢他的模式,但不知道它如何跨多个in添加任何状态维护立场。我想你每次都必须从“plugin”对象中提取它?这很简单。根据最初的插件指南,不是用javascript存储对象内部的状态,而是使用jQuery的
.data()以“每个受影响的元素”为基础存储它
。每次您想要获取插件下元素的状态,只需从元素中检索数据,使用它,然后将其存储回。这基本上就像在DOM中的元素中存储JS数据。看起来您的操作更像python风格,定义了“self=this”每次,就像我抓取元素一样。看起来使用“this”是正确的方法。
...
    var methods = {

        init : function( options ){

          //do setup type stuff for the entire Plugin out here
          var _options = $.MyPlugin.options = $.extend( defaults, options );

          //add some listeners to $(document) that will later be handled               
          //but put them in an external function to keep things organized:
          //methods.addListeners() 

          //this refers to the array of elements returned by $(selector).myPlugin();
          //this.each() iterates over, EACH element, and does everything inside (similar to Array.map())
          //if the selector has 100 elements youre gonna do whats in here 100 times
          return this.each(function(){
            //do function calls for individual elements here        
          });

        },