在样板插件中创建添加/删除或刷新功能

时间:2014-02-14 09:58:47

标签: javascript jquery

我正在构建这个简单的插件,只是构建一个表:

; (function ($, window, document, undefined) {

    // Create the defaults once
    var pluginName = "tableBuilder",
        defaults = {
        };

    // The actual plugin constructor
    function Plugin(element, options) {
        this.element = element;

        // jQuery has an extend method that merges the
        // contents of two or more objects, storing the
        // result in the first object. The first object
        // is generally empty because we don't want to alter
        // the default options for future instances of the plugin
        this.options = $.extend({}, defaults, options);

        this._defaults = defaults;
        this._name = pluginName;

        this.init();
    }

    String.prototype.format = function (values) {

        var regex = /\{([\w-.]+)(?:\:([\w\.]*)(?:\((.*?)?\))?)?\}/g;

        var getValue = function (key) {
            var value = values,
                arr, type;

            if (values == null || typeof values === 'undefined') return null;

            if (key.indexOf('.')) {
                arr = key.split('.');

                while (arr.length && value) {
                    value = value[arr.shift()];
                }
            } else {
                value = val && val[key] || values[key];
            }

            type = typeof value;

            return type === 'string' || type === 'number' ? value : null;
        };

        return this.replace(regex, function (match) {
            //match will look like {sample-match}
            //key will be 'sample-match';
            var key = match.substr(1, match.length - 2);

            var value = getValue(key);

            return value != null ? value : match;
        });
    };

    Plugin.prototype = {

        init: function () {
            // Place initialization logic here
            // You already have access to the DOM element and
            // the options via the instance, e.g. this.element
            // and this.options
            // you can add more functions like the one below and
            // call them like so: this.yourOtherFunction(this.element, this.options).

            this.cycle();
        },

        cycle: function() {
            var self = this;

            self.buildRow();
            self.display();
        },

        buildRow: function () {
            var self = this;
            self.rows = [];

            $.each(self.options.json, function (i, item) {
                self.rows.push(self.options.rowTemplate.format(item));
            });

            console.log(self.rows);
        },

        display: function (el, options) {
            var self = this;

            $(self.element).html(self.rows.join());
        }
    };

    // A really lightweight plugin wrapper around the constructor,
    // preventing against multiple instantiations
    $.fn[pluginName] = function (options) {
        return this.each(function () {
            if (!$.data(this, "plugin_" + pluginName)) {
                $.data(this, "plugin_" + pluginName,
                new Plugin(this, options));
            }
        });
    };

})(jQuery, window, document);

我是通过按钮点击事件来调用它的:

var row = "<tr data-id=\"{Id}\"><td>{FileName}</td><td>{Metadata.FileSize}</td><td></td><td><button type=\"button\" class=\"close\" data-id=\"{Id}\" aria-hidden=\"true\">&times;</button></td></tr>"

$("#assets").on("click", ".glyphicon", function () {
    var $asset = $(this).parent();
    var $actionBar = $("#action-bar");
    var $selected = $("#selected-asset");
    var $table = $(".table");

    var currentSelected = parseInt($selected.text());
    var assetId = parseInt($asset.attr("id"))

    if ($asset.hasClass("active")) {
        $selected.text(currentSelected - 1);
        activeItems = $.grep(activeItems, function (obj) {
            return obj.Id != assetId
        });
        $asset.removeClass("active");

        if (activeItems.length <= 0) {
            $actionBar.hide();
        }
    } else {
        $selected.text(currentSelected + 1);
        var asset = $.grep(assets, function (obj) {
            return obj.Id == assetId
        });

        activeItems.push(asset[0]);
        $asset.addClass("active");

        $actionBar.show();
    }

    $("#assets-table").tableBuilder({
        json: activeItems,
        rowTemplate: row
    });
});

现在,当我第一次点击添加时,会创建表格。但是之后的每次点击都没有。我在 buildRows 函数上放了一个 console.log ,只调用一次,这是预期的,因为我们只在该元素上实例化插件。

因此,我需要添加一个可供客户端使用的刷新功能或添加/删除功能。

任何人都可以帮我一把吗?

2 个答案:

答案 0 :(得分:1)

