JS動(dòng)畫的三大家族offset/scroll/client

JS動(dòng)畫的三大家族offset/scroll/client

我們知道,JS動(dòng)畫的三大家族包括:offset/scroll/client竞滓。
本文對(duì)三大家族以及與其相關(guān)的勻速動(dòng)畫講解

offset 家族的組成

offset的中文是:偏移橡娄,補(bǔ)償,位移蹲姐。

js中有一套方便的獲取元素尺寸的辦法就是offset家族阱表。offset家族包括:

  • offsetWidth
  • offsetHight
  • offsetLeft
  • offsetTop
  • offsetParent

下面分別介紹。

1馁菜、offsetWidth 和 offsetHight

offsetWidthoffsetHight:獲取元素的寬高 + padding + border茴扁,不包括margin。如下:

  • offsetWidth = width + padding + border
  • offsetHeight = Height + padding + border

這兩個(gè)屬性火邓,他們綁定在了所有的節(jié)點(diǎn)元素上丹弱。獲取元素之后,只要調(diào)用這兩個(gè)屬性铲咨,我們就能夠獲取元素節(jié)點(diǎn)的寬和高。

舉例如下:

<!DOCTYPE html>
<html>
<head lang="en">
    <meta charset="UTF-8">
    <title></title>
    <style>
        div {
            width: 100px;
            height: 100px;
            padding: 10px;
            border: 10px solid #000;
            margin: 100px;
            background-color: pink;
        }
    </style>
</head>
<body>

<div class="box"></div>
<script>
    var div1 = document.getElementsByTagName("div")[0];

    console.log(div1.offsetHeight);          //打印結(jié)果:140(100+20+20)
    console.log(typeof div1.offsetHeight);   //打印結(jié)果:number

</script>
</body>
</html>

2蜓洪、offsetParent

offsetParent:獲取當(dāng)前元素的定位父元素纤勒。

  • 如果當(dāng)前元素的父元素,有CSS定位(position為absolute隆檀、relative摇天、fixed),那么 offsetParent 獲取的是最近的那個(gè)父元素恐仑。
  • 如果當(dāng)前元素的父元素泉坐,沒有CSS定位(position為absolute、relative裳仆、fixed)腕让,那么offsetParent 獲取的是body

舉例:

<!DOCTYPE html>
<html>
<head lang="en">
    <meta charset="UTF-8">
    <title></title>
</head>
<body>
<div class="box1" style="position: absolute;">
    <div class="box2" style="position: fixed;">
        <div class="box3"></div>
    </div>
</div>
<script>

    var box3 = document.getElementsByClassName("box3")[0];

    console.log(box3.offsetParent);
</script>
</body>
</html>

打印結(jié)果:


3歧斟、offsetLeft 和 offsetTop

offsetLeft:當(dāng)前元素相對(duì)于其定位父元素的水平偏移量纯丸。

offsetTop:當(dāng)前元素相對(duì)于其定位父元素的垂直偏移量。

備注:從父親的 padding 開始算起静袖,父親的 border 不算在內(nèi)觉鼻。

舉例:

<!DOCTYPE html>
<html>
<head lang="en">
    <meta charset="UTF-8">
    <title></title>
    <style>
        .box1 {
            width: 300px;
            height: 300px;
            padding: 100px;
            margin: 100px;
            position: relative;
            border: 100px solid #000;
            background-color: pink;
        }

        .box2 {
            width: 100px;
            height: 100px;
            background-color: red;
            /*position: absolute;*/
            /*left: 10px;*/
            /*top: 10px;*/
        }
    </style>
</head>
<body>
<div class="box1">
    <div class="box2" style="left: 10px"></div>
</div>

<script>

    var box2 = document.getElementsByClassName("box2")[0];

    //offsetTop和offsetLeft
    console.log(box2.offsetLeft);  //100
    console.log(box2.style.left);  //10px


</script>

</body>
</html>

在父盒子有定位的情況下,offsetLeft == style.left(去掉px之后)队橙。注意坠陈,后者只識(shí)別行內(nèi)樣式萨惑。但區(qū)別不僅僅于此,下面會(huì)講仇矾。

offsetLeft 和 style.left 區(qū)別

(1)最大區(qū)別在于:

offsetLeft 可以返回?zé)o定位父元素的偏移量庸蔼。如果父元素中都沒有定位,則body為準(zhǔn)若未。

style.left 只能獲取行內(nèi)樣式朱嘴,如果父元素中都沒有設(shè)置定位,則返回""(意思是粗合,返回空字符串);

