從零開始學 Web 之 BOM(三)offset,scroll,變速動畫函數

你們好,這裏是「 從零開始學 Web 系列教程 」,並在下列地址同步更新......javascript

在這裏我會從 Web 前端零基礎開始,一步步學習 Web 相關的知識點,期間也會分享一些好玩的項目。如今就讓咱們一塊兒進入 Web 前端學習的冒險之旅吧!html

1、直接使用 document 獲取的元素

// 獲取 body
document.body;
// 獲取 title
document.title; // 獲取的是 title 中的值
// 獲取 html
document.documentElement;

一、案例:圖片跟着鼠標移動

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <style>
        img {
            position: absolute;
        }
    </style>
</head>
<body>
<img src="images/Daotin.png" id="im">
<script src="common.js"></script>
<script>
    document.onmousemove = function (ev) {
        // 獲取鼠標的橫縱座標
        my$("im").style.left = ev.clientX + "px";
        my$("im").style.top = ev.clientY + "px";
    }
</script>
</body>
</html>

一、獲取鼠標的橫縱座標在鼠標移動的事件中;前端

二、注意:圖片可以移動,必定要脫標。java


2、offset系列

offsetWidth:獲取元素的寬(加邊框)
offsetHeight:獲取元素的高(加邊框)
offsetLeft:獲取元素距離左邊位置的值
offsetTop:獲取元素距離上邊位置的值

3、scroll 系列

scroll:捲曲git

scrollWidth:若是元素中內容寬度小於元素的寬度,則爲元素的寬度(不含邊框),不然爲元素中內容的實際寬度。
scrollHeight:若是元素中內容高度小於元素的高度,則爲元素的高度(不含邊框),不然爲元素中內容的實際高度。
scrollLeft:元素中的內容往左捲曲出去的距離。(有滾動條的時候)
scrollTop:元素中的內容往上捲曲出去的距離。(有滾動條的時候)

一、封裝獲取 scrollLeft 和 scrollTop 的函數

function getScroll() {
    return {
            left: window.pageXOffset || document.documentElement.scrollLeft || document.body.scrollLeft,
            top: window.pageYOffset || document.documentElement.scrollTop || document.body.scrollTop
    };
}

一、返回的是一個對象,這個對象有兩個自定義屬性 left 和 top ,使用的時候直接使用 getScroll().left 或者 getScroll().top 便可得到瀏覽器滾動條向左向上移動的距離。github

二、之因此用 「||」 操做是由於瀏覽器兼容問題。chrome

4、變速動畫函數

// 變速動畫移動函數
function animation(element, target) {
  clearInterval(element.timeId); // 每次調用函數就清理以前的timeId
  // 判斷當前的位置
  element.timeId = setInterval(function () {
    var current = element.offsetLeft; // 不能使用 element.style.left
    var onestep = (target - current) / 10;
    onestep = onestep > 0 ? Math.ceil(onestep) : Math.floor(onestep);
    current += onestep;
    element.style.left = current + "px";
    // if (Math.abs(current - target) >= onestep) {
    //     element.style.left = current + "px";
    // } else {
    //     clearInterval(timeId);
    //     element.style.left = target + "px";
    // }

    if(target === current) {
      clearInterval(element.timeId);
      return;
    }

    // 測試代碼
    console.log("target="+target+", current="+current+", step="+onestep);
  }, 20);
}

一、Math.ceil() 和 Math.round() 和 Math.floor() 的區別:json

zconsole.log(Math.ceil(11.1)); // 12
console.log(Math.ceil(11.8)); // 12
console.log(Math.ceil(-11.1)); // -11
console.log(Math.ceil(-11.8)); // -11

console.log(Math.round(11.1)); // 11
console.log(Math.round(11.8)); // 12
console.log(Math.round(-11.1)); // -11
console.log(Math.round(-11.8));// -12

console.log(Math.floor(11.1)); // 11
console.log(Math.floor(11.8)); // 11
console.log(Math.floor(-11.1)); // -12
console.log(Math.floor(-11.8)); // -12

二、這裏 onestep 使用向上取整,才能走到終點。瀏覽器

三、這裏就不須要判斷 if (Math.abs(current - target) >= onestep) 了,由於每次走的 onestep 老是愈來愈小,到最後都會變成1,因此不存在走不夠或者超出的狀況。微信

四、定時器中加個 return,能夠防止走到終點,函數還在不停循環的狀況。

