更新jQuery插件以构建HTML并防止它在多次调用时重建

时间:2015-07-11 11:14:19

标签: javascript jquery css

我正在努力将我的简单JavaScript Donut Chart转换为jQuery插件。

这是我的第一个jQuery插件,我可以在几个地方使用一些帮助...

到目前为止我演示的内容:http://jsfiddle.net/jasondavis/qsgqebox/

以下是我到目前为止的JavaScript。

jQuery

jQuery.fn.updatePercentageGraph = function (options) {

    var settings = $.extend({
            // These are the defaults.
            percent: 0,
        }, options );    

    var percent = settings.percent;

    if(typeof percent === 'undefined') {
        var percent = parseInt(this.data('percent'));
    }else{
        if(percent === '') {
            var percent = parseInt(this.data('percent'));
        }else{
            var percent = parseInt(percent);
            this.attr('data-percent', percent);
        }
    }

    var deg = 360*percent/100;
    if (percent > 50) {
        this.addClass('gt-50');
    }else{
        this.removeClass('gt-50');
    }
    $('.ppc-progress-fill').css('transform','rotate('+ deg +'deg)');
    $('.ppc-percents span').html(percent+'%');

};

用法:

$('#project_progress2').updatePercentageGraph(34);

我需要帮助:

1)
它目前要求用户像这样设置HTML:

<div id="project_progress" class="progress-pie-chart" data-percent="40">
    <div class="ppc-progress">
        <div class="ppc-progress-fill4" style="transform: rotate(136.8deg);"></div>
    </div>
    <div class="ppc-percents4">
        <div class="pcc-percents-wrapper">
            <span>40%</span>
        </div>
    </div>
</div>

我想做的就是把它放在你可以做这样的事情的地方......

<div id="project_progress" class="progress-pie-chart" data-percent="40"></div>

然后jQuery插件会自动创建正确的子节点。

jQuery会自动创建:

<div class="ppc-progress">
    <div class="ppc-progress-fill4" style="transform: rotate(136.8deg);"></div>
</div>
<div class="ppc-percents4">
    <div class="pcc-percents-wrapper">
        <span>40%</span>
    </div>
</div>

2)更新一些选择器以允许页面上的多个圆环图

到目前为止插件中的另一个问题是从上面显示的JavaScript底部开始的第3和第4行。它正在调用$('.ppc-progress-fill')$('.ppc-percents span'),这会阻止在页面上使用多个图表,因此需要更新以仅定位当前图表中存在的类。

3)优化以防止每次调用函数时重新创建HTML结构以更新百分比值

如果我将此插件转换为自动生成HTML结构,那么我还需要考虑对其进行优化,以便每次我的代码运行时都不必重复生成该结构。将调用$('#project_progress2').updatePercentageGraph(34);因为在我将使用它的项目中,这些图表将不断更新百分比值。

或许甚至可能更好的是有一个创建初始图表HTML的函数,然后是第二个可以反复调用的函数,只是处理百分比的更新并且不会尝试重建和一遍又一遍地注入HTML结构!

我提到的这些问题是我目前有点困难的关键领域,可以请一些帮助。

JSFiddle演示:

JSFiddle我到目前为止所提供的一些按钮来测试更新百分比值:http://jsfiddle.net/jasondavis/qsgqebox/

2 个答案:

答案 0 :(得分:2)

我疯了吗?是的,我是!

您在http://jsfiddle.net/qsgqebox/3/

我不会向你解释所有这些代码。只是想说这是我通常为jQuery编写插件的方式。