(2)offsetTop 返回的是數(shù)字萍嬉,而 style.top 返回的是字符串,而且還帶有單位:px隙疚。

比如:

div.offsetLeft = 100;
div.style.left = "100px";

(3)offsetLeft 和 offsetTop 只讀壤追,而 style.left 和 style.top 可讀寫(只讀是獲取值,可寫是修改值)

總結(jié):我們一般的做法是:用offsetLeft 和 offsetTop 獲取值供屉,用style.left 和 style.top 賦值(比較方便)行冰。理由如下:

  • style.left:只能獲取行內(nèi)式,獲取的值可能為空伶丐,容易出現(xiàn)NaN悼做。
  • offsetLeft:獲取值特別方便,而且是現(xiàn)成的number哗魂,方便計(jì)算肛走。它是只讀的,不能賦值录别。

動(dòng)畫的種類

  • 閃現(xiàn)(基本不用)
  • 勻速(本文重點(diǎn))
  • 緩動(dòng)(后續(xù)重點(diǎn))

簡單舉例如下:(每間隔500ms朽色,向右移動(dòng)盒子100px)

<!DOCTYPE html>
<html>
<head lang="en">
    <meta charset="UTF-8">
    <title></title>
    <style>
        div {
            width: 100px;
            height: 100px;
            background-color: pink;
            position: absolute;
        }
    </style>
</head>
<body>
<button>動(dòng)畫</button>
<div class="box" style="left: 0px"></div>

<script>
    var btn = document.getElementsByTagName("button")[0];
    var div = document.getElementsByTagName("div")[0];

    //1、閃動(dòng)
    //    btn.onclick = function () {
    //        div.style.left = "500px";
    //    }

    //2组题、勻速運(yùn)動(dòng)
    btn.onclick = function () {
        //定時(shí)器葫男,每隔一定的時(shí)間向右走一些
        setInterval(function () {
            console.log(parseInt(div.style.left));
            //動(dòng)畫原理: 盒子未來的位置 = 盒子現(xiàn)在的位置 + 步長;
            //用style.left賦值崔列,用offsetLeft獲取值梢褐。
            div.style.left = div.offsetLeft + 100 + "px";
            //div.style.left = parseInt(div.style.left)+10+"px";  //NaN不能用

        }, 500);
    }
</script>
</body>
</html>

效果如下:

勻速動(dòng)畫的封裝:每間隔30ms,移動(dòng)盒子10px【重要】

代碼如下:

<!DOCTYPE html>
<html>
<head lang="en">
    <meta charset="UTF-8">
    <title></title>
    <style>
        .box1 {
            margin: 0;
            padding: 5px;
            height: 300px;
            background-color: #ddd;
            position: relative;
        }

        button {
            margin: 5px;
        }

        .box2 {
            width: 100px;
            height: 100px;
            background-color: red;
            position: absolute;
            left: 195px;
            top: 40px;
        }

        .box3 {
            width: 100px;
            height: 100px;
            background-color: yellow;
            position: absolute;
            left: 0;
            top: 150px;
        }
    </style>
</head>
<body>
<div class="box1">
    <button>運(yùn)動(dòng)到 left = 200px</button>
    <button>運(yùn)動(dòng)到 left = 400px</button>
    <div class="box2"></div>
    <div class="box3"></div>
</div>

<script>
    var btnArr = document.getElementsByTagName("button");
    var box2 = document.getElementsByClassName("box2")[0];
    var box3 = document.getElementsByClassName("box3")[0];

    //綁定事件
    btnArr[0].onclick = function () {
        //如果有一天我們要傳遞另外一個(gè)盒子峻呕,那么我們的方法就不好用了
        //所以我們要增加第二個(gè)參數(shù)利职,被移動(dòng)的盒子本身。
        animate(box2, 200);
        animate(box3, 200);
    }

    btnArr[1].onclick = function () {
        animate(box2, 400);
        animate(box3, 400);
    }

    //【重要】方法的封裝:每間隔30ms瘦癌,將盒子向右移動(dòng)10px
    function animate(ele, target) {
        //要用定時(shí)器猪贪,先清除定時(shí)器
        //一個(gè)盒子只能有一個(gè)定時(shí)器,這樣的話讯私,不會(huì)和其他盒子出現(xiàn)定時(shí)器沖突
        //我們可以把定時(shí)器本身热押,當(dāng)成為盒子的一個(gè)屬性
        clearInterval(ele.timer);
        //我們要求盒子既能向前又能向后西傀,那么我們的步長就得有正有負(fù)
        //目標(biāo)值如果大于當(dāng)前值取正,目標(biāo)值如果小于當(dāng)前值取負(fù)
        var speed = target > ele.offsetLeft ? 10 : -10;  //speed指的是步長
        ele.timer = setInterval(function () {
            //在執(zhí)行之前就獲取當(dāng)前值和目標(biāo)值之差
            var val = target - ele.offsetLeft;
            ele.style.left = ele.offsetLeft + speed + "px";
            //移動(dòng)的過程中桶癣,如果目標(biāo)值和當(dāng)前值之差如果小于步長拥褂,那么就不能在前進(jìn)了
            //因?yàn)椴介L有正有負(fù),所有轉(zhuǎn)換成絕對(duì)值來比較
            if (Math.abs(val) < Math.abs(speed)) {
                ele.style.left = target + "px";
                clearInterval(ele.timer);
            }
        }, 30)
    }
