1. 程式人生 > >javascript運動系列第一篇——勻速運動

javascript運動系列第一篇——勻速運動

前面的話

  除了拖拽以外,運動也是javascript動畫的一個基本操作。通過CSS屬性transitionanimation可以實現運動。但是,要進行更精細地操作,javascript運動是必不可少的。本文將詳細介紹javascript運動

簡單運動

  讓一個元素在頁面中運動起來很簡單,設定定時器,改變定位元素的left或top值即可

<button id="btn">開始運動</button>
<button id="reset">還原</button>
<div id="test" style="height: 100px;width: 100px;background-color: pink;position:absolute;left:0;"
></div> <script> var timer; reset.onclick = function(){history.go();} btn.onclick = function(){ timer = setInterval(function(){ if(test.offsetLeft < 500){ test.style.left = test.offsetLeft + 10 + 'px'; }else{ test.style.left = '500px'; clearInterval(timer); } },
30); } </script>

定時器管理

  上面的程式碼中沒有進行定時器管理。當元素在運動的過程中,多次按下按鈕,會開啟多個定時器,從而使元素運動速度加快

  有兩種定時器管理方式

【1】開啟新定時器前,消除舊定時器

  [注意]即使沒有定時器的情況下,消除定時器也不會報錯,只是靜默失敗

<button id="btn">開始運動</button>
<button id="reset">還原</button>
<div id="test" style="height: 100px;width: 100px;background-color: pink;position:absolute;left:0;"
></div> <script> var timer; reset.onclick = function(){history.go();} btn.onclick = function(){ clearInterval(timer); timer = setInterval(function(){ if(test.offsetLeft < 500){ test.style.left = test.offsetLeft + 10 + 'px'; }else{ test.style.left = '500px'; clearInterval(timer); } },30); } </script>

【2】當定時器未停止時,不允許開啟新定時器

  [注意]由於定時器開啟時,其返回值是一個不為0的整數,所以可以通過判斷其返回值,來確定是否使用return語句

<button id="btn">開始運動</button>
<button id="reset">還原</button>
<div id="test" style="height: 100px;width: 100px;background-color: pink;position:absolute;left:0;"></div>
<script>
var timer;
reset.onclick = function(){history.go();}
btn.onclick = function(){
    if(timer) return;
    timer = setInterval(function(){
        if(test.offsetLeft < 500){
            test.style.left = test.offsetLeft + 10 + 'px';
        }else{
            test.style.left = '500px';
            clearInterval(timer);
        }    
    },30);
}
</script>

分享效果

  現在要做一個類似於“分享到”側邊欄的效果

<style>
#test{
    width: 100px;
    height: 100px;
    background-color: lightblue;
    text-align:center;
    position:absolute;
    top: 0;
    left: -100px;
}    
#test-in{
    width: 30px;
    height: 60px;
    background-color: orange;
    margin-left: 100px;
    position:relative;
    top: 20px;
}
</style>
<div id="test">
    <div id="test-in">分享到</div>
</div>    
<script>
test.onmouseover = function(){test.style.left = '0px';}
test.onmouseout = function(){test.style.left = '-100px';}
</script>

移入移出

  如果把滑鼠移入和滑鼠移出都增加運動效果,則需要使用運動函式

  但是,有一個很重要的問題需要注意的是,滑鼠移入移出的順序問題

  如果把移入移出事件都加在父元素的身上,則需要做如下處理

  由於滑鼠從子元素移動到父元素上時,會觸發子元素的移出事件,通過冒泡也會觸發父元素移出事件。此時,有兩種方法解決該問題。一種是在子元素移出事件中阻止冒泡,另一種是在父元素移出事件設定target判斷條件。當target為父元素本身時才執行

  滑鼠從父元素移動到子元素的過程中,會按照順序觸發父元素的移出事件、子元素的移入事件以及父元素的移入事件

  為了避免觸發移入事件。此時,使用開關變數對移入事件的程式碼進行限制。移出事件程式碼完成之前不執行移入事件程式碼