一、案例:筋斗雲

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

        #box {
            width: 800px;
            height: 50px;
            margin: 0 auto;
            margin-top: 200px;
            background-color: pink;
            position: relative;
        }

        li {
            float: left;
            list-style-type: none;
            width: 100px;
            height: 30px;
            background-color: #fff;
            margin: 10px;
            cursor: pointer;
            text-align: center;
            font: 700 20px/30px "Microsoft YaHei";
        }

        span {
            position: absolute;
            width: 100px;
            height: 30px;
            background-color: rgba(181, 14, 205, 0.8);
            left: 10px;
            top: 10px;

        }
    </style>
</head>
<body>
<input type="button" value="按鈕" id="btn">

<div id="box">
    <ul>
        <li>1</li>
        <li>2</li>
        <li>3</li>
        <li>4</li>
        <li>5</li>
        <li>6</li>
    </ul>
    <span></span>
</div>

<script src="common.js"></script>
<script>

    // 獲取box元素
    var boxObj = my$("box");

    // 獲取span元素
    var spanObj = boxObj.children[1];

    // 獲取全部li元素
    var liObjs = boxObj.children[0].children;

    // 爲全部的li註冊事件
    for (var i = 0; i < liObjs.length; i++) {
        // 註冊鼠標進入
        liObjs[i].onmouseover = mouseoverHandle;
        // 註冊鼠標點擊
        liObjs[i].onclick = clickHandle;
        // 註冊鼠標出來
        liObjs[i].onmouseout = mouseoutHandle;
    }

    function mouseoverHandle() {
        animationChangeSpeed(spanObj, this.offsetLeft);
    }
    var currentPos = 10;
    function clickHandle() {
        currentPos = this.offsetLeft;
    }
    function mouseoutHandle() {
        animationChangeSpeed(spanObj, currentPos);
    }

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

一、var currentPos = 10; 是由於個人 span 有個 maigin-left:10px,若是是從最左邊開始的話就爲 0。

5、獲取任意元素的任意屬性值

在 window 下有一個方法:window.getComputedStyle(element, string) 能夠獲取一個元素全部的屬性值。

其中第一個參數爲須要獲取的元素;第二個參數爲是否有僞類或者僞樣式。返回值是這個元素全部屬性的對象集合。

當咱們須要什麼屬性的時候,點出來就能夠了。

可是這個方法 IE8 不支持,在 IE8 下有一個屬性 currentStyle, 經過 元素.currentStyle 的方式能夠獲得返回值爲這個元素全部屬性的集合。

兼容代碼:

function getStyle(element, attr) {
    return window.getComputedStyle ?
        window.getComputedStyle(element, null)[attr] :
        element.currentStyle[attr];
}

6、爲變速動畫函數加強

一、增長任意一個屬性值

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

        input {
            margin-top: 10px;
        }

        div {
            position: absolute;
            width: 200px;
            height: 100px;
            background-color: yellowgreen;
            margin-top: 10px;
            /*left: 20px;*/
        }
    </style>
</head>
<body>
<input type="button" value="移動400px" id="btn1">
<input type="button" value="移動800px" id="btn2">
<div id="dv"></div>

<script src="common.js"></script>
<script>
    // 移動400px
    my$("btn1").onclick = function () {
        animation(my$("dv"), "top", 400);

    };
    // 移動800px
    my$("btn2").onclick = function () {
        animation(my$("dv"), "width", 800);

    };

    var timeId = 0;

    // 變速動畫移動函數
    // element --- 任意元素
    // attr ---- 任意屬性名字
    // target ---目標位置
    function animation(element, attr, target) {
        clearInterval(element.timeId); // 每次調用函數就清理以前的timeId
        // 判斷當前的位置
        element.timeId = setInterval(function () {
            var current = parseInt(getStyle(element, attr)); // 獲取任意元素的任意一個屬性值
            var onestep = (target - current) / 10;
            onestep = onestep > 0 ? Math.ceil(onestep) : Math.floor(onestep);
            current += onestep;
            element.style[attr] = current + "px";

            if(target === current) {
                clearInterval(element.timeId);
            }
            // 測試代碼
            console.log("target="+target+", current="+current+", step="+onestep);
        }, 20);
    }
</script>
</body>
</html>

getStyle 函數返回的屬性值是加「px」的因此要加 parseInt 進行處理。

二、增長任意多個屬性值

<body>
<input type="button" value="移動" id="btn">
<div id="dv"></div>