</script>
</body>
</html>

實(shí)現(xiàn)的效果:

上方代碼中的方法封裝牙寞,可以作為一個(gè)模板步驟饺鹃,要記住。其實(shí)间雀,這個(gè)封裝的方法悔详,寫成下面這樣,會(huì)更嚴(yán)謹(jǐn)惹挟,更容易理解:(將if語句進(jìn)行了改進(jìn))

    //【重要】方法的封裝:每間隔30ms茄螃,將盒子向右移動(dòng)10px
    function animate(ele, target) {
        //要用定時(shí)器,先清除定時(shí)器
        //一個(gè)盒子只能有一個(gè)定時(shí)器连锯,這樣的話归苍,不會(huì)和其他盒子出現(xiàn)定時(shí)器沖突
        //我們可以把定時(shí)器本身,當(dāng)成為盒子的一個(gè)屬性
        clearInterval(ele.timer);
        //我們要求盒子既能向前又能向后运怖,那么我們的步長就得有正有負(fù)
        //目標(biāo)值如果大于當(dāng)前值取正拼弃,目標(biāo)值如果小于當(dāng)前值取負(fù)
        var speed = target > ele.offsetLeft ? 10 : -10;  //speed指的是步長
        ele.timer = setInterval(function () {
            //在執(zhí)行之前就獲取當(dāng)前值和目標(biāo)值之差
            var val = target - ele.offsetLeft;

            //移動(dòng)的過程中,如果目標(biāo)值和當(dāng)前值之差如果小于步長摇展,那么就不能在前進(jìn)了
            //因?yàn)椴介L有正有負(fù)肴敛,所有轉(zhuǎn)換成絕對(duì)值來比較
            if (Math.abs(val) < Math.abs(speed)) {  //如果val小于步長,則直接到達(dá)目的地吗购;否則,每次移動(dòng)一個(gè)步長
                ele.style.left = target + "px";
                clearInterval(ele.timer);
            } else {
                ele.style.left = ele.offsetLeft + speed + "px";
            }
        }, 30)
    }

scroll 相關(guān)屬性

window.onscroll() 方法

當(dāng)我們用鼠標(biāo)滾輪砸狞,滾動(dòng)網(wǎng)頁的時(shí)候捻勉,會(huì)觸發(fā) window.onscroll() 方法。效果如下:(注意看控制臺(tái)的打印結(jié)果)

如果你需要做滾動(dòng)監(jiān)聽刀森,可以使用這個(gè)方法踱启。

我們來看看和 scroll 相關(guān)的有哪些屬性。

1研底、ScrollWidth 和 scrollHeight

ScrollWidthscrollHeight:獲取元素整個(gè)滾動(dòng)區(qū)域的寬埠偿、高。包括 width 和 padding榜晦,不包括 border和margin冠蒋。

注意

scrollHeight 的特點(diǎn)是:如果內(nèi)容超出了盒子,scrollHeight為內(nèi)容的高(包括超出的內(nèi)容)乾胶;如果不超出抖剿,scrollHeight為盒子本身的高度朽寞。ScrollWidth同理。

<!DOCTYPE html>
<html>
<head lang="en">
    <meta charset="UTF-8">
    <title></title>
    <style>
        div {
            width: 100px;
            height: 100px;
            padding: 10px;
            margin: 3px;
            border: 8px solid red;
        }
    </style>
</head>
<body>

