成人国产在线小视频_日韩寡妇人妻调教在线播放_色成人www永久在线观看_2018国产精品久久_亚洲欧美高清在线30p_亚洲少妇综合一区_黄色在线播放国产_亚洲另类技巧小说校园_国产主播xx日韩_a级毛片在线免费

資訊專欄INFORMATION COLUMN

JavaScript完美運(yùn)動(dòng)框架的進(jìn)階之旅

Pines_Cheng / 849人閱讀

摘要:運(yùn)動(dòng)框架動(dòng)起來進(jìn)行運(yùn)動(dòng)的節(jié)點(diǎn)定時(shí)器你沒看錯(cuò),就是那么簡(jiǎn)單。直接在定時(shí)器內(nèi)部,判斷到達(dá)目標(biāo)值,清除定時(shí)器就行拉運(yùn)動(dòng)框架運(yùn)動(dòng)終止進(jìn)行運(yùn)動(dòng)的節(jié)點(diǎn)運(yùn)動(dòng)終止條件。

轉(zhuǎn)自個(gè)人博客三省吾身丶丶
原來是JS動(dòng)畫效果,但是我會(huì)過頭再看的時(shí)候,發(fā)現(xiàn)太粗略了,于是重新寫了一篇。
喜歡別只收藏啊,點(diǎn)個(gè)推薦,大兄弟^ ^!

運(yùn)動(dòng)框架的實(shí)現(xiàn)思路

運(yùn)動(dòng),其實(shí)就是在一段時(shí)間內(nèi)改變left、right、width、heightopactiy的值,到達(dá)目的地之后停止。

現(xiàn)在按照以下步驟來進(jìn)行我們的運(yùn)動(dòng)框架的封裝:

勻速運(yùn)動(dòng)。

緩沖運(yùn)動(dòng)。

多物體運(yùn)動(dòng)。

任意值變化。

鏈?zhǔn)竭\(yùn)動(dòng)。

同時(shí)運(yùn)動(dòng)。

(一)勻速運(yùn)動(dòng) 速度動(dòng)畫 運(yùn)動(dòng)基礎(chǔ)

思考:如何讓div動(dòng)起來?
如下:

設(shè)置元素為絕對(duì)定位,只有絕對(duì)定位后,left,top等值才生效。

定時(shí)器的使用(動(dòng)態(tài)改變值),這里使用setInterval()每隔指定的時(shí)間執(zhí)行代碼。

計(jì)時(shí)器setInterval(函數(shù),交互時(shí)間(毫秒)):在執(zhí)行時(shí),從載入頁(yè)面后每隔指定的時(shí)間執(zhí)行代碼。

取消計(jì)時(shí)器clearInterval(函數(shù)) 方法可取消由 setInterval() 設(shè)置的交互時(shí)間。

獲取當(dāng)前的位置,大小等等。offsetLeft(當(dāng)前元素相對(duì)父元素位置)。

速度--物體運(yùn)動(dòng)的快慢

定時(shí)器間隔時(shí)間

改變值的大小

根據(jù)上面的信息我們就可以開始封裝運(yùn)動(dòng)框架創(chuàng)建一個(gè)變化的div了。

/**
 * 運(yùn)動(dòng)框架-1-動(dòng)起來
 * @param {HTMLElement} element 進(jìn)行運(yùn)動(dòng)的節(jié)點(diǎn)
 */
var timer = null;
function startMove(element) {
    timer = setInterval(function () {//定時(shí)器
        element.style.left = element.offsetLeft + 5 + "px";
    }, 30);
}

你沒看錯(cuò),就是那么簡(jiǎn)單。但是等等, what? 怎么不會(huì)停?WTF?

那是因?yàn)槲覀儧]有運(yùn)動(dòng)終止條件。好再還是比較簡(jiǎn)單。直接在定時(shí)器內(nèi)部,判斷到達(dá)目標(biāo)值,清除定時(shí)器就行拉!

/**
 * 運(yùn)動(dòng)框架-2-運(yùn)動(dòng)終止
 * @param {HTMLElement} element 進(jìn)行運(yùn)動(dòng)的節(jié)點(diǎn)
 * @param {number}      iTarget 運(yùn)動(dòng)終止條件。
 */
 var timer = null;