<script src="common.js"></script>
<script>
    my$("btn").onclick = function () {
        animation(my$("dv"), {"left":100,"top":400,"width":400,"height":200});

    };

    var timeId = 0;

    // 變速動畫移動函數
    // element --- 任意元素
    // attr ---- 任意屬性名字
    // target ---目標位置
    function animation(element, json) {
        clearInterval(element.timeId); // 每次調用函數就清理以前的timeId
        // 判斷當前的位置
        element.timeId = setInterval(function () {
            var flag = true;
            for(var attr in json) {
                var current = parseInt(getStyle(element, attr)); // 獲取任意元素的任意一個屬性值
                var target = json[attr];
                var onestep = (target - current) / 10;
                onestep = onestep > 0 ? Math.ceil(onestep) : Math.floor(onestep);
                current += onestep;
                element.style[attr] = current + "px";

                // 保證全部屬性都達到目標才清理定時器
                if(target !== current) {
                    flag = false;
                }
            }
            if (flag) {
                clearInterval(element.timeId);
            }
            // 測試代碼
            console.log("target="+target+", current="+current+", step="+onestep);
        }, 20);
    }
</script>
</body>

一、既然須要多對屬性,很天然的想到 json

二、在移動的時候使用 for in 循環遍歷 json

三、由於每一個屬性達到目標值的次數不一樣,因此須要在全部屬性都到達目標值時才清理定時器。

三、增長回調函數

回調函數:當一個函數做爲參數的時候,這個函數就是回調函數。

做用:增長動畫的次數。

<body>
<input type="button" value="移動" id="btn">
<div id="dv"></div>

<script src="common.js"></script>
<script>
    my$("btn").onclick = function () {
        animation(my$("dv"), {"left":100,"top":400,"width":400,"height":200}, function (){
            animation(my$("dv"), {"left":300,"top":40,"width":140,"height":20}, function (){
                animation(my$("dv"), {"left":50,"top":200,"width":200,"height":100});
            });
        });
    };

    var timeId = 0;

    // 變速動畫移動函數
    // element --- 任意元素
    // attr ---- 任意屬性名字
    // target ---目標位置
    function animation(element, json, fn) {
        clearInterval(element.timeId); // 每次調用函數就清理以前的timeId
        // 判斷當前的位置
        element.timeId = setInterval(function () {
            var flag = true;
            for(var attr in json) {
                var current = parseInt(getStyle(element, attr)); // 獲取任意元素的任意一個屬性值
                var target = json[attr];
                var onestep = (target - current) / 10;
                onestep = onestep > 0 ? Math.ceil(onestep) : Math.floor(onestep);
                current += onestep;
                element.style[attr] = current + "px";

                // 保證全部屬性都達到目標才清理定時器
                if(target !== current) {
                    flag = false;
                }
            }
            if (flag) {
                clearInterval(element.timeId);

                if(fn) {
                    fn();
                }
            }
            // 測試代碼
            //console.log("target="+target+", current="+current+", step="+onestep);
        }, 20);
    }

    // 獲取任意元素的任意一個屬性值
    function getStyle(element, attr) {
        return window.getComputedStyle ?
            window.getComputedStyle(element, null)[attr] :
            element.currentStyle[attr];
    }
</script>
</body>

一、回調函數的調用應該在循環以後,清理定時器以後調用。

二、測試 chrome、firefox 均可以, IE8 出錯,顯示 element.style[attr] = current + "px"; 有問題,暫時不知道什麼緣由。

四、增長透明度和層級

透明度:opacity

層級:z-Index

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <style>
        * {
            margin: 0;
            padding: 0;
        }
        div {
            position: absolute;
            width: 200px;
            height: 100px;
            background-color: yellowgreen;
        }
        input {
            z-index: 1;
            position: absolute;
        }
    </style>
</head>
<body>
<input type="button" value="移動" id="btn">
<div id="dv"></div>