<div class="box">
    靜斩郎,能寒窗苦守脑融;動(dòng),能點(diǎn)石成金缩宜。
    靜肘迎,能寒窗苦守;動(dòng)锻煌,能點(diǎn)石成金妓布。
    靜,能寒窗苦守炼幔;動(dòng)秋茫,能點(diǎn)石成金。
    靜乃秀,能寒窗苦守肛著;動(dòng),能點(diǎn)石成金跺讯。
    靜枢贿,能寒窗苦守;動(dòng)刀脏,能點(diǎn)石成金局荚。
    靜,能寒窗苦守愈污;動(dòng)耀态,能點(diǎn)石成金。
</div>
<script>

    var div = document.getElementsByTagName("div")[0];

    // `scrollHeight` 的特點(diǎn)是:如果內(nèi)容超出了盒子暂雹,`scrollHeight`為內(nèi)容的高(包括超出的內(nèi)容)首装;如果不超出,`scrollHeight`為盒子本身的高度杭跪。
    //IE8以下(不包括IE8)仙逻,為盒子本身內(nèi)容的高度。
    console.log(div.scrollWidth);
    console.log(div.scrollHeight);

</script>
</body>
</html>

打印結(jié)果:


2涧尿、scrollTop 和 scrollLeft

  • scrollLeft:獲取水平滾動(dòng)條滾動(dòng)的距離系奉。
  • scrollTop:獲取垂直滾動(dòng)條滾動(dòng)的距離。

實(shí)戰(zhàn)經(jīng)驗(yàn)

當(dāng)某個(gè)元素滿足scrollHeight - scrollTop == clientHeight時(shí)姑廉,說明垂直滾動(dòng)條滾動(dòng)到底了缺亮。

當(dāng)某個(gè)元素滿足scrollWidth - scrollLeft == clientWidth時(shí),說明水平滾動(dòng)條滾動(dòng)到底了庄蹋。

這個(gè)實(shí)戰(zhàn)經(jīng)驗(yàn)非常有用瞬内,可以用來判斷用戶是否已經(jīng)將內(nèi)容滑動(dòng)到底了迷雪。比如說,有些場景下虫蝶,希望用戶能夠看完“長長的活動(dòng)規(guī)則”章咧,才允許觸發(fā)接下來的表單操作。

scrollTop 的兼容性

如果要獲取頁面滾動(dòng)的距離能真,scrollTop 這個(gè)屬性的寫法要注意兼容性赁严,如下。

(1)如果文檔沒有 DTD 聲明粉铐,寫法為:

    document.body.scrollTop

在沒有 DTD 聲明的情況下疼约,要求是這種寫法,chrome瀏覽器才能認(rèn)出來蝙泼。

(2)如果文檔有 DTD 聲明程剥,寫法為:

   document.documentElement.scrollTop

在有 DTD 聲明的情況下,要求是這種寫法汤踏,IE6织鲸、7、8才能認(rèn)出來溪胶。

綜合上面這兩個(gè)搂擦,就誕生了一種兼容性的寫法:

    document.body.scrollTop || document.documentElement.scrollTop //方式一

    document.body.scrollTop + document.documentElement.scrollTop  //方式二

另外還有一種兼容性的寫法:window.pageYOffsetwindow.pageXOffset。這種寫法無視DTD的聲明哗脖。這種寫法支持的瀏覽器版本是:火狐/谷歌/ie9+瀑踢。

綜合上面的幾種寫法,為了兼容才避,不管有沒有DTD橱夭,最終版的兼容性寫法:

    window.pageYOffset || document.body.scrollTop || document.documentElement.scrollTop;

判斷是否已經(jīng) DTD 聲明

方法如下:

    document.compatMode === "CSS1Compat"   // 已聲明
    document.compatMode === "BackCompat"   // 未聲明

將 scrollTop 和 scrollLeft 進(jìn)行封裝

這里,我們將 scrollTop 和 scrollLeft 封裝為一個(gè)方法桑逝,名叫scroll()徘钥,返回值為 一個(gè)對(duì)象。以后就直接調(diào)用scroll().topscroll().left就好肢娘。

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

<html>
<head lang="en">
    <meta charset="UTF-8">
    <title></title>
    <style>
        body {
            height: 6000px;
            width: 5000px;
        }
    </style>
</head>
<body>