function startMove(element, iTarget) {
    timer = setInterval(function () {
        element.style.left = element.offsetLeft + 5 + "px";
        if (element.offsetLeft === iTarget) {//停止條件
            clearInterval(timer);
        }
    }, 30);
}

就這樣是不是就完成了呢?已經(jīng)ok了呢?
no。還有一些Bug需要處理。

運(yùn)動(dòng)中的Bug

速度取到某些值會(huì)無法停止

到達(dá)位置后再點(diǎn)擊還會(huì)運(yùn)動(dòng)

重復(fù)點(diǎn)擊速度加快

速度無法更改

解決BUG

速度取到某些值會(huì)無法停止(這個(gè)Bug稍后解決,在進(jìn)化過程中自然解決)

把運(yùn)動(dòng)和停止隔開(if/else)

在開始運(yùn)動(dòng)時(shí),關(guān)閉已有定時(shí)器

把速度用變量保存

/**
 * 運(yùn)動(dòng)框架-3-解決Bug
 */
var timer = null;
function startMove(element, iTarget) {
    clearInterval(timer);//在開始運(yùn)動(dòng)時(shí),關(guān)閉已有定時(shí)器
    timer = setInterval(function () {
        var iSpeed = 5;//把速度用變量保存
        //把運(yùn)動(dòng)和停止隔開(if/else)
        if (element.offsetLeft === iTarget) {//結(jié)束運(yùn)動(dòng)
            clearInterval(timer);
        } else {
            element.style.left = element.offsetLeft + iSpeed + "px";
        }
    }, 30);
}

這樣一個(gè)簡(jiǎn)單的運(yùn)動(dòng)框架就完成了。但是,再等等。只能向右走?別急,我們不是定義了把速度變成為了變量嗎?只需要對(duì)它進(jìn)行一些處理就行啦!
var iSpeed = 5;-->

//判斷距離目標(biāo)位置,達(dá)到自動(dòng)變化速度正負(fù)
var iSpeed = 0;
if (element.offsetLeft < iTarget) {
    iSpeed = 5;
} else {
    iSpeed = -5;
}
透明度動(dòng)畫

用變量alpha儲(chǔ)存當(dāng)前透明度。

把上面的element.offsetLeft改成變量alpha

運(yùn)動(dòng)和停止條件部分進(jìn)行更改。如下:

//透明度瀏覽器兼容實(shí)現(xiàn)
if (alpha === iTarget) {
    clearInterval(time);
} else {
    alpha += speed;
    element.style.filter = "alpha(opacity:" + alpha + ")"; //兼容IE
    element.style.opacity = alpha / 100;//標(biāo)準(zhǔn)
}
(二)緩沖動(dòng)畫

思考:怎么樣才是緩沖動(dòng)畫?

應(yīng)該有以下幾點(diǎn):

逐漸變慢,最后停止

距離越遠(yuǎn)速度越大

速度由距離決定

速度=(目標(biāo)值-當(dāng)前值)/縮放系數(shù)

Bug :速度取整(使用Math方法),不然會(huì)閃

向上取整。Math.ceil(iSpeed)

向下取整。Math.floor(iSpeed)

還是對(duì)速度作文章:

/**
 * 運(yùn)動(dòng)框架-4-緩沖動(dòng)畫
 */
function startMove(element, iTarget) {
    clearInterval(timer);
    timer = setInterval(function () {
    //因?yàn)樗俣纫獎(jiǎng)討B(tài)改變,所以必須放在定時(shí)器中
        var iSpeed = (iTarget - element.offsetLeft) / 10; //(目標(biāo)值-當(dāng)前值)/縮放系數(shù)=速度
        iSpeed = iSpeed > 0 ? Math.ceil(iSpeed) : Math.floor(iSpeed); //速度取整
        if (element.offsetLeft === iTarget) {//結(jié)束運(yùn)動(dòng)
            clearInterval(timer);
        } else {
            element.style.left = element.offsetLeft + iSpeed + "px";
        }
    }, 30);
}

