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()
。减小了执行队列的复杂度。
到这里关于“跑马灯”插件的代码解析详和优化就已经完了。详细的代码和使用文档请点击链接。如果有什么问题可以随时在 github 上反馈给我。
JavaScript “跑马灯”抽奖活动代码解析与优化(二)的更多相关文章
- JavaScript “跑马灯”抽奖活动代码解析与优化(一)
最近的项目中做了一个"跑马灯"的抽奖特效插件.上篇文章已经分享过html和css 的相关知识.这篇文章主要分享一些 JavaScript 相关的知识.这几天在写这篇文章的时候,也顺 ...
- javascript 跑马灯
1.看了写跑马灯的教程案例,隔了段时间自己写了一个简单的跑马灯.将过程中遇到的问题特此记录下来 代码如下: <!DOCTYPE html> <html> <head> ...
- PL-SVO公式推导及代码解析:位姿优化
通过跳过极线约束单独优化图像中每个特征的位置后,必须通过最小化3D特征与图像中相应的2D特征位置之间的重投影误差来进一步细化(3)中获得的相机姿态( 见图5).为此,我们考虑在世界坐标系中3D特征和相 ...
- javascript跑马灯抽奖
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8&quo ...
- js之跑马灯广告
目标效果:每过1秒重复把广告的第一个字符放到最后,达到动态跑马灯效果 代码如下: <!DOCTYPE html> <html lang="en"> < ...
- TextView实现跑马灯效果
网上有很多跑马灯的介绍,有很多跑马灯的代码.或许我的不是最好的,但是应该很容易明白的. 我们先来介绍一个跑马灯的代码 <LinearLayout xmlns:android="http ...
- javascript小记五则:用JS写一个图片左右自由滚动的“跑马灯”效果
之前看了很多百度搜索出的东西,十个有九个是不能实用的,个个讲的都不详细,今天详细给大家讲解下关于这个图片“跑马灯”滚动效果,源码如下: <!DOCTYPE html PUBLIC "- ...
- JavaScript小实例-文字跑马灯效果
我们常常能看到显示屏上字体的滚动以及手机弹幕等,下面所示代码就是一个简易的文字跑马灯的效果: <!DOCTYPE html> <html> <head lang=&quo ...
- 解析Android开发优化之:从代码角度进行优化的技巧
下面我们就从几个方面来了解Android开发过程中的代码优化,需要的朋友参考下 通常我们写程序,都是在项目计划的压力下完成的,此时完成的代码可以完成具体业务逻辑,但是性能不一定是最优化的.一般来说 ...
随机推荐
- 结构体指offsetof宏详细解析
1.#define offsetof(TYPE, MEMBER) ((size_t) &((TYPE*)0)->MEMBER) (include/linux/stddef.h) ...
- canvas(四) Gradient- demo
/** * Created by xianrongbin on 2017/3/9. */ /* strokeStyle 或 fillStyle 属性的值*/ /** * Demo1 创建线性渐变 */ ...
- 50-2018 蓝桥杯省赛 B 组模拟赛(五)
1.结果填空:矩阵求和 import java.math.BigInteger; import java.util.HashSet; public class Main{ public static ...
- Linux驱动之输入子系统简析
输入子系统由驱动层.输入子系统核心.事件处理层三部分组成.一个输入事件,如鼠标移动.键盘按下等通过Driver->Inputcore->Event handler->userspac ...
- 16. pt-mysql-summary
pt-mysql-summary --host=192.168.100.101 --port=3306 --user=admin --password=admin \ pt-mysql-summary ...
- caoni大业 spring boot 跳坑记
IDEA环境 win10 跑得刚刚,到xp系统就戈壁 报错 Caused by: java.lang.NoSuchMethodError: javax.servlet.ServletContext.g ...
- 网站日志流量分析采集(LuaJIT系统环境部署-node03,相关jar包自己手动上传)
注:/usr/local/src 是源码包路径,可以自己更改 服务器中安装依赖 yum -y install gcc perl pcre-devel openssl openssl-devel 上传 ...
- dom4j 使用原生xpath 处理带命名空间的文档
测试文件 <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.o ...
- 自己封装的简单DbDao
首先,DbDao是一个用来操作数据库的类.需要对数据库的驱动包 要操作数据库首先要获得链接,这时候就需要链接数据库的所有参数了,包括driver,url,user,password.(全部定义为pri ...
- 关于wifi网络基本原理了解
对于esp32,其wifi功能还是十分强大的,为了能够良好的完成wifi的相关开发,这里需要计算机网络的结构体系进行大致的了解. 一.网络结构分层 对于计算机网络结构,大体上可以分为5层结构: 物理层 ...