JavaScript “跑马灯”抽奖运动代码剖析与优化(二)

既然是要编写插件。那末叫做“插件”的东西肯定是具有的某些特性能够满足我们日常平凡开辟的需求或者是进步我们的开辟效力。那末叫做插件的东西应当具有哪些基础特性呢?让我们来总结一下:

1.JavaScript 插件一些基础特性:

  1. 设置一定要简朴

  2. 插件中定义的变量不污染全局变量;

  3. 统一段代码能够在差别的处所复用;

  4. 用户能够自定义本身功用参数;

  5. 具有烧毁变量和参数的功用;

假如依据以上的几个特性来写插件的话,我们能够总结出一个基础的代码构造,我们一个一个的来看:

1.插件设置要尽能够的简朴

html中设置容器节点

//这里的node-type="reward-area" 是标识我们插件的容器节点
<div class="re-area" node-type="reward-area" >

DOM加载完成今后初始化插件

$(function() {
    //这里的 test 是代表容器的 class
    window.LightRotate.init($('[node-type=reward-area]'));
});

2.插件中定义的变量不污染全局变量

JavaScript 具有块级作用域的标识符就是function了。那我们怎样声明我们的变量才能够使它不污染全局变量呢?
这里我们须要用到的一个 JavaScript 函数的自实行的知识点。代码以下:

(function(){
    // do something
})();

3.在差别的处所复用功用代码

这就要用到我们面向对象的知识点,把我们的功用代码笼统成对象,在我们须要运用的时刻,实例化对象就能够了。那我们接着第二部的代码继承写,

//
(function($){
    // 建立功用对象
    var LightRotate = function (select) {
        // do something
    };

    LightRotate.init = function (select) {
        var _this = this;
        //依据差别的容器实例化差别的对象
        select.each(function () {
            new _this($(this));
        });
    };

    window.LightRotate = LightRotate;
})(jQuery);

4.用户能够自定义功用参数

起首我们应当有默许的参数设定,比以下面如许

//
(function($){
    // 建立功用对象
    var LightRotate = function (select) {
        // 自定义的参数
        this.setting = {
            liAutoPlay: false,  //四周的灯是不是自动扭转
            roLiSpeed: 100,     //灯扭转的速率ms
            roPrSpeed: 200,     //奖品扭转速率ms
            liDirection: true,  //扭转方向 true  正方向   false  反方向
            randomPrize: false  //空格是不是随机拔取
        };
    };

    LightRotate.init = function (select) {
        var _this = this;
        //依据差别的容器实例化差别的对象
        select.each(function () {
            new _this($(this));
        });
    };

    window.LightRotate = LightRotate;
})(jQuery);

实在如许写的话,运用者已能够修正我们的 JavaScript 文件来完成自定义了。然则为了能够让我们的差价充足的好用,比方说,我们的运用者一点儿都不懂 js 呢?该怎样办?
如许我们能够把这些参数用自定义属性设置在 html中,以下:

<div class="re-area" node-type="reward-area" data-setting='{
    "liAutoPlay":false,
    "roLiSpeed":100,
    "roPrSpeed":200,
    "liDirection":true,
    "randomPrize":false}'>

如许用户只须要在 html的节点中就能够设置当前容器运转的参数。如许的长处还能够使统一页面上的差别容器,能够零丁的设置参数,削减耦合。

那末在 js 中我们该怎样猎取这些参数呢?在上面的代码中,已有了功用对象函数。那末我们想扩大对象要领来猎取用户的自定义参数,怎样办呢?我们平常运用prototype的东西来扩大我们已有对象的要领,代码以下:

//
(function($){
    // 建立功用对象
    var LightRotate = function (select) {
        // 自定义的参数
        this.setting = {
            liAutoPlay: false,  //四周的灯是不是自动扭转
            roLiSpeed: 100,     //灯扭转的速率ms
            roPrSpeed: 200,     //奖品扭转速率ms
            liDirection: true,  //扭转方向 true  正方向   false  反方向
            randomPrize: false  //空格是不是随机拔取
        };
        
        //这里挪用对象的猎取用户自定义参数的要领,而且将默许参数兼并
        $.extend(_this.setting, _this.getSettingUser());
    };

    LightRotate.prototype = {
        //扩大猎取用户自定义参数的要领
        getSettingUser: function () {
            var userSetting = this.LightArea.attr('data-setting');
            if (userSetting && userSetting !== '') {
                return $.parseJSON(userSetting);
            } else {
                return {};
            }
        }
    };

    LightRotate.init = function (select) {
        var _this = this;
        //依据差别的容器实例化差别的对象
        select.each(function () {
            new _this($(this));
        });
    };

    window.LightRotate = LightRotate;
})(jQuery);

5.烧毁变量和参数的功用;

末了一个就是我们的插件应当具有烧毁本身变量和参数的功用。我们该怎样写呢?照样在上面的代码基础上继承扩大功用对象的可挪用要领,代码以下:

LightRotate.prototype = {
        //扩大猎取用户自定义参数的要领
        getSettingUser: function () {
            var userSetting = this.LightArea.attr('data-setting');
            if (userSetting && userSetting !== '') {
                return $.parseJSON(userSetting);
            } else {
                return {};
            }
        },
        //烧毁对象参数
        destory: function () {
            $(_this.LightArea).off();
            this.closeAnimation();
            this.rewardTimer = null;
        }
    };