<script>

    //需求:封裝一個(gè)兼容的scroll().返回的是對(duì)象,用scroll().top獲取scrollTop舆驶,用scroll().left獲取scrollLeft

    window.onscroll = function () {
//        var myScroll = scroll();
//        myScroll.top;
        console.log(scroll().top);
        console.log(scroll().left);
    }

    //函數(shù)封裝(簡單封裝橱健,實(shí)際工作使用)
    function scroll() {
        return { //此函數(shù)的返回值是對(duì)象
            top: window.pageYOffset || document.body.scrollTop || document.documentElement.scrollTop,
            left: window.pageXOffset || document.body.scrollLeft || document.documentElement.scrollLeft
        }
    }
</script>
</body>
</html>

上方代碼中,函數(shù)定義的那部分就是要封裝的代碼沙廉。

另外還有一種比較麻煩的封裝方式:(僅供參考)

function scroll() {  // 開始封裝自己的scrollTop
    if(window.pageYOffset !== undefined) {  // ie9+ 高版本瀏覽器
        // 因?yàn)?window.pageYOffset 默認(rèn)的是  0  所以這里需要判斷
        return {
            left: window.pageXOffset,
            top: window.pageYOffset
        }
    }
    else if(document.compatMode === "CSS1Compat") {    // 標(biāo)準(zhǔn)瀏覽器   來判斷有沒有聲明DTD
        return {
            left: document.documentElement.scrollLeft,
            top: document.documentElement.scrollTop
        }
    }
    return {   // 未聲明 DTD
        left: document.body.scrollLeft,
        top: document.body.scrollTop
    }
}

獲取 html 文檔的方法

獲取title拘荡、body、head撬陵、html標(biāo)簽的方法如下:

  • document.title 文檔標(biāo)題珊皿;
  • document.head 文檔的頭標(biāo)簽
  • document.body 文檔的body標(biāo)簽网缝;
  • document.documentElement (這個(gè)很重要)。

document.documentElement表示文檔的html標(biāo)簽蟋定。也就是說粉臊,基本結(jié)構(gòu)當(dāng)中的 html 標(biāo)簽而是通過document.documentElement訪問的,并不是通過 document.html 去訪問的驶兜。

scrollTop 舉例:固定導(dǎo)航欄

完整版代碼實(shí)現(xiàn):

(1)index.html:

<!DOCTYPE html>
<html>
<head lang="en">
    <meta charset="UTF-8">
    <title></title>
    <style>
        * {
            margin: 0;
            padding: 0
        }

        img {
            vertical-align: top;
        }

        .main {
            margin: 0 auto;
            width: 1000px;
            margin-top: 10px;

        }

        #Q-nav1 {
            overflow: hidden;
        }

        .fixed {
            position: fixed;
            top: 0;
            left: 0;
        }
    </style>

    <!--引入工具js-->
    <script src="tools.js"></script>
    <script>
        window.onload = function () {
            //需求1:當(dāng)我們滾動(dòng)界面的時(shí)候扼仲,被卷曲的頭部如果超過第二個(gè)盒子距離頂部的位置,那么直接給第二個(gè)盒子加類名.fixed
            //需求2:當(dāng)我們滾動(dòng)界面的時(shí)候抄淑,被卷曲的頭部如果小于第二個(gè)盒子距離頂部的位置屠凶,那么直接給第二個(gè)盒子取消類名.fixed

            //1.老三步。
            var topDiv = document.getElementById("top");
            var height = topDiv.offsetHeight;
            var middle = document.getElementById("Q-nav1");
            var main = document.getElementById("main");

            window.onscroll = function () {
                //2.判斷 肆资,被卷曲的頭部的大小
                if (scroll().top > height) {
                    //3.滿足條件添加類矗愧,否則刪除類
                    middle.className += " fixed";
                    //第二個(gè)盒子也要占位置,為了避免重疊郑原,我們給第三個(gè)盒子一個(gè)上padding的空間唉韭,把這個(gè)空間留給第二個(gè)盒子
                    main.style.paddingTop = middle.offsetHeight + "px";
                } else {
                    middle.className = "";
                    //清零
                    main.style.paddingTop = 0;
                }
            }

        }
    </script>
</head>
<body>
<div class="top" id="top">
    <img src="images/top.png" alt=""/>
</div>
<div id="Q-nav1">
    <img src="images/nav.png" alt=""/>
</div>
<div class="main" id="main">
    <img src="images/main.png" alt=""/>
</div>
</body>
</html>

上方代碼中,有一個(gè)技巧:

main.style.paddingTop = middle.offsetHeight + "px";

仔細(xì)看注釋就好颤专。

(2)tools.js:

/**
 * Created by smyhvae on 2018/02/03.
 */