好的,所以我对上一个答案印象不深。 在此视频的帮助下:

Head first into plugin development

我能够确定所有函数实际上都是插件实例的一部分。 所以,这是我的新插件:)

String.prototype.format = function (values) {

    var regex = /\{([\w-.]+)(?:\:([\w\.]*)(?:\((.*?)?\))?)?\}/g;

    var getValue = function (key) {
        var value = values,
            arr, type;

        if (values == null || typeof values === 'undefined') return null;

        if (key.indexOf('.')) {
            arr = key.split('.');

            while (arr.length && value) {
                value = value[arr.shift()];
            }
        } else {
            value = val && val[key] || values[key];
        }

        type = typeof value;

        return type === 'string' || type === 'number' ? value : null;
    };

    return this.replace(regex, function (match) {
        //match will look like {sample-match}
        //key will be 'sample-match';
        var key = match.substr(1, match.length - 2);

        var value = getValue(key);

        return value != null ? value : match;
    });
};

; (function ($, window, document, undefined) {

    var pluginName = "tableBuilder",
        defaults = {
        };

    function Plugin(element, options) {
        this.element = element;
        this.$element = $(element);
        this.rows = [];

        this.rowTemplate = (typeof options === "string") ? options : options.rowTemplate;
        this.options = $.extend({}, defaults, options);

        this._defaults = defaults;
        this._name = pluginName;

        this.init();
    }

    Plugin.prototype = {

        init: function () {
            this.cycle();
        },

        cycle: function () {
            var self = this;

            if (self.options.json != null) {
                self.buildRow();
                self.display();
            }

            if (typeof self.options.onComplete === "function") {
                self.options.onComplete.apply(self.element, arguments);
            }
        },

        buildRow: function () {
            var self = this;

            $.each(self.options.json, function (i, item) {
                self.rows.push(self.rowTemplate.format(item));
            });
        },

        display: function (el, options) {
            this.$element.html(this.rows.join());
        },

        add: function (row) {
            console.log("moo");

            this.rows.push(this.options.rowTemplate.format(row));
            this.display();
        },

        remove: function(row) {
            var match = this.options.rowTemplate.format(row);
            this.rows = $.grep(this.rows, function (obj) {
                return obj != match;
            });
            this.display();
        }
    };

    $.fn[pluginName] = function (options) {
        return this.each(function () {
            if (!$.data(this, "plugin_" + pluginName)) {
                $.data(this, "plugin_" + pluginName,
                new Plugin(this, options));
            }
        });
    };

})(jQuery, window, document);

现在,我需要访问的功能是 add() remove(),所以如果你看一下这些行:

$.fn[pluginName] = function (options) {
    return this.each(function () {
        if (!$.data(this, "plugin_" + pluginName)) {
            $.data(this, "plugin_" + pluginName,
            new Plugin(this, options));
        }
    });
};

他们实际上是将实例传递给$ .data数组,这允许我用一行代码调用我的实例:

$("#assets-table").data("plugin_tableBuilder")

因此,我可以调用属于该实例的任何函数,如下所示:

$("#assets-table").data("plugin_tableBuilder").add(asset[0]); // Add a row to our widget

我希望这有助于其他人:D

/ r3plica

答案 1 :(得分:0)

我将自己回答:) 基本上我认为这不是处理我的小部件的最佳方式,因此我使用widget factory boilerplate来解决我的问题。我将点击事件修改为:

$("#assets").on("click", ".glyphicon", function () {
    var $asset = $(this).parent(); // Get our asset element
    var $actionBar = $("#action-bar"); // Get the action bar
    var $selected = $("#selected-asset");// Get our selected asset counter

    var currentSelected = parseInt($selected.text()); // Get our current counter value
    var assetId = parseInt($asset.attr("id")); // Get the asset id
    var asset = $.grep(assets, function (obj) { // Find our asset from our array
        return obj.Id == assetId;
    });

    if ($asset.hasClass("active")) { // If our asset is already selected, then we must unselect it
        $selected.text(currentSelected - 1); // First, decrease our counter
        tableWidget.tableBuilder("remove", asset[0]); // Then call our widget and remove the current asset from the table
        activeItems = $.grep(activeItems, function (obj) { // Repopulate our array of active assets
            return obj != asset;
        });
        $asset.removeClass("active"); // And remove the active class from our element

        if (activeItems.length <= 0) { // Finally, if this is the only selected asset
            $actionBar.hide(); // Hide our actionbar
        }
    } else { // Else, we are selecting an asset
        $selected.text(currentSelected + 1); // Increase our counter
        tableWidget.tableBuilder("add", asset[0]); // Add a row to our widget
        activeItems.push(asset[0]); // Add the asset to our array of active assets
        $asset.addClass("active"); // Add our active alss to our element

        $actionBar.show(); // And show our actionbar
    }
});