做到這里,(速度取到某些值會(huì)無法停止)這個(gè)Bug就自動(dòng)解決啦!

例子:緩沖菜單

跟隨頁(yè)面滾動(dòng)的緩沖側(cè)邊欄
在線演示:codepen

潛在問題目標(biāo)值不是整數(shù)時(shí)

(三)多物體運(yùn)動(dòng)

思考:如何實(shí)現(xiàn)多物體運(yùn)動(dòng)?

單定時(shí)器,存在問題。每個(gè)div一個(gè)定時(shí)器

定時(shí)器作為對(duì)象的屬性

直接使用element.timer把定時(shí)器變成對(duì)象上的一個(gè)屬性。

參數(shù)的傳遞:物體/目標(biāo)值
比較簡(jiǎn)單把上面框架的進(jìn)行如下更改:timer-->element.timer

就這樣就行啦!

(四)任意值變化

咳咳。我們來給div加個(gè)1px的邊框。boder :1px solid #000

然后來試試下面的代碼

setInterval(function () {
    oDiv.style.width = oDiv.offsetWidth - 1 + "px";
}, 30)

嗯,神奇的事情發(fā)生了!what?我設(shè)置的不是寬度在減嗎?怎么尼瑪增加了! 不對(duì)啊,大兄弟。

究竟哪里出了問題呢?

一起找找資料,看看文檔,原來offset這一系列的屬性都會(huì)存在,被其他屬性干擾的問題。

好吧,既然不能用,那么我們就順便把任意值變化給做了吧。

第一步:獲取實(shí)際樣式

使用offsetLeft..等獲取樣式時(shí), 若設(shè)置了邊框, padding, 等可以改變?cè)貙挾雀叨鹊膶傩詴r(shí)會(huì)出現(xiàn)BUG..

通過查找發(fā)現(xiàn)element.currentStyle(attr)可以獲取計(jì)算過之后的屬性。

但是因?yàn)榧嫒菪缘膯栴},需封裝getStyle函數(shù)。(萬惡的IE)

當(dāng)然配合CSS的box-sizing屬性設(shè)為border-box可以達(dá)到一樣的效果 ? (自認(rèn)為,未驗(yàn)證)。

/**
 * 獲取實(shí)際樣式函數(shù)
 * @param   {HTMLElement}   element  需要尋找的樣式的html節(jié)點(diǎn)
 * @param   {String]} attr 在對(duì)象中尋找的樣式屬性
 * @returns {String} 獲取到的屬性
 */
function getStyle(element, attr) {
    //IE寫法
    if (element.currentStyle) {
        return element.currentStyle[attr];
    //標(biāo)準(zhǔn)
    } else {
        return getComputedStyle(element, false)[attr];
    }
}
第二步:改造原函數(shù)

添加參數(shù),attr表示需要改變的屬性值。

更改element.offsetLeftgetStyle(element, attr)

需要注意的是:getStyle(element, attr)不能直接使用,因?yàn)樗@取到的字符串,例:10px。

變量iCurrent使用parseInt(),將樣式轉(zhuǎn)成數(shù)字。

element.style.leftelement.style[attr]。

/**
 * 運(yùn)動(dòng)框架-4-任意值變化
 * @param {HTMLElement} element 運(yùn)動(dòng)對(duì)象
 * @param {string}      attr    需要改變的屬性。
 * @param {number}      iTarget 目標(biāo)值
 */
function startMove(element, attr, iTarget) {
    clearInterval(element.timer);
    element.timer = setInterval(function () {
        //因?yàn)樗俣纫獎(jiǎng)討B(tài)改變,所以必須放在定時(shí)器中
    var iCurrent=0;
    iCurrent = parseInt(getStyle(element, attr));//實(shí)際樣式大小
        var iSpeed = (iTarget - iCurrent) / 10; //(目標(biāo)值-當(dāng)前值)/縮放系數(shù)=速度
        iSpeed = iSpeed > 0 ? Math.ceil(iSpeed) : Math.floor(iSpeed); //速度取整
        if (iCurrent === iTarget) {//結(jié)束運(yùn)動(dòng)
            clearInterval(element.timer);
        } else {
            element.style[attr] = iCurrent + iSpeed + "px";
        }
    }, 30);
}

