[js高手之路]打造通用的勻速運動框架

来源:http://www.cnblogs.com/ghostwu/archive/2017/10/15/7670033.html
-Advertisement-
Play Games

本文,是接著上文[js高手之路]勻速運動與實例實戰(側邊欄,淡入淡出)繼續的,在這篇文章的最後,我們做了2個小實例:側邊欄與改變透明度的淡入淡出效果,本文我們把上文的animate函數,繼續改造,讓他變得更加的通用和強大: 1,支持多個物體的運動 2,同時運動 3,順序運動 這三種運動方式也是jqu ...


本文,是接著上文[js高手之路]勻速運動與實例實戰(側邊欄,淡入淡出)繼續的,在這篇文章的最後,我們做了2個小實例:側邊欄與改變透明度的淡入淡出效果,本文我們把上文的animate函數,繼續改造,讓他變得更加的通用和強大:

1,支持多個物體的運動

2,同時運動

3,順序運動

這三種運動方式也是jquery中animate函數支持的

一、animate函數中怎麼區分變化不同的樣式?

上文中,側邊欄效果 用的animate函數 改變的是left值

 1 function animate(obj, target, speed) {
 2     clearInterval(timer);
 3     timer = setInterval(function () {
 4         if (obj.offsetLeft == target) {
 5             clearInterval(timer);
 6         } else {
 7             obj.style.left = obj.offsetLeft + speed + 'px';
 8         }
 9     }, 30);
10 }

淡入淡出效果 用的animate函數 改變的是透明度

 1             function animate(obj, target, speed) {
 2                 clearInterval(timer);
 3                 var cur = 0;
 4                 timer = setInterval(function () {
 5                     cur = css( obj, 'opacity') * 100;
 6                     if( cur == target ){
 7                        clearInterval( timer );
 8                     }else {
 9                         cur += speed;
10                         obj.style.opacity = cur / 100;
11                         obj.style.filter = "alpha(opacity:" + cur + ")";
12                     }
13                 }, 30);
14             }

而我們封裝的函數,要變成通用的,首先面臨的問題就是 這個函數要同時支持left值和透明度的變化,更通用的做法應該是要支持所有的樣式變化,比如輪播功能,他有左右滑動,也有上下滑動。

我們可以在獲取樣式和改變樣式的時候,做一下判斷就可以了,判斷分2類就能達到目的,因為其他樣式( margin, left, top, right, font-size等等 )都是px,而透明度沒有px單位

 1 function animate(obj, attr, target, speed) {
 2     clearInterval(timer);
 3     var cur = 0;
 4     timer = setInterval(function () {
 5         if (attr == 'opacity') {
 6             cur = css(obj, 'opacity') * 100;
 7         } else {
 8             cur = parseInt(css(obj, attr));
 9         }
10 
11         if (cur == target) {
12             clearInterval(timer);
13         } else {
14             if (attr == 'opacity') {
15                 obj.style.opacity = ( cur + speed ) / 100;
16                 obj.style.filter = "alpha(opacity:" + (cur + speed) + ")";
17             } else {
18                 obj.style[attr] = cur + speed + "px";
19             }
20         }
21     }, 30);
22 }

合併之後的animate相比之前多了一個參數attr, 這個參數就是變化的樣式,obj: 變化的對象, target: 樣式需要變化到的目標值.  speed: 樣式每次變化的大小

如:

