如何从元素附加插件数据方法中获取附加元素?

时间:2018-06-22 16:10:34

标签: jquery jquery-plugins

我正在编写一个jquery插件,我一直试图找出如何从中调用当前方法执行的元素。

这是我正在做的基本版本。

我有一些表单输入:

<input class="myInput" id="txtInput1" type="text" />
<input class="myInput" id="txtInput2" type="text" />
<input class="myInput" id="txtInput3" type="text" />

我有这个插件:

(function($) {
    $.fn.myplugin=function(options) {
        options=$.extend({
            opt1: 'val1',
            etc: ''
        }, options);

        function example() {
            // 'this' in here is the data-myplugin value of the element that called this method.

            // ---------------------------------------------------------
            //
            // How do I determine which element is calling this method ?
            //
            // eg: in this example how do I know it is the $('#input2') element ?  
            //
            // ---------------------------------------------------------
        }

        this.each(function() {            

            // in this example -- loops through each of the form input elements
            // .. manipulate the DOM

        }).data('myplugin', { 
            // .. adds data-myplugin to each of the form elements in the loop with a value that is our plugin object which contains our example() method and options
            example: example,            
            options: options
        });

        return this;
    }
})(jQuery);

我以如下方式实例化插件:

$('.myInput').myplugin();

我这样调用example()插件方法:

$('#input2').data('myplugin').example();

我试图避免将其作为参数传递,例如:

// I don't want to have to do this if I don't have to:
$('#input2').data('myplugin').example('input2');

1 个答案:

答案 0 :(得分:1)

不幸的是,由于jQuery基于集合的性质,因此该设计存在很大问题,这恰恰导致了您所遇到的问题(这就是为什么您看不到它使用太多的原因)。考虑一下:

<div id="first"  class="a c"></div>
<div id="second" class="b c"></div>

然后输入代码:

$(".a").myplugin({option: 1});
$(".b").myplugin({option: 2});
$(".c").data("myplugin").example();

作者显然打算在与example匹配的所有元素上使用.c函数,但是data函数只会返回 first 的数据对象。这些元素的em>,用option: 1初始化(这通常是jQuery的访问器的工作方式:在集合中的所有元素上设置集合,仅从集合中的第一个元素获取)。创建可解决此问题的数据对象时,您无能为力。

相反,插件应该假定它将针对各种不同的集合而被调用,并且在每种情况下都应使用该集合中每个元素特有的信息。

要做到这一点,请遵循一种完善的模式,使您的插件既具有初始化程序(接受带有选项的对象),又具有方法 (接受带有命令名的字符串): / p>

$(".a").myplugin({option: 1});
$(".b").myplugin({option: 2});
$(".c").myplugin("example");

现在,在myplugin内,您可以愉快地遍历".c"集并使用存储在其中的每个元素的选项,这些选项会有所不同(有些是option: 1,有些则是是option: 2)。

这是执行上述操作的简单但完整的示例(请参见注释):

(function($) {
    // A map of our methods
    var methods = Object.create(null);

    // Default options
    var defaultOptions = {
        color: "red",
        fontSize: "16px"
    };

    // Methods

    methods.color = function color(set, args) {
        // Loop over the elements, using the options specific to each element
        // Return the set for chaining
        return set.each(function() {
            var info = methodEntry(this);
            info.$element.css("color", info.options.color);
        });
    };

    methods.fontSize = function fontSize(set, args) {
        return set.each(function() {
            var info = methodEntry(this);
            info.$element.css("font-size", info.options.fontSize);
        });
    };

    methods.getColor = function getColor(set, args) {
        // Getters only access the first element...
        var info = methodEntry(set[0]);
        // ...and return something other than the set
        return info.options.color;
    }

    // init
    
    function init(set, args) {
        return set.data("myplugin", $.extend({}, defaultOptions, args[0]));
    }

    // plumbing

    function methodEntry(element) {
        var $element = $(element);
        var options = $element.data("myplugin");
        if (!options) {
            throw new Error("myplugin not initialized for element");
        }
        return {$element: $element, options: options};
    }

    // Plugin function

    $.fn.myplugin = function(methodName) {
        var isMethodCall = typeof methodName === "string";
        var args = Array.prototype.slice.call(arguments, isMethodCall ? 1 : 0);
        var method = isMethodCall ? methods[methodName] : init;
        if (!method) {
            throw new Error("myplugin has no method called '" + arg + "'");
        }
        return method(this, args);
    };
})(jQuery);

// Using it
$(".a").myplugin({color: "green"});
$(".b").myplugin({color: "blue", fontSize: "20px"});
$(".c").myplugin("color").myplugin("fontSize"); // Note chainging works
console.log($(".c").myplugin("getColor"));      // "green" because the *first* element's setting is green
<div id="first"  class="a c">first</div>
<div id="second" class="b c">second</div>

<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>

或者,您可以使用myplugin()本身来代替data("myplugin")做相同的事情:

$(".a").myplugin({option: 1});
$(".b").myplugin({option: 2});
$(".c").myplugin().example();

您将myplugin通过不带选项的调用来响应,方法是返回一个对象,该对象上带有您的方法,并带有一个引用集以调用该方法:

return {
    elements: this,
    example: ...
}

然后,这些方法将使用this.elements来使元素起作用。我不会编写完整的示例,但是如果您喜欢该语法,则可以很容易地对其进行修改。

相关问题