function scroll() {  // 開始封裝自己的scrollTop
    if (window.pageYOffset !== undefined) {  // ie9+ 高版本瀏覽器
        // 因?yàn)?window.pageYOffset 默認(rèn)的是  0  所以這里需要判斷
        return {
            left: window.pageXOffset,
            top: window.pageYOffset
        }
    }
    else if (document.compatMode === "CSS1Compat") {    // 標(biāo)準(zhǔn)瀏覽器   來判斷有沒有聲明DTD
        return {
            left: document.documentElement.scrollLeft,
            top: document.documentElement.scrollTop
        }
    }
    return {   // 未聲明 DTD
        left: document.body.scrollLeft,
        top: document.body.scrollTop
    }
}

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

image

緩動(dòng)動(dòng)畫

三個(gè)函數(shù)

緩慢動(dòng)畫里纽哥,我們要用到三個(gè)函數(shù),這里先列出來:

  • Math.ceil() 向上取整
  • Math.floor() 向下取整
  • Math.round(); 四舍五入

緩動(dòng)動(dòng)畫的原理

緩動(dòng)動(dòng)畫的原理就是:在移動(dòng)的過程中栖秕,步長越來越小春塌。
設(shè)置步長為:目標(biāo)位置和盒子當(dāng)前位置的十分之一。用公式表達(dá)簇捍,即:

    盒子位置 = 盒子本身位置 + (目標(biāo)位置 - 盒子本身位置)/ 10只壳;

代碼舉例:

<!DOCTYPE html>
<html>
<head lang="en">
    <meta charset="UTF-8">
    <title></title>
    <style>
        div {
            width: 100px;
            height: 100px;
            background-color: pink;
            position: absolute;
        }
    </style>
</head>
<body>
<button>運(yùn)動(dòng)到left = 400px</button>
<div></div>

<script>

    var btn = document.getElementsByTagName("button")[0];
    var div = document.getElementsByTagName("div")[0];

    btn.onclick = function () {
        setInterval(function () {
            //動(dòng)畫原理:盒子未來的位置 = 盒子當(dāng)前的位置+步長
            div.style.left = div.offsetLeft + (400 - div.offsetLeft) / 10 + "px";
        }, 30);
    }

</script>
</body>
</html>

效果:

image

緩慢動(dòng)畫的封裝(解決四舍五入的問題)

我們發(fā)現(xiàn)一個(gè)問題,上圖中的盒子最終并沒有到達(dá)400px的位置暑塑,而是只到了396.04px就停住了:

image

原因是:JS在取整的運(yùn)算時(shí)吼句,進(jìn)行了四舍五入。

我們把打印396.04px這個(gè)left值打印出來看看:

image

我么發(fā)現(xiàn)事格,通過div.style.left獲取的值是精確的惕艳,通過div.offsetLeft獲取的left值會(huì)進(jìn)行四舍五入。

此時(shí)驹愚,我們就要用到取整的函數(shù)了远搪。

通過對(duì)緩動(dòng)動(dòng)畫進(jìn)行封裝,完整版的代碼實(shí)現(xiàn)如下:

<!DOCTYPE html>
<html>
<head lang="en">
    <meta charset="UTF-8">
    <title></title>
    <style>
        div {
            width: 100px;
            height: 100px;
            background-color: pink;
            position: absolute;
            left: 0;
        }
    </style>
</head>
<body>
<button>運(yùn)動(dòng)到200</button>
<button>運(yùn)動(dòng)到400</button>
<div></div>

<script>

    var btn = document.getElementsByTagName("button");
    var div = document.getElementsByTagName("div")[0];

    btn[0].onclick = function () {
        animate(div, 200);
    }

    btn[1].onclick = function () {
        animate(div, 400);
    }

    //緩動(dòng)動(dòng)畫封裝
    function animate(ele, target) {
        //要用定時(shí)器逢捺,先清定時(shí)器
        //一個(gè)蘿卜一個(gè)坑兒谁鳍,一個(gè)元素對(duì)應(yīng)一個(gè)定時(shí)器
        clearInterval(ele.timer);
        //定義定時(shí)器
        ele.timer = setInterval(function () {
            //獲取步長
            //步長應(yīng)該是越來越小的,緩動(dòng)的算法。
            var step = (target - ele.offsetLeft) / 10;
            //對(duì)步長進(jìn)行二次加工(大于0向上取整,小于0向下取整)
            //達(dá)到的效果是:最后10像素的時(shí)候都是1像素1像素的向目標(biāo)位置移動(dòng)倘潜,就能夠到達(dá)指定位置绷柒。
            step = step > 0 ? Math.ceil(step) : Math.floor(step);
            //動(dòng)畫原理: 目標(biāo)位置 = 當(dāng)前位置 + 步長
            ele.style.left = ele.offsetLeft + step + "px";
            console.log(step);
            //檢測緩動(dòng)動(dòng)畫有沒有停止
            console.log("smyhvae");
            if (Math.abs(target - ele.offsetLeft) <= Math.abs(step)) {
                //處理小數(shù)賦值
                ele.style.left = target + "px";
                clearInterval(ele.timer);
            }
        }, 30);
    }