oImg.onmouseover = function () {   animate(this, 'opacity', 100, 10); } oImg是獲取到的圖片對象. 這裡各參數意思如下: this:當前圖片對象 opacity: 變化的樣式是透明度 100: 滑鼠移到圖片上時,透明度變成100 10: 透明度每次在原來的基礎上加10
 1 <!doctype html>
 2 <html lang="en">
 3 <head>
 4     <meta charset="UTF-8">
 5     <title>合併的運動 - by ghostwu</title>
 6     <style>
 7         img {
 8             border: none;
 9             opacity: 0.3;
10             filter: alpha(opacity:30);
11             position: absolute;
12             left: 200px;
13         }
14 
15         #box {
16             width: 150px;
17             height: 300px;
18             background: red;
19             position: absolute;
20             left: -150px;
21             top: 50px;
22         }
23 
24         #box div {
25             width: 28px;
26             height: 100px;
27             position: absolute;
28             right: -28px;
29             top: 100px;
30             background: green;
31         }
32     </style>
33     <script>
34         window.onload = function () {
35             var oImg = document.getElementById("img"),
36                 oBox = document.getElementById("box"),
37                 timer = null;
38 
39             oImg.onmouseover = function () {
40                 animate(this, 'opacity', 100, 10);
41             }
42             oImg.onmouseout = function () {
43                 animate(this, 'opacity', 30, -10);
44             }
45 
46             oBox.onmouseover = function () {
47                 animate(this, 'left', 0, 10);
48             }
49 
50             oBox.onmouseout = function () {
51                 animate(this, 'left', -150, -10);
52             }
53 
54             function animate(obj, attr, target, speed) {
55                 clearInterval(timer);
56                 var cur = 0;
57                 timer = setInterval(function () {
58                     if (attr == 'opacity') {
59                         cur = css(obj, 'opacity') * 100;
60                     } else {
61                         cur = parseInt(css(obj, attr));
62                     }
63 
64                     if (cur == target) {
65                         clearInterval(timer);
66                     } else {
67                         if (attr == 'opacity') {
68                             obj.style.opacity = ( cur + speed ) / 100;
69                             obj.style.filter = "alpha(opacity:" + (cur + speed) + ")";
70                         } else {
71                             obj.style[attr] = cur + speed + "px";
72                         }
73                     }
74                 }, 30);
75             }
76 
77             function css(obj, attr) {
78                 if (obj.currentStyle) {
79                     return obj.currentStyle[attr];
80                 } else {
81                     return getComputedStyle(obj, false)[attr];
82                 }
83             }
84         }
85     </script>
86 </head>
87 <body>
88 <div id="box">
89     <div>分享到</div>
90 </div>
91 <img src="./img/h4.jpg" alt="" id="img"/>
92 </body>
93 </html>
View Code

上述就是完整的代碼實例,請自行展開,點擊run code預覽效果 


  當你分別測試這兩個功能的時候: 移動到圖片上然後移出來 移動到分享到,然後移出來 這樣是沒有問題的   如果你這樣測試: 移動到 分享到,然後迅速又移動到圖片上, 這個時候你會發現 分享到 停下來了,這就不符合邏輯了! 按道理來說,滑鼠移動到圖片上,相當於觸發了 “分享到” 的mouseout( 滑鼠移出事件 ),那麼  "分享到" 這個時候要隱藏,並不是停止。 為什麼會這樣呢?因為這兩個運動共用了一個定時器,當滑鼠移動到圖片上,開啟定時器的時候,把“分享到”的定時器給停了。那麼再做多物體運動的時候,我們就要把定時器拆分,每個對象都要有一個定時器,怎麼做呢? 非常簡單,不要定義一個簡單的timer變數,我們只要把timer加在obj對象上,那麼每個對象都有一個timer屬性,就達到定時器的分離效果了 修改之後的完整代碼如下,請自行展開:
 1 <!doctype html>
 2 <html lang="en">
 3 <head>
 4     <meta charset="UTF-8">
 5     <title>Document</title>
 6     <style>
 7         img {
 8             border: none;
 9             opacity: 0.3;
10             filter: alpha(opacity:30);
11             position: absolute;
12             left: 200px;
13         }
14 
15         #box {
16             width: 150px;
17             height: 300px;
18             background: red;
19             position: absolute;
20             left: -150px;
21             top: 50px;
22         }
23 
24         #box div {
25             width: 28px;
26             height: 100px;
27             position: absolute;
28             right: -28px;
29             top: 100px;
30             background: green;
31         }
32     </style>
33     <script>
34         window.onload = function () {
35             var oImg = document.getElementById("img"),
36                 oBox = document.getElementById("box");
37 
38             oImg.onmouseover = function () {
39                 animate(this, 'opacity', 100, 10);
40             }
41             oImg.onmouseout = function () {
42                 animate(this, 'opacity', 30, -10);
43             }
44 
45             oBox.onmouseover = function () {
46                 animate(this, 'left', 0, 10);
47             }
48 
49             oBox.onmouseout = function () {
50                 animate(this, 'left', -150, -10);
51             }
52 
53             function animate(obj, attr, target, speed) {
54                 clearInterval(obj.timer);
55                 var cur = 0;
56                 obj.timer = setInterval(function () {
57                     if (attr == 'opacity') {
58                         cur = css(obj, 'opacity') * 100;
59                     } else {
60                         cur = parseInt(css(obj, attr));
61                     }
62 
63                     if (cur == target) {
64                         clearInterval(obj.timer);
65                     } else {
66                         if (attr == 'opacity') {
67                             obj.style.opacity = ( cur + speed ) / 100;
68                             obj.style.filter = "alpha(opacity:" + (cur + speed) + ")";
69                         } else {
70                             obj.style[attr] = cur + speed + "px";
71                         }
72                     }
73                 }, 30);
74             }
75 
76             function css(obj, attr) {
77                 if (obj.currentStyle) {
78                     return obj.currentStyle[attr];
79                 } else {
80                     return getComputedStyle(obj, false)[attr];
81                 }
82             }
83         }
84     </script>
85 </head>
86 <body>
87 <div id="box">
88     <div>分享到</div>
89 </div>
90 <img src="./img/h4.jpg" alt="" id="img"/>
91 </body>
92 </html>
View Code

至此,我們就完成了多物體運動與不同樣式的修改

二、讓animate函數支持多個樣式同時改變

比如:

oBox.onmouseover = function(){
  animate( this, { "width" : 500, "height" : 400 }, 10 );
}

oBox是一個div元素,animate各參數的意思:

this: 當前div元素

{width : 500, "height" : 400 } : 把寬度變成500, 高度變成400,這兩個樣式要在同一時間完成,

10: 樣式每次在原來的基礎上變化10(如width初始值200--> 210, 220, 230.....)

完整的同時運動變化 代碼:

 1 <!doctype html>
 2 <html lang="en">
 3 <head>
 4     <meta charset="UTF-8">
 5     <title>Document</title>
 6     <style>
 7     div {
 8         width: 200px;
 9         height: 200px;
10         background: red;
11     }
12     </style>
13     <script>
14         window.onload = function () {
15             var oBox = document.getElementById("box");
16             oBox.onmouseover = function(){
17 //                animate( this, { "width" : 500, "height" : 500 }, 10 );
18                 animate( this, { "width" : 500, "height" : 400 }, 10 );
19             }
20 
21             function animate(obj, attr, speed) {
22                 clearInterval(obj.timer);
23                 var cur = 0;
24                 obj.timer = setInterval(function () {
25                     for ( var key in attr ) {
26                         if (key == 'opacity') {
27                             cur = css(obj, 'opacity') * 100;
28                         } else {
29                             cur = parseInt(css(obj, key));
30                         }
31                         var target = attr[key];
32                         if (cur == target) {
33                             clearInterval(obj.timer);
34                         } else {
35                             if (key == 'opacity') {
36                                 obj.style.opacity = ( cur + speed ) / 100;
37                                 obj.style.filter = "alpha(opacity:" + (cur + speed) + ")";
38                             } else {
39                                 obj.style[key] = cur + speed + "px";
40                             }
41                         }
42                     }
43                 }, 30);
44             }
45 
46             function css(obj, attr) {
47                 if (obj.currentStyle) {
48                     return obj.currentStyle[attr];
49                 } else {
50                     return getComputedStyle(obj, false)[attr];
51                 }
52             }
53         }
54     </script>
55 </head>
56 <body>
57     <div id="box"></div>
58 </body>
59 </html>
View Code

請自行展開這段代碼,這段代碼能夠同時運動,但是有一個問題:

div的初始寬度與高度( width : 200, height : 200)

變化步長一樣( 10 )

變化時間一樣( 每30毫秒變化一次 )

目標( width: 500, height : 400 )

你能想到什麼問題嗎?( 兩個人在同一起跑線上,速度一樣, 時間一樣,但是要同時到達不同的目標,一個500, 一個400 )

答案是很明顯的,肯定是目標近的( height : 400 )那個先到達,然後把對象上的定時器關了,另一個目標更遠的( width: 500 )肯定到達不了

你可以在這句代碼下麵,輸出當前的值和目標值:

var target = attr[key]; console.log( key, cur, target );

輸出來的結果是:

 

 

 從上圖可以看出,height已經達到了400px,但是width停在了410px,為什麼不是400px ? 因為width = 400的時候, 就是( cur == 500 ) 相當於( 400 == 500 ) 不成立,所以執行了else語句,width = cur + 10 = 400 + 10 = 410,然後height到達400px停止了定時器,所以width停在了410px.

那麼我們怎麼解決這個問題呢?

其實也好辦,就是height = 400的時候 不要把定時器關了,應該等width = 500的時候再關閉定時器,不就在同一時間,完成了同時到達目標的效果嗎?

修改後的代碼如下:

 1 <!doctype html>
 2 <html lang="en">
 3 <head>
 4     <meta charset="UTF-8">
 5     <title>Document</title>
 6     <style>
 7     div {
 8         width: 200px;
 9         height: 200px;
10         background: red;
11     }
12     </style>
13     <script>
14         window.onload = function () {
15             var oBox = document.getElementById("box");
16             oBox.onmouseover = function(){
17                 animate( this, { "width" : 500, "height" : 400 }, 10 );
18             }
19 
20             function animate(obj, attr, speed) {
21                 clearInterval(obj.timer);
22                 var cur = 0;
23                 obj.timer = setInterval(function () {
24                     var bFlag = true;
25                     for ( var key in attr ) {
26                         if (key == 'opacity') {
27                             cur = css(obj, 'opacity') * 100;
28                         } else {
29                             cur = parseInt(css(obj, key));
30                         }
31                         var target = attr[key];
32                         if (cur != target) {
33                             bFlag = false;
34                             if (key == 'opacity') {
35                                 obj.style.opacity = ( cur + speed ) / 100;
36                                 obj.style.filter = "alpha(opacity:" + (cur + speed) + ")";
37                             } else {
38                                 obj.style[key] = cur + speed + "px";
39                             }
40                         }
41                     }
42                     if ( bFlag ) {
43                         clearInterval( obj.timer );
44                     }
45                 }, 30);
46             }
47 
48             function css(obj, attr) {
49                 if (obj.currentStyle) {
50                     return obj.currentStyle[attr];
51                 } else {
52                     return getComputedStyle(obj, false)[attr];
53                 }
54             }
55         }
56     </script>
57 </head>
58 <body>
59     <div id="box"></div>
60 </body>
61 </html>
View Code

聲明一個變數,每次變化完一次( width, height )樣式 把bFlag = true, 只要在for迴圈中有一個沒有到達目標,bFlag的值都是false,這樣就不會關閉定時器。當兩個都到達目標,才關閉定時器.

三、順序運動

 如樣式變化,按順序來,不是同時變化, 如:

oBox.onmouseover = function(){
//回調函數: 把函數當做參數傳遞給另一個函數
  animate( this, { 'width' : 500 }, 10, function(){
    animate( this, { 'height' : 500 }, 10 );
  } );
}

當把width變成500px的時候,如果傳遞了回調函數, 再接著執行回調函數裡面的運動

修改後的完整代碼:

 1 <!DOCTYPE html>
 2 <html>
 3 <head lang="en">
 4     <meta charset="UTF-8">
 5     <title>通用的勻速運動框架 - by ghostwu</title>
 6     <style>
 7         div {
 8             width: 200px;
 9             height: 200px;
10             background: red;
11         }
12     </style>
13     <script>
14         window.onload = function () {
15             var oBox = document.getElementById("box");
16             oBox.onmouseover = function(){
17                 //回調函數: 把函數當做參數傳遞給另一個函數
18                 animate( this, { 'width' : 500 }, 10, function(){
19                     animate( this, { 'height' : 500 }, 10 );
20                 } );
21             }
22 
23             function animate(obj, attr, speed, fn ) {
24 
25                 clearInterval(obj.timer);
26                 var cur = 0;
27                 obj.timer = setInterval(function () {
28                     var bFlag = true;
29                     for (var key in attr) {
30                         if (key == 'opacity') {
31                             cur = css(obj, 'opacity') * 100;
32                         } else {
33                             cur = parseInt(css(obj, key));
34                         }
35                         var target = attr[key];
36                         if (cur != target) {
37                             bFlag = false;
38                             if (key == 'opacity') {
39                                 obj.style.opacity = ( cur + speed ) / 100;
40                                 obj.style.filter = "alpha(opacity:" + (cur + speed) + ")";
41                             } else {
42                                 obj.style[key] = cur + speed + "px";
43                             }
44                         }
45                     }
46 
47                     if (bFlag) {
48                         clearInterval(obj.timer);
49                         fn && fn.call( obj );
50                     }
51                 }, 30);
52             }
53 
54             function css(obj, attr) {
55                 if (obj.currentStyle) {
56                     return obj.currentStyle[attr];
57                 } else {
58                     return getComputedStyle(obj, false)[attr];
59                 }
60             }
61         }
62     </script>
63 </head>
64 <body>
65 <div id="box"></div>
66 </body>
67 </html>
View Code

  


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 一、搭建SVN環境 1.下載VisualSVN Sever。下載地址:https://www.visualsvn.com/server/download/ 2.安裝VisualSVN Server。 點擊“Next”。 單擊“Next”,下一步,這裡預設,安裝SVN伺服器和管理控制台,下麵也是預設勾 ...
  • 1.字典的定義 字典類似於列表,但相對於列表來說字典更加通用,列表的下標必須必須為整數,而字典下標則可以為任意字元串/數字等,不可以是可變數據類型(列表,數組,元組) 字典包含下標(keys)集合和值(vaule)集合,且keys是唯一的 2.字典的創建 實例如下: 輸入如下 3.字典的特性 無序性 ...
  • 轉自 內置函數 ...
  • 前幾天跟著視頻做了一個簡單的購物車程式,但是沒有做出來,之後又跟著後面的視頻,做了一個,視頻裡面老師也講了,只有不斷的嘗試寫,才能慢慢有感覺,越不寫,越不會。下麵是我前幾天寫的購物車和跟著視頻做的購物車的對比: 自己寫的: 老師寫的: ​ 後面的視頻佈置的作業是把購物車進行優化,優化的內容是,分別添 ...
  • "項目目錄結構"其實也是屬於"可讀性和可維護性"的範疇。 目錄組織方式 關於如何組織一個較好的Python工程目錄結構,已經有一些得到了共識的目錄結構。在Stackoverflow的這個問題上,能看到大家對Python目錄結構的討論。 這裡面說的已經很好了,我也不打算重新造輪子列舉各種不同的方式,這 ...
  • ...
  • 2017 Multi-University Training Contest - Team 1 簽到題 ...
  • 這篇文章的效果,需要看過以下3篇文章: [js插件開發教程]一步步開發一個可以定製配置的隔行變色小插件 [js高手之路]勻速運動與實例實戰(側邊欄,淡入淡出) [js高手之路]打造通用的勻速運動框架 ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...