简体   繁体   English

带有原型的jQuery插件

[英]Jquery plugin with prototype

I was trying on the basics of Jquery plugin and the prototype concept, but ended up in an unusual behavior. 我尝试使用Jquery插件的基础知识和原型概念,但最终出现了异常行为。

HTML : HTML:

<div>
    <span>
        <textarea>Text Area with 500 characters. Adding Some text.</textarea>
        <span class="cl"></span>
    </span>
    <span>
        <textarea>Text Area with 100 characters</textarea>
        <span class="cl"></span>
    </span>
</div>

JQuery : jQuery的:

(function ($) {
    var tisCharsLeftCntxt = null;

    function fnCharsLeft(ele, genStngs) {
        this.jqe = $(ele);
        this.maxChars = genStngs.maxChars;
        tisCharsLeftCntxt = this;
        this.fnInit();
    }
    fnCharsLeft.prototype = {
        fnInit: function () {
           tisCharsLeftCntxt.fnUpdateRemainingChars();
            tisCharsLeftCntxt.jqe.keyup(function (event) {
                key = event.keyCode ? event.keyCode : event.which;
                if ((37 != key) && (38 != key) && (39 != key) && (40 != key)) {
                    tisCharsLeftCntxt.fnUpdateRemainingChars();
                }
            });
        },
        fnUpdateRemainingChars: function () {
            var charsLft = tisCharsLeftCntxt.maxChars - tisCharsLeftCntxt.jqe.val().length,
                jqeDestToUpdt = tisCharsLeftCntxt.jqe.siblings('.cl');
            charsLft = (charsLft < 0) ? 0 : charsLft;
            if (charsLft) {
                jqeDestToUpdt.text(charsLft + ' more of ' + tisCharsLeftCntxt.maxChars + ' characters');
            } else {
                tisCharsLeftCntxt.jqe.val(tisCharsLeftCntxt.jqe.val()
                    .substring(0, tisCharsLeftCntxt.maxChars));
                tisCharsLeftCntxt.jqe.scrollTop(tisCharsLeftCntxt.jqe[0].scrollHeight);
                jqeDestToUpdt.text("Maximum limit of " + tisCharsLeftCntxt.maxChars + " characters reached");
                return false;
            }
        }
    };
    $.fn.fnCharsLeftPlgn = function (genStngs) {
        return $(this).data("charsleft", new fnCharsLeft(this, genStngs));
    };
})(window.jQuery);
$('div span:nth-child(1) textarea').fnCharsLeftPlgn({maxChars: 500});
$('div span:nth-child(2) textarea').fnCharsLeftPlgn({maxChars: 100});

Fiddle : http://jsfiddle.net/5UQ4D/ & http://jsfiddle.net/5UQ4D/1/ 小提琴: http : //jsfiddle.net/5UQ4D/&http : //jsfiddle.net/5UQ4D/1/

Requirement is, the plugin should show the number of characters that can be added in a text-area. 要求是,插件应显示可以在文本区域中添加的字符数。 If there is only one text-area in a page this is working good. 如果页面中只有一个文本区域,则效果很好。 But if there are more than one, only the text-area which is last associated with the plugin is working properly. 但是,如果有多个,则只有与插件最后关联的文本区域可以正常工作。

With respect to code here, In both the text-area number of characters left is updated correctly during initialization (only for the first time). 关于此处的代码,在初始化期间,两个文本区域中剩余的字符数都已正确更新(仅第一次)。 But later when the text area content is changed, only the second with 100 chars (or the most recent text-area associated with the plugin) is working properly. 但是稍后,当更改文本区域的内容时,只有第二个100个字符(或与插件关联的最新文本区域)可以正常工作。

Seems like, I'm failing to restrict the plugin context independently to a text-area. 似乎,我无法将插件上下文单独限制为一个文本区域。 Please Advice,.. 请指教,..

Problem 1: 问题一:

As mentioned in the comments, you're creating a variable named tisCharsLeftCntxt outside of the other contexts, then assigning this to it in your constructor. 正如在评论中提到的,你要创建一个命名的变量tisCharsLeftCntxt其他环境之外,然后分配this在你的构造吧。 Every time you run your plugin you stomp on tisCharsLeftCntxt with a new this . 每次运行插件时,您tisCharsLeftCntxt使用新的thistisCharsLeftCntxttisCharsLeftCntxt

