如何以OO方式编写jquery插件

时间:2014-03-11 17:08:36

标签: javascript jquery jquery-plugins

我写了以下jquery插件。我想要做的是,当用户点击链接时,进行相关的div显示:基于数据属性的块。但是这个插件不起作用。在过去的两天里,我试图解决这个问题。但我失败了。

我的HTML

<div class="container1">
    <a href="#" class="link1" data-link="a">asd</a>
    <div class="window1" data-window="a">
           asd         
    </div>
</div>

<hr>

<div class="container2">
    <a href="#" class="link2" data-link="b">asdf1</a>
    <a href="#" class="link2" data-link="c">asdf2</a>
    <a href="#" class="link2" data-link="d">asdf3</a>
    <div class="window2" data-window="b">
           asdf1         
    </div>
    <div class="window2" data-window="c">
           asdf2        
    </div>
    <div class="window2" data-window="d">
           asdf3         
    </div>
</div>

<script src="jquery-1.11.0.min.js"></script>
<script src="script.js"></script>

<script>

    $('.container1').myPlugin({
        link: $('.link1'),
        container : $('.window1')
    });
    $('.container2').myPlugin({
        link: $('.link2'),
        container : $('.window2')
    });

</script>

插件

   (function ($, window, document, undefind) {

   MyPlugin = {


    init : function (options, element) {
        $.fn.myPlugin.config = $.extend({}, $.fn.myPlugin.config, options);
        var link = $.fn.myPlugin.config.link;                

        link.on('click', this.secondFunc);
    },

    secondFunc : function () {
        var dataLinkId = $(this).data('link'),
            container = $($.fn.myPlugin.config).filter('[data-section="' + dataLinkId + '"]'); 
        container.show();
    }

};

$.fn.myPlugin = function(options) {
   return this.each(function () {
        var rezG = Object.create(MyPlugin);
        rezG.init(options, this);
    });
}; 

$.fn.myPlugin.config = {
    link: $('.link'),
    container : $('.container')
};

   })(jQuery, window, document);

CSS

.window1, .window2 {
    display: none;
}

DEMO

2 个答案:

答案 0 :(得分:2)

您需要使用var来确保您的变量都是本地变量而不是全局变量。

var MyPlugin = {
    // ...
};

此外,在init函数中,您正在执行此操作:

$.fn.myPlugin.config = $.extend({}, $.fn.myPlugin.config, options);

这是覆盖 $.fn.myPlugin.config,这是默认选项。这意味着调用myPlugin()所有元素将使用相同的配置。您只需要在一个实例上设置配置。

this.config = $.extend({}, $.fn.myPlugin.config, options);

您的secondFunc没有对象(rezG)实例的引用,因此无法访问配置。您需要将其传递给secondFunc()。一种方法是使用闭包来捕获实例。

secondFunc: function (rezG) {
    return function(){
        var dataLinkId = $(this).data('link'),
            container = $(rezG.config.container).filter(function(){
                return $(this).data('window') == dataLinkId;
            });
        container.show();
    };
}

然后你这样绑定它:

link.on('click', this.secondFunc(this));

请注意,在secondFunc中,您需要使用config.container(不仅仅是config作为对象),而且您的属性也是data-window,而不是{{1 }}

更新了演示:http://jsfiddle.net/K82gg/7/

答案 1 :(得分:1)

您的插件可以像

一样简单
(function ($, window, document, undefind) {
$.fn.myPlugin = function(options) {
    // When $(stuff).myPlugin(...) is called
    // this keyword inside of myPlugin function is referencing a set 
    // of elements plugin was called upon
    // e.g. for call like $('.container1').myPlugin();
    // this keyword will reference all elements selected by 
    // $('.container1') not jquery wrapped, 
    // in general it can be a any number.
   return this.each(function pluginImplementation () {
       // Here we iterate over the set, and for each element in the set
       // we do some pretty standard click 
       var container = $(this);
       // I use 'click.myPlugin' event instead just 'click' ale to later on
       // do $(..).off('click.myPlugin') to remove only handlers that were 
       // attached by plugin (a good practice)
       container.on('click.myPlugin', options.linkSelector, function(){               
           var dataLinkId = $(this).data('link');
           container.find('[data-window="' + dataLinkId + '"]').toggle();
       })
   });
};
})(jQuery, window, document);

请参阅jsfiddle

然而,上面的代码可能会在每次迭代时创建一个问题luginImplementation ()函数,如果该函数的主体更复杂,那将是一团糟。这就是为什么最好在外面创建pluginImplementation ()

(function ($, window, document, undefind) {
    // Notice that pluginImplementation () now accepts parameters
    // They make it possible for pluginImplementation to know which
    // elements it's working with

    function pluginImplementation (container, options) {
        container.on('click.myPlugin', options.linkSelector, function(){               
            var dataLinkId = $(this).data('link');
            container.find('[data-window="' + dataLinkId + '"]').toggle();
        })
    }

    $.fn.myPlugin = function(options) {
        return this.each(function () {
            pluginImplementation($(this), options);
        });
    };
})(jQuery, window, document);

demo

这种分离可能不够好。你可能希望你的插件更多OOP而不是。所以你可以像这样去所有的OOPy:

(function ($, window, document, undefind) {
    // For that purpose we create a class
    // That describes behavior that our plugin provides
    // 
    function MyPlugin(container, options) {
        this.container = container;
        this.options = options;

        // To the topic of maintainability 
        // This could be parametrised as an option at plugin instantiation
        this.eventName = 'click.myPlugin';
    }

    MyPlugin.prototype.attachClickHandlers = function() {
        var self = this;
        // This gets a little messy with all the thises vs selfs and a 
        // noname function wrapping the handler.
        // The point is to preserve this keyword reference 
        // inside of clickHandler method.
        // If I would have just self.clickHandler as a handler there
        // this keyword inside of self.clickHandler would reference to 
        // whatever $(...).on binds handlers to i.e. triggering element.
        // I need this keyword inside of self.clickHandler to point to 
        // "current" instance of MyPlugin, that's why I have wrapping 
        // function. It just lets me call clickHandler in the right context.
        // clickHandler method also needs to know what link is being clicked
        // so we pass that in as parameter.
        self.container.on(self.eventName, 
                          self.options.linkSelector, 
                          function() {
            self.clickHandler($(this));
        })
    }

    MyPlugin.prototype.clickHandler = function(clickedLink) {
        var dataLinkId = clickedLink.data('link');
        this.container.find('[data-window="' + dataLinkId + '"]').toggle();
    }

    $.fn.myPlugin = function(options) {
        return this.each(function () {
            var pluginInstance = new MyPlugin($(this), options);
            pluginInstance.attachClickHandlers();
        });
    };        
})(jQuery, window, document);

在此实现中,MyPlugin是一个类(在javascript意义上的单词类),它使您能够以其行为方式处理每个特定点。并介绍各种OOP功能。

demo