試一試,這樣是不是就可以了呢?

還記得上面我們寫的透明度變化嗎? 再試試

果然還是不行, (廢話,你見過透明度有"px"單位的么? - -白眼

第三步:透明度兼容處理

思考:需要對(duì)那些屬性進(jìn)行修改?

判斷attr是不是透明度屬性opacity

對(duì)于速度進(jìn)行處理。

為透明度時(shí),由于獲取到的透明度會(huì)是小數(shù),所以需要 * 100

并且由于計(jì)算機(jī)儲(chǔ)存浮點(diǎn)數(shù)的問題,還需要將小數(shù),進(jìn)行四舍五入為整數(shù)。使用: Math.round(parseFloat(getStyle(element, attr)) * 100)。

否則,繼續(xù)使用默認(rèn)的速度。

對(duì)結(jié)果輸出部分進(jìn)行更改。

判斷是透明度屬性,使用透明度方法

否則,使用使用默認(rèn)的輸出格式。

/**
 * 運(yùn)動(dòng)框架-5-兼容透明度
 * @param {HTMLElement} element 運(yùn)動(dòng)對(duì)象
 * @param {string}      attr    需要改變的屬性。
 * @param {number}      iTarget 目標(biāo)值
 */
function startMove(element, attr, iTarget) {
    clearInterval(element.timer);
    element.timer = setInterval(function () {
        //因?yàn)樗俣纫獎(jiǎng)討B(tài)改變,所以必須放在定時(shí)器中
        var iCurrent = 0;
        if (attr === "opacity") { //為透明度時(shí)執(zhí)行。
            iCurrent = Math.round(parseFloat(getStyle(element, attr)) * 100);
        } else { //默認(rèn)情況
            iCurrent = parseInt(getStyle(element, attr)); //實(shí)際樣式大小
        }
        var iSpeed = (iTarget - iCurrent) / 10; //(目標(biāo)值-當(dāng)前值)/縮放系數(shù)=速度
        iSpeed = iSpeed > 0 ? Math.ceil(iSpeed) : Math.floor(iSpeed); //速度取整
        if (iCurrent === iTarget) {//結(jié)束運(yùn)動(dòng)
            clearInterval(element.timer);
        } else {
            if (attr === "opacity") { //為透明度時(shí),執(zhí)行
                element.style.filter = "alpha(opacity:" + (iCurrent + iSpeed) + ")"; //IE
                element.style.opacity = (iCurrent + iSpeed) / 100; //標(biāo)準(zhǔn)
            } else { //默認(rèn)
                element.style[attr] = iCurrent + iSpeed + "px";
            }
        }
    }, 30);
}

到這里,這個(gè)運(yùn)動(dòng)框架就基本上完成了。但是,我們是追求完美的不是嗎?

繼續(xù)進(jìn)化!

(五)鏈?zhǔn)絼?dòng)畫

鏈?zhǔn)絼?dòng)畫:顧名思義,就是在該次運(yùn)動(dòng)停止時(shí),開始下一次運(yùn)動(dòng)。

如何實(shí)現(xiàn)呢?

使用回調(diào)函數(shù):運(yùn)動(dòng)停止時(shí),執(zhí)行函數(shù)

添加func形參(回調(diào)函數(shù))。

在當(dāng)前屬性到達(dá)目的地時(shí)iCurrent === iTarget,判斷是否有回調(diào)函數(shù)存在,有則執(zhí)行。

if (iCurrent === iTarget) {//結(jié)束運(yùn)動(dòng)
    clearInterval(element.timer);
    if (func) {
        func();//回調(diào)函數(shù)
    }
}

good,鏈?zhǔn)絼?dòng)畫完成!距離完美還差一步!

(六)同時(shí)運(yùn)動(dòng)

思考:如何實(shí)現(xiàn)同時(shí)運(yùn)動(dòng)?

使用JSON傳遞多個(gè)值

使用for in循環(huán),遍歷屬性,與值。

定時(shí)器問題!(運(yùn)動(dòng)提前停止)

在循環(huán)外設(shè)置變量,假設(shè)所有的值都到達(dá)了目的值為true

