>  기사  >  웹 프론트엔드  >  복권 이벤트 예시 코드 분석 및 최적화 JavaScript 구현 (2)_javascript 기술

복권 이벤트 예시 코드 분석 및 최적화 JavaScript 구현 (2)_javascript 기술

WBOY
WBOY원래의
2016-05-16 15:15:291201검색

지난 글에서 마키 복권 이벤트 예제 코드 분석 및 최적화의 JavaScript 구현(1)에 대해 소개했는데, 플러그인을 작성해야 하기 때문입니다. 그렇다면 "플러그인"이라는 것이 일상적인 개발 요구 사항을 충족하거나 개발 효율성을 향상시킬 수 있는 특정 특성을 가져야 합니다. 그렇다면 플러그인이라는 것이 갖춰야 할 기본 특성은 무엇일까요? 요약하자면:

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(){
// 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에서 이러한 매개변수를 어떻게 얻을 수 있을까요? 위 코드에는 이미 기능적 객체 함수가 있습니다. 그래서 우리는 사용자의 맞춤 매개변수를 얻기 위해 객체 메소드를 확장하고 싶습니다. 어떻게 해야 할까요? 우리는 일반적으로 기존 객체의 메서드를 확장하기 위해 프로토타입을 사용합니다.

//
(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의 경우 코드 최적화가 필수입니다.
먼저 "marquee" 플러그인에 어떤 기능이 있어야 하는지 살펴보겠습니다.

조명 자동 재생 여부를 제어할 수 있습니다.
조명의 회전 방향을 제어할 수 있습니다.
빛의 회전 속도를 제어할 수 있습니다.
상품의 회전 속도를 제어할 수 있습니다.
여기서는 이러한 기능점의 개발 과정을 자세히 소개하지 않고 최적화 과정만 소개하겠습니다. 관심이 있으신 분은 제 글 마지막에 첨부된 소스코드 주소를 보시고 다운로드하여 읽어보실 수 있습니다.

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');

그런 다음 "light" 노드의 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实现跑马灯抽奖活动实例代码解析与优化(二)的相关知识就给大家介绍到这里,希望本文所述对大家有所帮助。

성명:
본 글의 내용은 네티즌들의 자발적인 기여로 작성되었으며, 저작권은 원저작자에게 있습니다. 본 사이트는 이에 상응하는 법적 책임을 지지 않습니다. 표절이나 침해가 의심되는 콘텐츠를 발견한 경우 admin@php.cn으로 문의하세요.