</script>
</body>
</html>

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

image

client 家族的組成

clientWidth 和 clientHeight

元素調(diào)用時(shí):

  • clientWidth:獲取元素的可見寬度(width + padding)。
  • clientHeight:獲取元素的可見高度(height + padding)涮因。

body/html 調(diào)用時(shí):

  • clientWidth:獲取網(wǎng)頁可視區(qū)域?qū)挾取?/li>
  • clientHeight:獲取網(wǎng)頁可視區(qū)域高度废睦。

聲明

  • clientWidthclientHeight 屬性是只讀的,不可修改蕊退。
  • clientWidthclientHeight 的值都是不帶 px 的郊楣,返回的都是一個(gè)數(shù)字,可以直接進(jìn)行計(jì)算瓤荔。

clientX 和 clientY

event調(diào)用:

  • clientX:鼠標(biāo)距離可視區(qū)域左側(cè)距離净蚤。
  • clientY:鼠標(biāo)距離可視區(qū)域上側(cè)距離。

clientTop 和 clientLeft

  • clientTop:盒子的上border输硝。
  • clientLeft:盒子的左border今瀑。

三大家族 offset/scroll/client 的區(qū)別

區(qū)別1:寬高

  • offsetWidth = width + padding + border
  • offsetHeight = height + padding + border
  • scrollWidth = 內(nèi)容寬度(不包含border)
  • scrollHeight = 內(nèi)容高度(不包含border)
  • clientWidth = width + padding
  • clientHeight = height + padding

區(qū)別2:上左

offsetTop/offsetLeft:

  • 調(diào)用者:任意元素。(盒子為主)
  • 作用:距離父系盒子中帶有定位的距離点把。

scrollTop/scrollLeft:

  • 調(diào)用者:document.body.scrollTop(window調(diào)用)(盒子也可以調(diào)用橘荠,但必須有滾動(dòng)條)
  • 作用:瀏覽器無法顯示的部分(被卷去的部分)。

clientY/clientX:

  • 調(diào)用者:event
  • 作用:鼠標(biāo)距離瀏覽器可視區(qū)域的距離(左郎逃、上)哥童。

函數(shù)封裝:獲取瀏覽器的寬高(可視區(qū)域)

函數(shù)封裝如下:

//函數(shù)封裝:獲取屏幕可視區(qū)域的寬高
function client() {
    if (window.innerHeight !== undefined) {
        //ie9及其以上的版本的寫法
        return {
            "width": window.innerWidth,
            "height": window.innerHeight
        }
    } else if (document.compatMode === "CSS1Compat") {
        //標(biāo)準(zhǔn)模式的寫法(有DTD時(shí))
        return {
            "width": document.documentElement.clientWidth,
            "height": document.documentElement.clientHeight
        }
    } else {
        //沒有DTD時(shí)的寫法
        return {
            "width": document.body.clientWidth,
            "height": document.body.clientHeight
        }
    }
}

案例:根據(jù)瀏覽器的可視寬度,給定不同的背景的色褒翰。

PS:這個(gè)可以用來做響應(yīng)式贮懈。

代碼如下:(需要用到上面的封裝好的方法)

<!DOCTYPE html>
<html>
<head lang="en">
    <meta charset="UTF-8">
    <title></title>
</head>
<body>

<script src="tools.js"></script>
<script>
    //需求:瀏覽器每次更改大小,判斷是否符合某一標(biāo)準(zhǔn)然后給背景上色优训。
    //  // >960紅色朵你,大于640小于960藍(lán)色,小于640綠色揣非。

    window.onresize = fn;  //頁面大小發(fā)生變化時(shí)抡医,執(zhí)行該函數(shù)。
    //頁面加載的時(shí)候直接執(zhí)行一次函數(shù)早敬,確定瀏覽器可視區(qū)域的寬忌傻,給背景上色
    fn();

    //封裝成函數(shù),然后指定的時(shí)候去調(diào)用和綁定函數(shù)名
    function fn() {
        if (client().width > 960) {
            document.body.style.backgroundColor = "red";
        } else if (client().width > 640) {
            document.body.style.backgroundColor = "blue";
        } else {
            document.body.style.backgroundColor = "green";
        }
    }