在循環(huán)中檢測(cè)是否到達(dá)目標(biāo)值,若沒有值未到則為false

在循環(huán)結(jié)束后,檢測(cè)是否全部達(dá)到目標(biāo)值.是則清除定時(shí)器

實(shí)現(xiàn):

刪除attriTarget兩個(gè)形參,改為json

在函數(shù)開始時(shí),設(shè)置一個(gè)標(biāo)記var flag = true; //假設(shè)所有運(yùn)動(dòng)到達(dá)終點(diǎn).

在定時(shí)器內(nèi)使用for in,遍歷屬性與目標(biāo),改寫原來的attriTarget,為json的屬性與值

修改運(yùn)動(dòng)終止條件,只有每一項(xiàng)的實(shí)際屬性值iCurrent,等于目標(biāo)值json[attr]時(shí),flag才為true。清除定時(shí)器,判斷是否回調(diào)。

否則,繼續(xù)執(zhí)行代碼,直到所有屬性值等于目標(biāo)值。

完美運(yùn)動(dòng)框架
/**
 * 獲取實(shí)際樣式函數(shù)
 * @param   {HTMLElement}   element  需要尋找的樣式的html節(jié)點(diǎn)
 * @param   {String]} attr 在對(duì)象中尋找的樣式屬性
 * @returns {String} 獲取到的屬性
 */
function getStyle(element, attr) {
    //IE寫法
    if (element.currentStyle) {
        return element.currentStyle[attr];
        //標(biāo)準(zhǔn)
    } else {
        return getComputedStyle(element, false)[attr];
    }
}
/**
 * 完美運(yùn)動(dòng)框架
 * @param {HTMLElement} element 運(yùn)動(dòng)對(duì)象
 * @param {JSON}        json    屬性:目標(biāo)值      
 *   @property {String} attr    屬性值
 *   @config   {Number} target  目標(biāo)值
 * @param {function}    func    可選,回調(diào)函數(shù),鏈?zhǔn)絼?dòng)畫。
 */
function startMove(element, json, func) {
    var flag = true; //假設(shè)所有運(yùn)動(dòng)到達(dá)終點(diǎn).
    clearInterval(element.timer);
    element.timer = setInterval(function () {
        for (var attr in json) {
            //1.取當(dāng)前的屬性值。
            var iCurrent = 0;
            if (attr === "opacity") { //為透明度時(shí)執(zhí)行。
                iCurrent = Math.round(parseFloat(getStyle(element, attr)) * 100);
            } else { //默認(rèn)情況
                iCurrent = parseInt(getStyle(element, attr)); //實(shí)際樣式大小
            }
            //2.算運(yùn)動(dòng)速度,動(dòng)畫緩沖效果
            var iSpeed = (json[attr] - iCurrent) / 10; //(目標(biāo)值-當(dāng)前值)/縮放系數(shù)=速度
            iSpeed = iSpeed > 0 ? Math.ceil(iSpeed) : Math.floor(iSpeed); //速度取整

            //3.未到達(dá)目標(biāo)值時(shí),執(zhí)行代碼 
            if (iCurrent != json[attr]) {
                flag = false; //終止條件
                if (attr === "opacity") { //為透明度時(shí),執(zhí)行
                    element.style.filter = "alpha(opacity:" + (iCurrent + iSpeed) + ")"; //IE
                    element.style.opacity = (iCurrent + iSpeed) / 100; //標(biāo)準(zhǔn)
                } else { //默認(rèn)
                    element.style[attr] = iCurrent + iSpeed + "px";
                }
            } else {
                flag = true;
            }
            //4. 運(yùn)動(dòng)終止,是否回調(diào)
            if (flag) {
                clearInterval(element.timer);
                if (func) {
                    func();
                }
            }
        }
    }, 30);
}
運(yùn)動(dòng)框架總結(jié)

運(yùn)動(dòng)框架演變過程

框架 變化
startMove(element) 運(yùn)動(dòng)
startMove(element,iTarget) 勻速-->緩沖-->多物體
startMove(element,attr,iTargrt) 任意值
startMove(element,attr,iTargrt,func) 鏈?zhǔn)竭\(yùn)動(dòng)
startMove(element,json,func) 多值(同時(shí))-->完美運(yùn)動(dòng)框架

