JavaScript实现跑马灯抽奖活动实例代码解析与优化(二)


Posted in Javascript onFebruary 16, 2016

在上篇文章给大家介绍了JavaScript实现跑马灯抽奖活动实例代码解析与优化(一),既然是要编写插件。那么叫做“插件”的东西肯定是具有的某些特征能够满足我们平时开发的需求或者是提高我们的开发效率。那么叫做插件的东西应该具有哪些基本特征呢?让我们来总结一下:

1.JavaScript 插件一些基本特征:

配置一定要简单
插件中定义的变量不污染全局变量;
同一段代码可以在不同的地方复用;
用户可以自定义自己功能参数;
具有销毁变量和参数的功能;
如果按照以上的几个特征来写插件的话,我们可以总结出一个基本的代码结构,我们一个一个的来看:

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.“顺序”获取旋转灯代码的优化

因为周围的灯我是使用绝对定位来做的,所以我需要“顺序”的获取他们的列表,然后操作。

首先获取 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()。减小了执行队列的复杂度。

关于JavaScript实现跑马灯抽奖活动实例代码解析与优化(二)的相关知识就给大家介绍到这里,希望本文所述对大家有所帮助。

Javascript 相关文章推荐
?牟┛途W扣了一??效果出?? target=
May 27 Javascript
jquery分割字符串的方法
Jun 24 Javascript
JS+CSS实现仿msn风格选项卡效果代码
Oct 22 Javascript
使用postMesssage()实现iframe跨域页面间的信息传递
Mar 29 Javascript
js和jQuery设置Opacity半透明 兼容IE6
May 24 Javascript
Angular5.1新功能分享
Dec 21 Javascript
微信小程序引入Vant组件库过程解析
Aug 06 Javascript
vue实现整屏滚动切换
Jun 29 Javascript
vue打包npm run build时候界面报错的解决
Aug 13 Javascript
vue配置多代理服务接口地址操作
Sep 08 Javascript
JavaScript实现原型封装轮播图
Dec 27 Javascript
JavaScript实现消消乐的源代码
Jan 12 Javascript
JavaScript实现跑马灯抽奖活动实例代码解析与优化(一)
Feb 16 #Javascript
javascript HTML+CSS实现经典橙色导航菜单
Feb 16 #Javascript
JavaScript中使用数组方法汇总
Feb 16 #Javascript
jquery拖拽排序简单实现方法(效果增强版)
Feb 16 #Javascript
jquery实现具有收缩功能的垂直导航菜单
Feb 16 #Javascript
学习使用AngularJS文件上传控件
Feb 16 #Javascript
JS中call/apply、arguments、undefined/null方法详解
Feb 15 #Javascript
You might like
php file_exists 检查文件或目录是否存在的函数
2010/05/10 PHP
php遍历目录方法小结
2015/03/10 PHP
PHP生成唯一ID之SnowFlake算法
2016/12/17 PHP
php表单习惯用的正则表达式
2017/10/11 PHP
PHP自定义函数实现数组比较功能示例
2017/10/19 PHP
jQuery+CSS 实现的超Sexy下拉菜单
2010/01/17 Javascript
JQuery的html(data)方法与&amp;lt;script&amp;gt;脚本块的解决方法
2010/03/09 Javascript
TBCompressor js代码压缩
2011/01/05 Javascript
css结合js制作下拉菜单示例代码
2014/02/27 Javascript
JavaScript使用RegExp进行正则匹配的方法
2015/07/11 Javascript
JS实用技巧小结(屏蔽错误、div滚动条设置、背景图片位置等)
2016/06/16 Javascript
BootstrapTable refresh 方法使用实例简单介绍
2017/02/20 Javascript
Bootstrap3多级下拉菜单
2017/02/24 Javascript
Vue2 使用 Echarts 创建图表实例代码
2017/05/18 Javascript
JS监控关闭浏览器操作的实例详解
2017/09/12 Javascript
react 应用多入口配置及实践总结
2018/10/17 Javascript
JavaScript中的事件与异常捕获详析
2019/02/24 Javascript
vue+mock.js实现前后端分离
2019/07/24 Javascript
微信小程序实现modal弹出框遮罩层组件(可带文本框)
2020/12/20 Javascript
[02:41]DOTA2英雄基础教程 亚巴顿
2014/01/02 DOTA
Python新手实现2048小游戏
2015/03/31 Python
详解Python多线程
2016/11/14 Python
一篇文章快速了解Python的GIL
2018/01/12 Python
pandas DataFrame 交集并集补集的实现
2019/06/24 Python
Python多版本开发环境管理工具介绍
2019/07/03 Python
关于pycharm中pip版本10.0无法使用的解决办法
2019/10/10 Python
python编写微信公众号首图思路详解
2019/12/13 Python
如何使用Python发送HTML格式的邮件
2020/02/11 Python
详解Anaconda安装tensorflow报错问题解决方法
2020/11/01 Python
大学四年规划书范文
2013/12/27 职场文书
遗产继承公证书
2014/04/09 职场文书
土地转让协议书
2014/04/15 职场文书
企业承诺书怎么写
2014/05/24 职场文书
2015元旦文艺汇演主持稿(开场白+结束语)
2014/12/14 职场文书
Python爬取用户观影数据并分析用户与电影之间的隐藏信息!
2021/06/29 Python
java代码实现空间切割
2022/01/18 Java/Android