<script>
var testIn = document.getElementById('test-in');
var timer1,timer2;
var onOff = false;
test.onmouseover = function(){
    if(!onOff){    
        clearInterval(timer1);
        timer1 = setInterval(function(){
            if(!onOff){
                if(test.offsetLeft < 0){
                    test.style.left = test.offsetLeft + 10 + 'px';
                }else{
                    test.style.left = '0';
                    clearInterval(timer1);
                    timer1 = 0;
                }                    
            }else{
                clearInterval(timer1);
            }
        },30);
    }
}
test.onmouseout = function(e){
    e = e || event;
    var target = e.target || e.srcElement;
    if(target === test){
        //當觸發父元素移出事件時,開啟開關
        onOff = true;
        clearInterval(timer2);
        timer2 = setInterval(function(){
            if(test.offsetLeft > -100){
                test.style.left = test.offsetLeft - 10 + 'px';
            }else{
                test.style.left = '-100px';
                clearInterval(timer2);
                timer2 = 0;
                //當運動結束後,關閉開關
                onOff = false;
            }    
        },30);        
    }
}
</script>

運動函式

  從上面的程式碼中,可以看出運動部分的重複程式碼較多,把運動封裝為帶引數的函式更合適

<style>
#test{width: 100px;height: 100px;background-color:lightblue;text-align:center;position:absolute;top: 0;left: -100px;}    
#test-in{width: 30px;height: 60px;background-color: orange;margin-left: 100px;position:relative;top: 20px;}
</style>
<div id="test">
    <div id="test-in">分享到</div>
</div>    
<script>
var testIn = document.getElementById('test-in');
var timer;
test.onmouseover = function(){move(test,0,10);}
test.onmouseout = function(){move(test,-100,-10)}
function move(obj,target,speed){
    clearInterval(timer);
    timer = setInterval(function(){
        if((obj.offsetLeft - target)*speed < 0){
            obj.style.left = obj.offsetLeft + speed + 'px';
        }else{
            obj.style.left = target + 'px';
            clearInterval(timer);
            timer = 0;
        }                
    },16);        
}    
</script>

  由於不僅僅是left值可以做運動,其他屬性(如width)也可以。所以,屬性attr也應該作為引數提取出來

  這時就無法使用offset類屬性,而應該使用計算樣式的相容函式getCSS()

function getCSS(obj,style){
    if(window.getComputedStyle){
        return getComputedStyle(obj)[style];
    }
    return obj.currentStyle[style];
}   

function move(obj,attr,target,speed){
    clearInterval(timer);
    timer = setInterval(function(){
        var cur = parseInt(getCSS(obj,attr));
        if((cur - target)*speed < 0){
            obj.style.left = cur + speed + 'px';
        }else{
            obj.style.left = target + 'px';
            clearInterval(timer);
            timer = 0;
        }                
    },30);        
}

透明度

  透明度是一個比較特殊的樣式,因為IE8-瀏覽器不支援opacity,只能通過濾鏡的方式寫成filter:alpha(opacity=透明值)

  但是,由於IE瀏覽器獲取計算樣式時,可以獲得自定義樣式,所以雖然opacity屬性在IE8-瀏覽器無法生效,但是可以獲得它的值

  如果透明度做運動的話,則需要對運動函式進行重新封裝

  [注意]由於透明度涉及小數計算,如0.07*100=> 7.000000000000001,所以需要用Math.round()去掉尾巴

<style>
#test{width: 100px;height: 100px;background-color:lightblue;text-align:center;position:absolute;top: 0;left: 0;}    
#test-in{width: 30px;height: 60px;background-color: orange;margin-left: 100px;position:relative;top: 20px;}
</style>
<div id="test">
    <div id="test-in">分享到</div>
</div>    
<script>
var testIn = document.getElementById('test-in');
var timer;
test.onmouseover = function(){move(test,'opacity',0.1,-0.05);}
test.onmouseout = function(){move(test,'opacity',1,0.05)}
function getCSS(obj,style){
    if(window.getComputedStyle){
        return getComputedStyle(obj)[style];
    }
    return obj.currentStyle[style];
}   
function move(obj,attr,target,speed){
    clearInterval(timer);
    var cur;
    timer = setInterval(function(){
        if(attr == 'opacity'){
            cur = Math.round(getCSS(obj,attr)*100);
            if((cur - target*100)*speed < 0){
                obj.style.opacity = (cur + speed*100)/100;
                obj.style.filter = 'alpha(opacity=' + (cur + speed*100) + ')';
            }else{
                obj.style.opacity = target;
                obj.filter = 'alpha(opacity=' + target + ')';
                clearInterval(timer);
                timer = 0;
            }
        }else{
            cur = parseInt(getCSS(obj,attr));
            if((cur - target)*speed < 0){
                obj.style[attr] = cur + speed + 'px';
            }else{
                obj.style[attr] = target + 'px';
                clearInterval(timer);
                timer = 0;
            }    
        }
                
    },30);        
}    
</script>

多值

  如果一個元素有多個值同時運動時,像下面這樣直接呼叫move()函式是有問題的