由以上我们的内容我们能够也许了解了一个成熟的插件应当具有的基础功用。

2.插件开辟和优化示例

恰好这个项目是在春节放假前的一个紧要的项目,当时为了赶进度就没有细致思索本身的代码构造,如许野味本身的后续优化供应了时机。

由上一节引见的定时器的内容能够晓得 JavaScript 是单线程的。所以

假如一段代码运转效力很低,就会影响后续代码的实行。所以关于 JavaScript ,代码优化是必需的。

先来看看我们的“跑马灯”插件应当具有哪些功用:

  1. 能够掌握灯是不是自动播放;

  2. 灯的扭转方向能够掌握;

  3. 灯的扭转速率能够掌握;

  4. 奖品的扭转速率能够掌握;

这里就不细致的引见这些功用点的开辟历程,仅仅引见优化历程。假如有兴致能够看我文章末了附上的源代码地点,举行下载浏览。

1.“递次”猎取扭转灯代码的优化

由于四周的灯我是运用相对定位来做的,所以我须要“递次”的猎取他们的列表,然后操纵。

起首猎取 DOM节点。

//猎取外围的灯,能够看到我这里运用的选择器多了一个 select,是为了猎取当前容器下的某些元素,防止有多个容器存在时争执
this.topLight = $('[node-type=re-top]', select).find('span');
this.rightLight = $('[node-type=re-right]', select).find('span');
this.bottomLight = $('[node-type=re-bottom]', select).find('span');
this.leftLight = $('[node-type=re-left]', select).find('span');

然后就应当“递次”的猎取“灯”节点的 DOM 元素列表。

我的初版是如许做的:

Zepto(topLight).each(function() {
      lightList.push(this);
});

Zepto(rightLight).each(function() {
      lightList.push(this);
});

for (var j = bottomLight.length - 1; j >= 0; j--) {
     lightList.push(bottomLight[j]);
}

for (var m = leftLight.length - 1; m >= 0; m--) {
       lightList.push(leftLight[m]);
}

由于“下”和“左”方向的灯是须要倒序的,所以我运用了两个倒序的 for轮回,实在当轮回涌现的时刻,我们都应当思索我们的代码是不是有可优化的空间。

优化后的代码是如许子的,在这里我削减了4次轮回的运用

function () {
    var lightList = [];
    var bottomRever;
    var leftRever;
     bottomRever = Array.from(this.bottomLight).reverse();
     leftRever = Array.from(this.leftLight).reverse();

     lightList = Array.from(this.topLight).concat(Array.from(this.rightLight));
     lightList = lightList.concat(bottomRever);
     lightList = lightList.concat(leftRever);
     }

列表倒序我运用了原生 Array对象的reverse要领。

2.运用“闭包”优化递次轮回播放

为了能够使我们的“灯”递次的跑起来,初版的思绪是:

每个“灯”(注重,这里是每个,罪行…罪行…)定义一个setTimeout(),实行时候就是数序的到场 js 实行行列中去。

代码是下面如许子的:

            var zepto_light = Zepto(lightList);
            var changeTime = 100;
            var lightLength = zepto_light.length;
            var totleTime = changeTime * lightLength;

            function lightOpen() {
                for (var i = 0; i < lightLength; i++) {
                    (function temp(i) {
                        lightTimer = setTimeout(function() {
                            if (stopAnimation === false) {
                                Zepto(zepto_light).removeClass('light_open');
                                Zepto(zepto_light[i]).addClass("light_open");
                            } else {
                                return;
                            }
                        }, changeTime * i);
                    })(i);
                }
            }

如许子写的瑕玷很明显:假如我有100个“灯”那末就会在当前的 js 实行行列中到场100个setTimeout(),再次强调的是我这里又运用了for轮回,在时候庞杂度上又增加了。代码的实行效力又下降了。

厥后思索了下,JavaScript 中“闭包”相符我当前的运用场景,就想着用闭包优化一下,优化后代码以下:

lightRun: function () {
            var _this = this;
            function tempFunc() {
                var lightList = _this.getLightList();
                var lightLength = lightList.length;
                var i = 0;
                return function () {

                    $(lightList, _this.LightArea).removeClass('light_open');
                    $(lightList[i], _this.LightArea).addClass("light_open");
                    i++;

                    //使一轮轮回完毕后能够继承下次轮回
                    if (i === lightLength) {
                        i = 0;
                    }
                };
            }

            var lightRunFunc = tempFunc();
            lightRunFunc();
            _this.lightInterVal = setInterval(lightRunFunc, _this.setting.roLiSpeed);
        }

由以上的代码能够很明显的发明两个长处:第一,就是削减了 for轮回的运用,降低了代码的时候庞杂度,第二就是,每次我仅仅在当前代码实行的行列中建立一个setInterval()。减小了实行行列的庞杂度。

到这里关于“跑马灯”插件的代码剖析详和优化就已完了。细致的代码和运用文档请点击链接。假如有什么问题能够随时在 github 上反应给我。

《JavaScript “跑马灯”抽奖运动代码剖析与优化(二)》

    原文作者:zhiqiang21
    原文地址: https://segmentfault.com/a/1190000004436642
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