</script>
</body>
</html>

上當(dāng)代碼中搞监,window.onresize事件指的是:在窗口或框架被調(diào)整大小時(shí)發(fā)生芯勘。各個(gè)事件的解釋如下:

  • window.onscroll 屏幕滑動(dòng)
  • window.onresize 瀏覽器大小變化
  • window.onload 頁面加載完畢
  • div.onmousemove 鼠標(biāo)在盒子上移動(dòng)(注意:不是盒子移動(dòng))

獲取顯示器的分辨率

比如,我的電腦的顯示器分辨率是:1920*1080腺逛。

獲取顯示器的分辨率:

    window.onresize = function () {
        document.title = window.screen.width + "    " + window.screen.height;
    }

顯示效果:

image

上圖中,不管我如何改變?yōu)g覽器的窗口大小,title欄顯示的值永遠(yuǎn)都是我的顯示器分辨率:1920*1080棍矛。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末安疗,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子够委,更是在濱河造成了極大的恐慌荐类,老刑警劉巖,帶你破解...
    沈念sama閱讀 206,378評(píng)論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件茁帽,死亡現(xiàn)場離奇詭異玉罐,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)潘拨,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,356評(píng)論 2 382
  • 文/潘曉璐 我一進(jìn)店門吊输,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人铁追,你說我怎么就攤上這事季蚂。” “怎么了琅束?”我有些...
    開封第一講書人閱讀 152,702評(píng)論 0 342
  • 文/不壞的土叔 我叫張陵扭屁,是天一觀的道長。 經(jīng)常有香客問我涩禀,道長料滥,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 55,259評(píng)論 1 279
  • 正文 為了忘掉前任艾船,我火速辦了婚禮葵腹,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘丽声。我一直安慰自己礁蔗,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,263評(píng)論 5 371
  • 文/花漫 我一把揭開白布雁社。 她就那樣靜靜地躺著浴井,像睡著了一般。 火紅的嫁衣襯著肌膚如雪霉撵。 梳的紋絲不亂的頭發(fā)上磺浙,一...
    開封第一講書人閱讀 49,036評(píng)論 1 285
  • 那天,我揣著相機(jī)與錄音徒坡,去河邊找鬼撕氧。 笑死,一個(gè)胖子當(dāng)著我的面吹牛喇完,可吹牛的內(nèi)容都是我干的伦泥。 我是一名探鬼主播,決...
    沈念sama閱讀 38,349評(píng)論 3 400
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼不脯!你這毒婦竟也來了府怯?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 36,979評(píng)論 0 259
  • 序言:老撾萬榮一對(duì)情侶失蹤防楷,失蹤者是張志新(化名)和其女友劉穎牺丙,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體复局,經(jīng)...
    沈念sama閱讀 43,469評(píng)論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡冲簿,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 35,938評(píng)論 2 323
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了亿昏。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片峦剔。...
    茶點(diǎn)故事閱讀 38,059評(píng)論 1 333
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖龙优,靈堂內(nèi)的尸體忽然破棺而出羊异,到底是詐尸還是另有隱情,我是刑警寧澤彤断,帶...
    沈念sama閱讀 33,703評(píng)論 4 323
  • 正文 年R本政府宣布野舶,位于F島的核電站,受9級(jí)特大地震影響宰衙,放射性物質(zhì)發(fā)生泄漏平道。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,257評(píng)論 3 307
  • 文/蒙蒙 一供炼、第九天 我趴在偏房一處隱蔽的房頂上張望一屋。 院中可真熱鬧,春花似錦袋哼、人聲如沸冀墨。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,262評(píng)論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽诽嘉。三九已至,卻和暖如春弟翘,著一層夾襖步出監(jiān)牢的瞬間虫腋,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,485評(píng)論 1 262
  • 我被黑心中介騙來泰國打工稀余, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留悦冀,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 45,501評(píng)論 2 354
  • 正文 我出身青樓睛琳,卻偏偏與公主長得像盒蟆,于是被迫代替她去往敵國和親踏烙。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,792評(píng)論 2 345

推薦閱讀更多精彩內(nèi)容