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

How do I get the attached element from the elements attached plugin data method?

我正在编写一个 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');

不幸的是,由于 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();

作者显然打算在所有匹配 .c 的元素上使用您的 example 函数,但是 data 函数只会 return 您的数据对象 第一个 个元素,用 option: 1 初始化(这就是 jQuery 访问器的一般工作方式:在集合中的所有元素上设置集合,获取只获取从集合中的第一个元素开始)。创建数据对象时,您无能为力。

相反,插件应该假设它会被各种不同的集合调用,并在每种情况下处理该集合中每个元素的特定信息。

要做到这一点,请遵循既定的模式使您的插件函数既是初始化程序(接受带有选项的对象)又是方法分派(接受带有命令名称):

$(".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 使用您的方法和对集合的引用来响应没有选项的调用:

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

然后,这些方法将使用 this.elements 来获取要执行的元素。我不会做一个完整的例子,但如果你喜欢那种语法,改编它是相当简单的。