There is no reason to use a reference to this in the wholesale fashion in which you have. 没有理由以您所使用的批发方式this进行引用。 There is only one place in your code where the scope changes such that this is no longer your instance. 您的代码中只有一个地方范围发生变化, this不再是您的实例。 That place is inside of the keyup event handling function. 该位置在keyup事件处理功能的内部。 You should localize your aliasing of this to just the method which contains that event handler. 你应该你的别名本地化this只是其中包含事件处理程序的方法。

Problem 2: 问题2:

I believe another part of your problem (this would be seen if you ran the plugin against a selector which matched more than one element) is inside of the plugin function (the one which lives off of $.fn ). 我相信问题的另一部分(如果您对匹配多个元素的选择器运行该插件,将会看到此问题)在插件函数内部(该函数$.fn )。

$.fn.fnCharsLeftPlgn = function (genStngs) {
    return $(this).data("charsleft", new fnCharsLeft(this, genStngs));
};

It should be: 它应该是:

$.fn.fnCharsLeftPlgn = function (genStngs) {
    return this.each(function () {
        $(this).data("charsleft", new fnCharsLeft(this, genStngs));
    });
};

When directly inside of a method which has been added to the jQuery prototype ( $.fn ), this refers to the entirety of the current collection, not an element. 当直接在已添加到jQuery原型( $.fn )中的方法内部时, this指的是当前集合的整体,而不是元素。 A plugin should each itself in order to run element specific logic against its individual members. 一个插件应each本身以针对其各个成员运行元件的特定逻辑。

Without using .each() you are calling .data() against an entire collection, setting all of their charsleft data properties to the one instance of fnCharsLeft . 如果不使用.each()您所呼叫.data()对整个集合,其所有的设置charsleft数据属性的一个实例fnCharsLeft By using .each() you create a new instance of fnCharsLeft for each of the elements in the collection. 通过使用.each()您可以为fnCharsLeft中的每个元素创建.each()的新实例。

Since the .each() then returns the collection, and a plugin should be chainable, you simply return it. 由于.each()然后返回集合,并且插件应该是可链接的,因此您只需返回它。

A rule of thumb is that if you're passing this into the jQuery factory ( $() ) directly inside of a plugin, function then you're doing something wrong since it is already the collection. 一条经验法则是,如果你传递this到jQuery的工厂( $()直接在插件内,函数,那么你所做的是错的,因为它已经集合。 As a second rule of thumb, almost all plugin definitions except those which are intended to return info about an element (such as .val() , .html() , or .text() when not given a param) should start with return this.each(function() {... 作为第二个经验法则,除旨在返回有关元素的信息(例如,在未提供参数的情况下, .val() .html().text()那些插件定义之外),几乎所有插件定义都应以return this.each(function() {...开头return this.each(function() {...

Solutions: 解决方案:

Bringing those changes together results in this fiddle: http://jsfiddle.net/5UQ4D/4/ 将这些更改汇总在一起将产生以下错误: http : //jsfiddle.net/5UQ4D/4/

And this code: 这段代码:

(function ($) {
    var fnCharsLeft = function (ele, genStngs) {
        this.jqe = $(ele);
        this.maxChars = genStngs.maxChars;
        this.fnInit();
    };
    fnCharsLeft.prototype = {
        fnInit: function () {
            var instance = this;

            this.fnUpdateRemainingChars();
            this.jqe.on('keyup', function (e) {
                key = e.keyCode ? e.keyCode : e.which;

                if (37 != key && 38 != key && 39 != key && 40 != key) {
                    instance.fnUpdateRemainingChars();
                }
            });
        },
        fnUpdateRemainingChars: function () {
            var charsLft = this.maxChars - this.jqe.val().length,
                jqeDestToUpdt = this.jqe.siblings('.cl');

            charsLft = charsLft < 0 ? 0 : charsLft;

            if (charsLft) {
                jqeDestToUpdt.text(charsLft + ' more of ' + this.maxChars + ' characters');
            } else {
                this.jqe
                    .val(this.jqe.val().substring(0, this.maxChars))
                    .scrollTop(this.jqe[0].scrollHeight);

                jqeDestToUpdt.text("Maximum limit of " + this.maxChars + " characters reached");

                return false;
            }
        }
    };

    $.fn.fnCharsLeftPlgn = function (genStngs) {
        return this.each(function () {
            $(this).data('charsleft', new fnCharsLeft(this, genStngs));
        });
    };
}(window.jQuery));

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM