0%

javascript 計數器應用

原理解說

和時間相關的應用在javascript中主要有兩個函式 setTimeoutsetInterval

  • setTimeout - 在指定時間後執行某些指令或函式,只會執行一次。
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    <!--在網頁上先建立一個區塊並命名一個id或是class-->
    <div class="counter"></div>

    <script>
    //先建立一個初始值
    let start=0;

    //宣告一個時間函式,並給予一個變數,
    //如果沒有指定變數,那麼這個時間函式將會無法停止
    let timeout=setTimeout(()=>{

    //將初始值加1
    start++;

    //將結果寫入網頁中指令的dom中
    //設定時間為三秒,所以要三秒後才會看到結果
    document.querySelector('.counter').innerHTML=start;
    },3000)
    </script>
  • setInterval - 在指定的間隔時間持續執行某些指令或函式,沒有停止時間。
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    <!--在網頁上先建立一個區塊並命名一個id或是class-->
    <div class="counter"></div>

    <script>
    //先建立一個初始值
    let start=0;

    //宣告一個時間函式,並給予一個變數,
    //如果沒有指定變數,那麼這個時間函式將會無法停止
    let interval=setInterval(()=>{

    //將初始值加1
    start++;

    //將結果寫入網頁中指令的dom中
    //設定時間為間隔一秒執行一次,
    //所以每秒鐘都會執行一次加1的計算並把結果放到指令的dom中
    document.querySelector('.counter').innerHTML=start;
    },1000)
    </script>
    由於以上的時間函式一旦執行後就會佔著一些記憶體空間,因此會搭配以下兩個函式來進行清楚或停止:
  • clearTimeout - 停止進行中的時間函式
    1
    2
    //函式中代入時間函式變數即可
    clearTimeout(timeout)
  • clearInterval - 停止進行中的間隔時間函式
    1
    2
    //函式中代入時間函式變數即可
    clearInterval(interval)

應用

一、快進時計

要讓數字有快進或慢進的感覺,基本上就是讓間隔時間變小,就會在畫面上呈現數字的快速變化效果,因此我們可以設定一個時間變化區間,然後把變化的量拿去除時間區間,就可以得到間隔時間,以下示範兩種時間函式的寫法,都可以得到一樣的結果:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
<!--在網頁上先建立一個區塊並命名一個id或是class-->
<div class="counter"></div>

<script>
let start=0; //起始值
let end=100; //結束值
let duration=3; //時間區間

//計算每個變量的間隔值,
//這裏使用abs函式來取得絕對值(正整數)
let timegap=(duration*1000/Math.abs(end-start));

let step=setInterval(()=>{
//在每個間隔時間的程式開始先判斷目前是否已到結束值
//如果已到結束值則中止時間函式的進行
//並使用return 來中斷整個回呼函式的執行
if(start>=end){
clearInterval(step)
return
}
start++;
document.querySelector('.counter').innerHTML=start;
},timegap)
</script>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
<!--在網頁上先建立一個區塊並命名一個id或是class-->
<div class="counter"></div>

<script>
let start=0; //起始值
let end=100; //結束值
let duration=3; //時間區間

//計算每個變量的間隔值,
//這裏使用abs函式來取得絕對值(正整數)
let timegap=(duration*1000/Math.abs(end-start));

let step=setTimeout(()=>{
//把要執行的動作獨立出去做成函式
timeloop()
},timegap)

/**
* 因為setTimeout只會執行一次,所以如果要做到連續執行多次,
* 就是在執行完成再執行一次,因此獨立成一個函式,
* 讓函式去重覆呼叫函式,就可以做到重覆執行的功能
*/
function timeloop(){
if(start>=end){
clearTimeout(step)
return
}
start++;
document.querySelector('.counter').innerHTML=start;

//更新完畫面的數字後,再重新執行一次時間函式
step=setTimeout(()=>{
timeloop()

},timegap)
}
</script>

二、進度條動畫

利用時間控制變量的原理,只要把時間和變量代入就可以做出任何動畫效果來,進度條的動畫效果一樣是有開始有結束,所以原理是一樣的,只是套用的對像從數字變成長度單位。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
<style>
.progress-box{
width:200px;
height:20px;
background:lightgreen;
border:1px solid darkgreen;
}
.progress-line{
width:0px;
height:20px;
background:green;
}
</style>
<div class='progress-box'>
<div class='progress-line'>
</div>

1
2
3
4
5
6
7
8
9
10
11
12
13
14
let start=0;
let end=150;
let duration=2;
let gap=(duration*10000/Math.abs(end-start))

let line=setInterval(()=>{
if(start>=end){
clearInterval(line);
return;
}
start++;
document.querySelector('.progress-line').style.Width=start+"px";
},gap)

三、動態時間函式

上面兩種應用都是算出固定的時間間隔,然後變量也是固定的,如果我們希望變化的效果可以更豐富,比如先快後慢或是先慢後快,那就需要在時間變化上下功夫,原則上有兩個方向可以進行:

  • 時間變化 - 固定每次的變量,但是時間不同,比如每次都加1,但是一開始是每秒加1,中間是0.5秒加1,最後是0.1秒加1。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    <!--在網頁上先建立一個區塊並命名一個id或是class-->
    <div class="counter"></div>

    <script>
    let start=0; //起始值
    let end=100; //結束值
    let duration=9; //時間區間
    let pt=0; //紀錄經過的時間
    let times=new Array() //宣告一個陣列用來存放時間間隔

    //使用迴圈來計算每個間隔時間的變化
    for(let i=start;i<100;i++){

    //在不同的時間區段計算不同的時間隔
    if(pt<(duration*1000/3)){

    //前面20個數字要在3秒內跑完,
    //所以計算每個數字的時間間隔,並存入陣列
    pt+= ((duration*1000/3)/20)
    times.push(((duration*1000/3)/20))

    }else if(pt<(duration*1000/3*2)){

    //中間50個數字要在3秒內跑完,
    //所以計算每個數字的時間間隔,並存入陣列
    pt+= ((duration*1000/3)/60)
    times.push(((duration*1000/3)/60))

    }else{

    //最後20個數字要在3秒內跑完,
    //所以計算每個數字的時間間隔,並存入陣列
    pt+= ((duration*1000/3)/20)
    times.push(((duration*1000/3)/20))

    }
    }

    let run=setTimeout(()=>{
    tf()
    },times[0])

    let ti=0; //這是一個時間索引,對應到的是times陣列

    function tf(){
    if(start>=end){
    clearTimeout(run)
    return;
    }
    document.querySelector(".counter").innerHTML=start;
    ti++;

    //每次執行完時間函式後,
    //再開一個新的時間函式並且指定新的時間
    run=setTimeout(()=>{
    tf()
    },times[ti])
    }

    </script>


  • 變量變化 - 固定間隔時間,但每次的變量不同,比如每次的時間間隔都是0.5秒,但是一開始時每次加1,中間每次加2,最後每次加3;這種模式比較適合用在圖形動畫上。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    <style>
    .progress-box{
    width:200px;
    height:20px;
    background:lightgreen;
    border:1px solid darkgreen;
    }
    .progress-line{
    width:0px;
    height:20px;
    background:green;
    }
    </style>
    <div class='progress-box'>
    <div class='progress-line'>
    </div>

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    let start=0;
    let end=150;

    let line=setInterval(()=>{
    if(start>=end){
    clearInterval(line)
    return;
    }

    //根據不同的變量區間來決定每次變量的不同
    if(start<20){
    start++;
    }else if(start<60){
    start+=2;
    }else{
    start+=4;
    }
    document.querySelector(".progress-line").style.width=start+"px";

    },100)

當然,要做出更複雜的效果,也可以考慮讓時間和變量都是動態不固定的。