前回の記事では、プラグインを書く必要があるため、マーキー宝くじイベントのJavaScript実装サンプルコード分析と最適化(1)を紹介しました。その場合、「プラグイン」と呼ばれるものは、日常の開発ニーズを満たしたり、開発効率を向上させたりできる特定の特性を備えている必要があります。では、プラグインと呼ばれるものが持つべき基本的な特性は何でしょうか?要約しましょう:
1. JavaScript プラグインのいくつかの基本機能:
構成はシンプルである必要があります
プラグインで定義された変数はグローバル変数を汚染しません。
同じコード部分を別の場所で再利用できます
ユーザーは独自の関数パラメータをカスタマイズできます。
変数とパラメータを破棄する機能があります。
上記の特性に従ってプラグインを作成すると、基本的なコード構造を 1 つずつ見てみましょう。
HTML でのコンテナ ノードの構成
//这里的node-type="reward-area" 是标识我们插件的容器节点 <div class="re-area" node-type="reward-area" >
$(function() { //这里的 test 是代表容器的 class window.LightRotate.init($('[node-type=reward-area]')); });
ブロックレベルのスコープを持つ JavaScript の識別子は function です。では、グローバル変数を汚染しないように変数を宣言するにはどうすればよいでしょうか?
ここでは、JavaScript 関数の自己実行に関する知識を使用する必要があります。コードは次のとおりです:
(function(){ // do something })();
これには、オブジェクト指向のナレッジ ポイントを使用して、関数コードをオブジェクトに抽象化し、それを使用する必要があるときにオブジェクトをインスタンス化する必要があります。次に、2 番目の部分
でコードを書き続けましょう。
// (function($){ // 创建功能对象 var LightRotate = function (select) { // do something }; LightRotate.init = function (select) { var _this = this; //根据不同的容器实例化不同的对象 select.each(function () { new _this($(this)); }); }; window.LightRotate = LightRotate; })(jQuery);
まず、次のようなデフォルトのパラメータ設定が必要です。
// (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);
<div class="re-area" node-type="reward-area" data-setting='{ "liAutoPlay":false, "roLiSpeed":100, "roPrSpeed":200, "liDirection":true, "randomPrize":false}'>
// (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);
上記の内容から、成熟したプラグインが備えるべき基本的な機能を大まかに理解できます。
2. プラグインの開発と最適化の例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; } };
前のセクションで紹介したタイマーの内容から、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');
「下」と「左」の方向のライトは逆の順序にする必要があるため、2 つの for ループを逆の順序で使用しました。実際、ループが出現するときは、最適化の余地があるかどうかを全員が考慮する必要があります。私たちのコードでは。
最適化されたコードは次のようになります。ここでは 4 つのループの使用を減らしています
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]); }
列表倒序我使用了原生 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实现跑马灯抽奖活动实例代码解析与优化(二)的相关知识就给大家介绍到这里,希望本文所述对大家有所帮助。