国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁 > 編程 > JavaScript > 正文

JavaScript實現跑馬燈抽獎活動實例代碼解析與優化(二)

2019-11-20 10:35:40
字體:
來源:轉載
供稿:網友

在上篇文章給大家介紹了JavaScript實現跑馬燈抽獎活動實例代碼解析與優化(一),既然是要編寫插件。那么叫做“插件”的東西肯定是具有的某些特征能夠滿足我們平時開發的需求或者是提高我們的開發效率。那么叫做插件的東西應該具有哪些基本特征呢?讓我們來總結一下:

1.JavaScript 插件一些基本特征:

配置一定要簡單
插件中定義的變量不污染全局變量;
同一段代碼可以在不同的地方復用;
用戶可以自定義自己功能參數;
具有銷毀變量和參數的功能;
如果按照以上的幾個特征來寫插件的話,我們可以總結出一個基本的代碼結構,我們一個一個的來看:

1.插件配置要盡可能的簡單

html中配置容器節點

//這里的node-type="reward-area" 是標識我們插件的容器節點<div class="re-area" node-type="reward-area" >

DOM加載完成以后初始化插件

$(function() {//這里的 test 是代表容器的 classwindow.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, //燈旋轉的速度msroPrSpeed: 200, //獎品旋轉速度msliDirection: 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, //燈旋轉的速度msroPrSpeed: 200, //獎品旋轉速度msliDirection: 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實現跑馬燈抽獎活動實例代碼解析與優化(二)的相關知識就給大家介紹到這里,希望本文所述對大家有所幫助。

發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
主站蜘蛛池模板: 广平县| 瑞丽市| 泸州市| 郎溪县| 萨迦县| 德阳市| 浪卡子县| 罗平县| 中牟县| 江源县| 莱州市| 尼玛县| 安多县| 常山县| 安吉县| 永新县| 古浪县| 祁东县| 大洼县| 九寨沟县| 依兰县| 同心县| 固阳县| 淄博市| 荆门市| 灵川县| 都江堰市| 阿坝| 杭锦旗| 萨迦县| 九江县| 方山县| 灵武市| 丹棱县| 和林格尔县| 安国市| 吉林市| 博白县| 云浮市| 博白县| 克东县|