move(test,'opacity',0.1,-0.05);
move(test,'left',-100,-1);

  因為函式裡面定時器的變數timer是一個公共變數,當一個運動停止時,會清除定時器。這時另一個運動即使沒有完成,定時器已經停止了,就無法繼續運動了

  所以,合適的做法是在引數物件obj下面設定一個自定義屬性timers,timers為一個空物件,然後將定時器返回值儲存在timers物件下的attr屬性中,此時兩個定時器不會相互干擾

<style>
#test{width: 100px;height: 100px;background-color: lightblue;text-align:center;position:absolute;top: 0;left: -100px;opacity:1;}    
#test-in{width: 30px;height: 60px;background-color: orange;margin-left: 100px;position:relative;top: 20px;}
</style>
<div id="test">
    <div id="test-in">分享到</div>
</div>    
<script>
test.onmouseover 
            
           

相關推薦

javascript運動系列第一——勻速運動

前面的話   除了拖拽以外,運動也是javascript動畫的一個基本操作。通過CSS屬性transition和animation可以實現運動。但是,要進行更精細地操作,javascript運動是必不可少的。本文將詳細介紹javascript運動 簡單運動   讓一個元素在頁面中運動起來很簡單,設定

深入理解javascript物件系列第一——初識物件

前面的話   javascript中的難點是函式、物件和繼承,前面已經介紹過函式系列。從本系列開始介紹物件部分,本文是該系列的第一篇——初識物件 物件定義   javascript的基本資料型別包括undefined、null、boolean、string、number和object。物件和其他基本

javascript運動系列第五——緩衝運動和彈性運動

前面的話   緩衝運動指的是減速運動,減速到0的時候,元素正好停在目標點。而彈性運動同樣是減速運動,但元素並不是直接停在目標點,而是在目標點附近彈幾下再停止。本文將以一種新的思路來詳細介紹緩衝運動和彈性運動 緩衝運動   在變速運動中,曾經用物理學的知識實現過緩衝運動。緩衝運動實際上就是減速運動的一

javascript面向物件系列第一——建構函式和原型物件

前面的話   一般地,javascript使用建構函式和原型物件來進行面向物件程式設計,它們的表現與其他面向物件程式語言中的類相似又不同。本文將詳細介紹如何用建構函式和原型物件來建立物件 建構函式   建構函式是用new建立物件時呼叫的函式,與普通唯一的區別是建構函式名應該首字母大寫 func

深入理解javascript作用域系列第一——內部原理

前面的話   javascript擁有一套設計良好的規則來儲存變數,並且之後可以方便地找到這些變數,這套規則被稱為作用域。作用域貌似簡單,實則複雜,由於作用域與this機制非常容易混淆,使得理解作用域的原理更為重要。本文是深入理解javascript作用域系列的第一篇——內部原理   內部原理分成編譯、執

深入理解javascript選擇器API系列第一——4種元素選擇器

前面的話   說到最常見的DOM應用,恐怕就要數取得特定的某個或某組元素的引用了。DOM定義了許多方式來選取元素,包括getElementById()、getElementsByTagName()、getElementsByName()和document.all4種。接下來,將對這4種方法進行詳細介紹

剖析Elasticsearch集群系列第一 Elasticsearch的存儲模型和讀寫操作

推薦 arch 變更 git 排序。 _id 包含 doc 現在 剖析Elasticsearch集群系列涵蓋了當今最流行的分布式搜索引擎Elasticsearch的底層架構和原型實例。 本文是這個系列的第一篇,在本文中,我們將討論的Elasticsearch的底層存儲模型及

阿里雲端渲染系列-第一:公網方式下的雲端渲染

目 錄 1.文件介紹 12.基本知識點 12.1. 渲染環境 12.2. 常見製作軟體(略) 12.3. 常見渲染器(略) 23.雲產品介紹 23.1. VPC 23.2. VPN 23.3. 高速通道 23.4. ECS 23.5. BCS 23.6. OSS 23.7. NAS 23.8. 塊儲存 24

撩課-Web架構師養成系列第一

前言 Web架構師養成系列共15篇,每週更新一篇,主要分享、探討目前大前端領域(前端、後端、移動端)企業中正在用的各種成熟的、新的技術。部分文章也會分析一些框架的底層實現,讓我們做到知其然知其所以然。本篇文章閱讀需要時長:約15分鐘 一、ECMAScript 6/7/8簡介 ECMAScrip

深入理解閉包系列第一——到底什麼才是閉包