我在页面上实例化了我的插件,如下所示:

var row = "<tr data-id=\"{Id}\"><td>{FileName}</td><td>{Metadata.FileSize}</td><td></td><td><button type=\"button\" class=\"close\" data-id=\"{Id}\" aria-hidden=\"true\">&times;</button></td></tr>"
var tableWidget;

$(function () {
    tableWidget = $("#assets-table").tableBuilder({
        rowTemplate: row
    });
});

然后,我的剧本改写为:

/*!
 * jQuery UI Widget-factory plugin boilerplate (for 1.8/9+)
 * Author: @addyosmani
 * Further changes: @peolanha
 * Licensed under the MIT license
 */

    String.prototype.format = function (values) {

        var regex = /\{([\w-.]+)(?:\:([\w\.]*)(?:\((.*?)?\))?)?\}/g;

        var getValue = function (key) {
            var value = values,
                arr, type;

            if (values == null || typeof values === 'undefined') return null;

            if (key.indexOf('.')) {
                arr = key.split('.');

                while (arr.length && value) {
                    value = value[arr.shift()];
                }
            } else {
                value = val && val[key] || values[key];
            }

            type = typeof value;

            return type === 'string' || type === 'number' ? value : null;
        };

        return this.replace(regex, function (match) {
            //match will look like {sample-match}
            //key will be 'sample-match';
            var key = match.substr(1, match.length - 2);

            var value = getValue(key);

            return value != null ? value : match;
        });
    };

; (function ($, window, document, undefined) {

    // define your widget under a namespace of your choice
    //  with additional parameters e.g.
    // $.widget( "namespace.widgetname", (optional) - an
    // existing widget prototype to inherit from, an object
    // literal to become the widget's prototype );

    $.widget("skipstone.tableBuilder", {

        //Options to be used as defaults
        options: {
            json: null,
            rowTemplate: null
        },

        //Setup widget (eg. element creation, apply theming
        // , bind events etc.)
        _create: function () {

            // _create will automatically run the first time
            // this widget is called. Put the initial widget
            // setup code here, then you can access the element
            // on which the widget was called via this.element.
            // The options defined above can be accessed
            // via this.options this.element.addStuff();

            this.rows = [];

            if (this.options.json != null) {
                this._buildRow();
                this._display();
            }
        },

        _buildRow: function () {
            var self = this;

            $.each(self.options.json, function (i, item) {
                self.rows.push(self.options.rowTemplate.format(item));
            });
        },

        _display: function (el, options) {
            $(this.element).html(this.rows.join());
        },

        add: function (row) {
            this.rows.push(this.options.rowTemplate.format(row));
            this._display();
        },

        remove: function(row) {
            var match = this.options.rowTemplate.format(row);
            this.rows = $.grep(this.rows, function (obj) {
                return obj != match;
            });
            this._display();
        },

        // Destroy an instantiated plugin and clean up
        // modifications the widget has made to the DOM
        destroy: function () {

            // this.element.removeStuff();
            // For UI 1.8, destroy must be invoked from the
            // base widget
            $.Widget.prototype.destroy.call(this);
            // For UI 1.9, define _destroy instead and don't
            // worry about
            // calling the base widget
        }
    });

})(jQuery, window, document);

这是如何解决我的问题。您可以看到我通过调用

添加行
tableWidget.tableBuilder("add", asset[0]);

并通过调用

删除项目
tableWidget.tableBuilder("remove", asset[0]);

我真的希望帮助别人:D

干杯, r3plica