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 相关文章推荐
IE6下javasc#ipt:void(0) 无效的解决方法
Dec 23 Javascript
jquery移除、绑定、触发元素事件使用示例详解
Apr 10 Javascript
JQuery异步获取返回值中文乱码的解决方法
Jan 29 Javascript
JavaScript使用function定义对象并调用的方法
Mar 23 Javascript
深入理解JavaScript的React框架的原理
Jul 02 Javascript
JavaScript中的Object对象学习教程
May 20 Javascript
jquery常用的12个小功能
Jul 22 Javascript
详解react如何在组件中获取路由参数
Jun 15 Javascript
Vue中的$set的使用实例代码
Oct 08 Javascript
Vue 解决多级动态面包屑导航的问题
Nov 04 Javascript
vue中echarts的用法及与elementui-select的协同绑定操作
Nov 17 Vue.js
vue数据字典取键值项目的字典问题
Apr 12 Vue.js
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 遍历数据表数据并列表横向排列的代码
2009/09/05 PHP
php获取字符串中各个字符出现次数的方法
2015/02/23 PHP
PHP实现简单汉字验证码
2015/07/28 PHP
PHP接口继承及接口多继承原理与实现方法详解
2017/10/18 PHP
Laravel框架表单验证操作实例分析
2019/09/30 PHP
MSN消息提示类
2006/09/05 Javascript
JS 事件绑定函数代码
2010/04/28 Javascript
javascript温习的一些笔记 基础常用知识小结
2011/06/22 Javascript
JS图片根据鼠标滚动延时加载的实例代码
2013/07/13 Javascript
让元素在网页中可拖动示例代码
2013/08/13 Javascript
JS+flash实现chrome和ie浏览器下同时可以复制粘贴
2013/09/22 Javascript
javascript bom是什么及bom和dom的区别
2015/11/26 Javascript
WordPress中利用AJAX异步获取评论用户头像的方法
2016/01/08 Javascript
bootstrap table配置参数例子
2017/01/05 Javascript
微信小程序分页加载的实例代码
2017/07/11 Javascript
Angular2+国际化方案(ngx-translate)的示例代码
2017/08/23 Javascript
vue中配置mint-ui报css错误问题的解决方法
2017/10/11 Javascript
JavaScript门面模式详解
2017/10/19 Javascript
使用electron制作满屏心特效的示例代码
2018/11/27 Javascript
使用Angular material主题定义自己的组件库的配色体系
2019/09/04 Javascript
Nuxt.js实现一个SSR的前端博客的示例代码
2019/09/06 Javascript
vue中进行微博分享的实例讲解
2019/10/14 Javascript
JS实现随机抽选获奖者
2019/11/07 Javascript
如何在vue 中使用柱状图 并自修改配置
2021/01/21 Vue.js
Python设计模式编程中解释器模式的简单程序示例分享
2016/03/02 Python
python 计算文件的md5值实例
2017/01/13 Python
如何用python整理附件
2018/05/13 Python
Python图像处理之图片文字识别功能(OCR)
2019/07/30 Python
Python如何将字符串转换为日期
2020/07/31 Python
CSS3常用的几种颜色渐变模式总结
2016/11/18 HTML / CSS
在C++ 程序中调用被C 编译器编译后的函数,为什么要加extern "C"
2014/08/09 面试题
销售自荐信
2013/10/22 职场文书
蟋蟀的住宅教学反思
2014/04/26 职场文书
员工离职感谢信
2015/01/22 职场文书
商务宴请邀请函范文
2015/02/02 职场文书
sentinel支持的redis高可用集群配置详解
2022/04/01 Redis