前面的話   閉包已經成為近乎神話的概念,它非常重要又難以掌握,而且還難以定義。本文就從閉包的定義說開去 古老定義   閉包(closure),是指函式變數可以儲存在函式作用域內,因此看起來是函式將變數“包裹”了起來   那這樣說來,包含變數的函式就是閉包 //按照古老定義,包含變數n的函式

深入理解定時器系列第一——理解setTimeout和setInterval

前面的話   很長時間以來,定時器一直是javascript動畫的核心技術。但是,關於定時器,人們通常只瞭解如何使用setTimeout()和setInterval(),對它們的內在執行機制並不理解,對於與預想不同的實際執行狀況也無法解決。本文將詳細介紹定時器的相關內容 setTimeout()  

深入理解指令碼化CSS系列第一——指令碼化行內樣式

前面的話   指令碼化CSS,通俗點說,就是使用javascript來操作CSS。引入CSS有3種方式:外部樣式,內部樣式和行間樣式。本文將主要介紹指令碼化行間樣式 基本用法   行間樣式又叫內聯樣式,使用HTML的style屬性進行設定 <div style="height: 40px

深入理解this機制系列第一——this的4種繫結規則

前面的話   如果要問javascript中哪兩個知識點容易混淆,作用域查詢和this機制絕對名列前茅。前面的作用域系列已經詳細介紹過作用域的知識。本系列開始將介紹javascript的另一大山脈——this機制。本文是該系列的第一篇——this的4種繫結規則 預設繫結   全域性環境中,this預

深入理解javascript物件系列第二——屬性操作

前面的話   對於物件來說,屬性操作是繞不開的話題。類似於“增刪改查”的基本操作,屬性操作分為屬性查詢、屬性設定、屬性刪除,還包括屬性繼承。本文是物件系列的第二篇——屬性操作 屬性查詢   屬性查詢一般有兩種方法,包括點運算子和方括號運算子 var o = { p: 'Hello Wor

深入理解webkit核心系列第一:如何快速編譯

       webkit自從Apple開發原始碼之後,經過google大力發展,目前webkit已經相當盛行,大量的瀏覽器開發人員對於webkit核心各種疑問隨之而來,小編從08年開始涉足webkit,對於webkit核心知識稍有心得,小編會打造一個系列,對這塊做一個深入

火箭入門GXChain開發系列第一|簡介與執行原理

火箭入門GXChain開發系列第一篇|簡介與執行原理 第一期:智慧合約簡介與執行原理 智慧合約簡介 智慧合約應用場景 智慧合約與dapp 智慧合約執行原理 webassembly虛擬機器 abi檔案與wast檔案 邏輯與持久化儲存(action與table) 智慧合約環境部署 智慧合

玩轉wireshark系列第一-抓取arp包(原創)

本實驗使用的版本是wireshark2.4.7版,開啟軟體,選擇“捕獲”-“選項”。選擇當前連的網,一般選擇流量“起起伏伏”的那個介面。 此時會有海量的資料包,為了便於分析,我們使用過濾器輸入“arp”以篩選出arp報文。選取以下的傳送和接收的報文進行分析,arp一次請求由廣

chromium瀏覽器開發系列第一:如何獲取最新chromium原始碼

轉自:https://my.oschina.net/ghost045/blog/397663 摘要: 前面介紹了原始碼下載,編譯。接下來要介紹一下目錄結構,方便大家以後對架構的瞭解。 附上上兩篇文章地址,方便大家檢視: 下載原始碼 編譯原始碼 上兩篇介紹了下載原始碼和

轉載 解密藍芽mesh系列 | 第一 【關於拓撲】【mesh網路的動機】【以訊息為中心的通訊】【訊息和裝置狀態】

藍芽技術聯盟EMEA技術專案經理Martin Woolley小碼哥前言藍芽技術是享譽全球的品牌之一,也是全世界應用最為普遍的無線通訊技術之一。從2000年到現在,藍芽技術已經廣泛應用於數十億臺裝置。就2016年而言,製造商的藍芽裝置出貨量更是超過30億臺。藍芽的創新步伐從未停止。自面世以來,每一次改進都系統嚴

Java面試系列第一-基本型別與引用型別

 這篇文章總結一下我認為面試中最應該掌握的關於基本型別和引用型別的面試題目。 面試題目1:值傳遞與引用傳遞 對於沒有接觸過C++這類有引用傳遞的Java程式設計師來說,很容易誤將引用型別的引數傳遞理解為引用傳遞,而基本型別的傳遞理解為值傳遞,這是錯誤的。要理解值傳遞與引用傳遞,首先要理清值傳遞、引用