文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請(qǐng)注明本文地址:http://systransis.cn/yun/86158.html

相關(guān)文章

  • javascript完美運(yùn)動(dòng)

    摘要:在這個(gè)完美運(yùn)動(dòng)框架中,我們可以只讓一個(gè)物體的一個(gè)屬性運(yùn)動(dòng),可以鏈?zhǔn)秸{(diào)用,也可以幾個(gè)屬性同時(shí)運(yùn)動(dòng)。能解決我們項(xiàng)目中遇到的大部分運(yùn)動(dòng)。運(yùn)動(dòng)框架演變過程運(yùn)動(dòng)實(shí)現(xiàn)留言板的例子完美運(yùn)動(dòng)運(yùn)動(dòng),高度展開發(fā)布 前面的運(yùn)動(dòng),每次只能改一個(gè)值,你改div的width的時(shí)候,就不能改div的高度,改高度的時(shí)候就不能改寬度,如果我的運(yùn)動(dòng)想同時(shí)改寬度和高度,怎么實(shí)現(xiàn)?在這里我們把屬性和目標(biāo)值用json實(shí)現(xiàn)。在這...

    BenCHou 評(píng)論0 收藏0
  • 【搶先領(lǐng)】《React 學(xué)習(xí)之道》我們翻譯了一本最簡(jiǎn)單,且最實(shí)用 React 實(shí)戰(zhàn)教程……

    摘要:學(xué)習(xí)之道簡(jiǎn)體中文版通往實(shí)戰(zhàn)大師之旅掌握最簡(jiǎn)單,且最實(shí)用的教程。前言學(xué)習(xí)之道這本書使用路線圖中的精華部分用于傳授,并將其融入一個(gè)獨(dú)具吸引力的真實(shí)世界的具體代碼實(shí)現(xiàn)。完美展現(xiàn)了的優(yōu)雅。膜拜的學(xué)習(xí)之道是必讀的一本書。 《React 學(xué)習(xí)之道》The Road to learn React (簡(jiǎn)體中文版) 通往 React 實(shí)戰(zhàn)大師之旅:掌握 React 最簡(jiǎn)單,且最實(shí)用的教程。 showIm...

    oneasp 評(píng)論0 收藏0
  • 大前端2018現(xiàn)在上車還還得及么

    摘要:面向?qū)ο笕筇卣骼^承性多態(tài)性封裝性接口。第五階段封裝一個(gè)屬于自己的框架框架封裝基礎(chǔ)事件流冒泡捕獲事件對(duì)象事件框架選擇框架。核心模塊和對(duì)象全局對(duì)象,,,事件驅(qū)動(dòng),事件發(fā)射器加密解密,路徑操作,序列化和反序列化文件流操作服務(wù)端與客戶端。 第一階段: HTML+CSS:HTML進(jìn)階、CSS進(jìn)階、div+css布局、HTML+css整站開發(fā)、 JavaScript基礎(chǔ):Js基礎(chǔ)教程、js內(nèi)置對(duì)...

    stormgens 評(píng)論0 收藏0
  • 大前端2018現(xiàn)在上車還還得及么

    摘要:面向?qū)ο笕筇卣骼^承性多態(tài)性封裝性接口。第五階段封裝一個(gè)屬于自己的框架框架封裝基礎(chǔ)事件流冒泡捕獲事件對(duì)象事件框架選擇框架。核心模塊和對(duì)象全局對(duì)象,,,事件驅(qū)動(dòng),事件發(fā)射器加密解密,路徑操作,序列化和反序列化文件流操作服務(wù)端與客戶端。 第一階段: HTML+CSS:HTML進(jìn)階、CSS進(jìn)階、div+css布局、HTML+css整站開發(fā)、 JavaScript基礎(chǔ):Js基礎(chǔ)教程、js內(nèi)置對(duì)...

    mylxsw 評(píng)論0 收藏0

發(fā)表評(píng)論

0條評(píng)論

最新活動(dòng)
閱讀需要支付1元查看
<