<script src="common.js"></script>
<script>
    my$("btn").onclick = function () {
        animation(my$("dv"),
            {"height": 200, "width":15,"opacity":1,"zIndex":10});
    };

    // 獲取任意元素的任意一個屬性值
    function getStyle(element, attr) {
        return window.getComputedStyle ?
            window.getComputedStyle(element, null)[attr] :
            element.currentStyle[attr];
    }

    // 變速動畫移動函數
    // element --- 任意元素
    // attr ---- 任意屬性名字
    // target ---目標位置
    function animation(element, json, fn) {
        clearInterval(element.timeId); // 每次調用函數就清理以前的timeId
        // 判斷當前的位置
        element.timeId = setInterval(function () {
            var flag = true;
            for (var attr in json) {
                // 判斷attr是否是層級zIndex
                if (attr === "zIndex") {
                    element.style[attr] = json[attr];
                } else if (attr === "opacity") { // 判斷attr是否是透明度opacity
                    // 獲取當前透明度*100,方便計算
                    var current = getStyle(element, attr) * 100;
                    // 目標透明度也*100
                    var target = json[attr] * 100;
                    var onestep = (target - current) / 10;
                    onestep = onestep > 0 ? Math.ceil(onestep) : Math.floor(onestep);
                    current += onestep;
                    element.style[attr] = current / 100;
                } else { // 其餘屬性
                    var current = parseInt(getStyle(element, attr)); // 獲取任意元素的任意一個屬性值
                    var target = json[attr];
                    var onestep = (target - current) / 10;
                    onestep = onestep > 0 ? Math.ceil(onestep) : Math.floor(onestep);
                    current += onestep;
                    element.style[attr] = current + "px";
                }
                // 保證全部屬性都達到目標才清理定時器
                if (target !== current) {
                    flag = false;
                }
            }
            if (flag) {
                clearInterval(element.timeId);

                if (fn) {
                    fn();
                }
            }
            // 測試代碼
            //console.log("target="+target+", current="+current+", step="+onestep);
        }, 20);
    }
</script>
</body>
</html>

一、此爲最終版變速動畫函數。

二、透明度的設置由於是小數計算,因此須要都乘以100,最後再除以100.

三、層級 zIndex 不須要漸變,直接設置便可。

五、案例:手風琴效果

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <style>
        * {
            margin: 0;
            padding: 0;
        }
        div {
            width: 1200px;
            height: 500px;
            margin: 100px 0 0 100px;
            border: 1px solid red;
            overflow: hidden;
        }

        li {
            float: left;
            list-style: none;
            width: 240px;
            height: 500px;
        }

    </style>
</head>
<body>
<div id="dv">
    <ul>
        <li></li>
        <li></li>
        <li></li>
        <li></li>
        <li></li>
    </ul>
</div>

<script src="common.js"></script>
<script>

    var liObjs = my$("dv").getElementsByTagName("li");

    for (var i = 0; i < liObjs.length; i++) {
        liObjs[i].style.backgroundImage = "url(images/dos.jpg)";
        // 鼠標進入
        liObjs[i].onmouseover = mouseoverHandle;
        // 鼠標退出
        liObjs[i].onmouseout = mouseoutHandle;
    }

    function mouseoverHandle() {
        // 先設置全部寬度爲100
        for (var j = 0; j < liObjs.length; j++) {
            animation(liObjs[j], {"width": 100});
        }
        // 再設置當前元素寬度爲800
        animation(this, {"width": 800});
    }

    function mouseoutHandle() {
        for (var j = 0; j < liObjs.length; j++) {
            animation(liObjs[j], {"width": 240});
        }
    }

    // 獲取任意元素的任意一個屬性值
    function getStyle(element, attr) {
        return window.getComputedStyle ?
            window.getComputedStyle(element, null)[attr] :
            element.currentStyle[attr];
    }

    // 變速動畫移動函數
    // element --- 任意元素
    // attr ---- 任意屬性名字
    // target ---目標位置
    function animation(element, json, fn) {
        clearInterval(element.timeId); // 每次調用函數就清理以前的timeId
        // 判斷當前的位置
        element.timeId = setInterval(function () {
            var flag = true;
            for (var attr in json) {
                // 判斷attr是否是層級zIndex
                if (attr === "zIndex") {
                    element.style[attr] = json[attr];
                } else if (attr === "opacity") { // 判斷attr是否是透明度opacity
                    // 獲取當前透明度*100,方便計算
                    var current = getStyle(element, attr) * 100;
                    // 目標透明度也*100
                    var target = json[attr] * 100;
                    var onestep = (target - current) / 10;
                    onestep = onestep > 0 ? Math.ceil(onestep) : Math.floor(onestep);
                    current += onestep;
                    element.style[attr] = current / 100;
                } else { // 其餘屬性
                    var current = parseInt(getStyle(element, attr)); // 獲取任意元素的任意一個屬性值
                    var target = json[attr];
                    var onestep = (target - current) / 10;
                    onestep = onestep > 0 ? Math.ceil(onestep) : Math.floor(onestep);
                    current += onestep;
                    element.style[attr] = current + "px";
                }
                // 保證全部屬性都達到目標才清理定時器
                if (target !== current) {
                    flag = false;
                }
            }
            if (flag) {
                clearInterval(element.timeId);

                if (fn) {
                    fn();
                }
            }
            // 測試代碼
            //console.log("target="+target+", current="+current+", step="+onestep);
        }, 20);
    }
</script>
</body>
</html>

Web前端之巔

相關文章
相關標籤/搜索