(function($) {
    'use strict';

    var PercentageGraph = function(element) {
        // Setup settings
        this.settings = $.extend({
            percent: element.data('percent') ? element.data('percent') : 0
        });

        // Store the given element
        this.element = element;

        // Create the progress bar
        this.create();

        // Initialization
        this.update();
    }

    PercentageGraph.prototype = {
        create: function() {
            // Create:
            // <div class="ppc-progress">
            //     <div class="ppc-progress-fill4"></div>
            // </div>
            this.progress = $('<div />');
            this.progress.addClass('ppc-progress');

            this.progressFill = $('<div />');
            this.progressFill
                .addClass('ppc-progress-fill')
                .appendTo(this.progress);

            // Create:
            // <div class="ppc-percents4">
            // <div class="pcc-percents-wrapper">
            //     <span>40%</span>
            // </div>
            // </div>
            this.percents = $('<div />');
            this.percents.addClass('ppc-percents');

            this.percentsWrapper = $('<div />');
            this.percentsWrapper
                .addClass('pcc-percents-wrapper')
                .appendTo(this.percents);

            this.percentsContent = $('<span />');
            this.percentsContent
                .text(this.settings.percent)
                .appendTo(this.percentsWrapper);

            // Append everything to the element
            this.progress.appendTo(this.element);
            this.percents.appendTo(this.element);
        },
        update: function(p) {
            var percent = p ? p : this.settings.percent,
                deg = 360 * percent / 100;

            if (percent > 50) {
                this.element.addClass('gt-50');
            } else {
                this.element.removeClass('gt-50');
            }

            this.progressFill.css('transform', 'rotate('+ deg +'deg)');
            this.percentsContent.html(percent + '%');
        }
    }

    jQuery.fn.percentageGraph = function() {
        return new PercentageGraph(this);
    }
})(jQuery);

(function($) {
    $(document).ready(function() {
        var progress = $('div#project_progress').percentageGraph();

        // Handle it
        $('.update-button').on('click', function() {
            var percent = $(this).data('percent');

            // Update it
            progress.update(percent);
        });        
    });
})(jQuery);

答案 1 :(得分:2)

  

1)jQuery部分将自动创建

要解决这一问题,您需要在插件创建时创建HTML结构。

  

2)更新一些选择器以允许页面上的多个甜甜圈图表

防止使用整页选择器。相反,您可以保留对创建的HTML结构的引用,并仅对此子集起作用。不是整个DOM。

  

3)优化以防止每次调用函数时重新创建HTML结构以更新百分比值

解决多个实例的常用模式是创建一个包含插件实例的data属性。如果某个实例已经存在,那么您只需对该实例执行操作,而不是创建新实例。

拥有此实例对于另一个用于向插件添加方法的jQuery模式也很有用。您可以检查传递给插件的参数是否为字符串,然后调用具有该名称的方法。

$('#project_progress').updatePercentageGraph('percent', percent);

您也可以使用不带参数的相同方法获取值:

var percent = $('#project_progress').updatePercentageGraph('percent');

一体化,我会建议这样的事情:

(function ($, undefined) {
    'use strict';
    function PercentageGraph(element, options) {
        this.$percentageGraph = $(element).append(
            '<div class="ppc-progress">' +
                '<div class="ppc-progress-fill"></div>' +
            '</div>' +
            '<div class="ppc-percents">' +
                '<div class="pcc-percents-wrapper">' +
                    '<span>0%</span>' +
                '</div>' +
            '</div>'
        );
        this.options = $.extend({}, $(element).data(), options);
        this._init();
    }
    PercentageGraph.prototype = {
        _init: function () {
            this.percent(this.options.percent || 0);
        },
        _update: function () {
            var percent = this.options.percent;
            var deg = 360*percent/100;
            if (percent > 50) {
                this.$percentageGraph.addClass('gt-50');
            }else{
                this.$percentageGraph.removeClass('gt-50');
            }
            this.$percentageGraph.find('.ppc-progress-fill').css('transform','rotate('+ deg +'deg)');
            this.$percentageGraph.find('.ppc-percents span').html(percent+'%');
        },
        percent: function (percent) {
            // If no parameter, act as a getter. Otherwise act as a setter.
            if (percent === undefined) {
                return this.options.percent;
            } else {
                this.options.percent = percent;
                this._update();
            }
        },
    }

    $.fn.updatePercentageGraph = function (options) {
        var args = Array.prototype.slice.call(arguments, 1),
            result;
        this.each(function () {
            var plugin = $(this).data('percentage-graph');
            if (!plugin) {
                $(this).data('percentage-graph', (plugin = new PercentageGraph(this, options)));
            }
            var method = typeof options === 'string' ? options : '_init';
            result = plugin[method].apply(plugin, args);
            // Break the .each iteration if it is a getter, that is, when the method returns something.
            return result === undefined;
        });
        return result || this;
    };
}(jQuery));

请参阅demo