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 相关文章推荐
指定js可访问其它域名的cookie的方法
Sep 18 Javascript
关于juqery radio写法的兼容性问题(新老版本jquery)
Jun 14 Javascript
Web开发之JavaScript
Mar 29 Javascript
jquery 表格的增行删行实现思路
Mar 21 Javascript
js数组操作学习总结
Nov 04 Javascript
jqGrid日期格式的判断示例代码(开始日期与结束日期)
Nov 08 Javascript
解决jQuery使用JSONP时产生的错误
Dec 02 Javascript
JS提交form表单实例分析
Dec 10 Javascript
jQuery解析XML 详解及方法总结
Sep 28 Javascript
Bootstrap CSS组件之导航条(navbar)
Dec 17 Javascript
js,jq,css多方面实现简易下拉菜单功能
May 13 Javascript
纯js实现画一棵树的示例
Sep 05 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遍历数组的方法分享
2012/03/22 PHP
PHP进程同步代码实例
2015/02/12 PHP
PHP图片水印类的封装
2017/07/06 PHP
Javascript在IE下设置innerHTML时出现未知的运行时错误的解决方法
2011/01/12 Javascript
Firefox中autocomplete=&quot;off&quot; 设置不起作用Bug的解决方法
2011/03/25 Javascript
Dreamweaver jQuery智能提示插件,支持版本提示,支持1.6api
2011/07/31 Javascript
JavaScript创建对象的方式小结(4种方式)
2015/12/17 Javascript
深入理解jQuery之防止冒泡事件
2016/05/24 Javascript
AngularJs html compiler详解及示例代码
2016/09/01 Javascript
jQuery列表检索功能实现代码
2017/07/17 jQuery
vue使用Element组件时v-for循环里的表单项验证方法
2018/06/28 Javascript
vue实现动态添加数据滚动条自动滚动到底部的示例代码
2018/07/06 Javascript
快速解决select2在bootstrap模态框中下拉框隐藏的问题
2018/08/10 Javascript
vue动态删除从数据库倒入列表的某一条方法
2018/09/29 Javascript
vue 中基于html5 drag drap的拖放效果案例分析
2018/11/01 Javascript
layui-select动态选中值的例子
2019/09/23 Javascript
关于引入vue.js 文件的知识点总结
2020/01/28 Javascript
js中!和!!的区别与用法
2020/05/09 Javascript
[00:35]DOTA2上海特级锦标赛 EG战队宣传片
2016/03/04 DOTA
由Python运算π的值深入Python中科学计算的实现
2015/04/17 Python
Python爬虫使用脚本登录Github并查看信息
2018/07/16 Python
Python异常处理知识点总结
2019/02/18 Python
python 反编译exe文件为py文件的实例代码
2019/06/27 Python
python3实现微型的web服务器
2019/09/03 Python
Flask缓存静态文件的具体方法
2020/08/02 Python
HTML5 用动画的表现形式装载图像
2016/03/08 HTML / CSS
video实现有声音自动播放的实现方法
2020/05/20 HTML / CSS
松本清官方海外旗舰店:日本最大的药妆连锁店
2017/11/21 全球购物
采用冷却技术的超自然舒适度:GhostBed床垫
2018/09/18 全球购物
广州某公司软件工程师面试题
2014/12/22 面试题
银行自荐信范文
2013/10/07 职场文书
满月酒答谢词
2014/01/14 职场文书
服务质量承诺书
2014/03/27 职场文书
养牛场项目建议书
2014/05/13 职场文书
禁止高声喧哗的标语
2014/06/11 职场文书
个人批评与自我批评总结
2014/10/17 职场文书