JS特效-三大家族-原生封裝

一、首先,我們先了解一下三大家族及其區別(offset/scroll/client)

1.offset

1.1.offsetWidth = width+padding+border;

1.2.offsetHeight = Height+padding+border;

1.3.offsetTop:檢測距離帶有定位的父盒子的上面的距離,返回值不帶有px

1.4.offsetLeft:檢測距離帶有定位的父盒子的左邊的距離,返回值不帶有px

1.5.offsetParent:檢測最近的帶有定位的父盒子的節點,返回值是一個節點。(若父盒子都沒有定位,則返回body)

2.scroll

2.1.scrollWidth = width+padding;

2.2.scrollHeight = Height+padding;如果文字超出了盒子,高度爲超出盒子的內容的高。不超出是盒子本身高度。IE8以下(不包括IE8) 爲盒子本身內容的高度。

2.3.scrollTop:特指網頁被捲去的頭部的高度(這個屬性的獲取有兼容問題,下文將闡述)

2.4.scrollLeft:特指網頁左邊被捲去的寬度(一般不用)

3.client

3.1.clientWidth = width+padding;

3.2.clientHeight = Height+padding;

3.3.clientTop:獲取盒子的上border的寬度

3.4.clientLeft:獲取盒子的左側border的寬度

3.5.clientX:event調用,鼠標距離瀏覽器可視區域的左邊距離

3.6.clientY:event調用,鼠標距離瀏覽器可視區域的頂部距離

二、各種函數封裝(動畫、獲取值)

1.勻速動畫封裝

function animate(ele,target){
        //要用定時器,先清除定時器
        //一個盒子只能有一個定時器,這樣兒的話,不會和其他盒子出現定時器衝突
        //而定時器本身講成爲盒子的一個屬性
        clearInterval(ele.timer);
        //我們要求盒子既能向前又能向後,那麼我們的步長就得有正有負
        //目標值如果大於當前值取正,目標值如果小於當前值取負
        var speed = target>ele.offsetLeft?10:-10;
        ele.timer = setInterval(function () {
            //在執行之前就獲取當前值和目標值之差
            var val = target - ele.offsetLeft;
            ele.style.left = ele.offsetLeft + speed + "px";
            //目標值和當前值只差如果小於步長,那麼就不能在前進了
            //因爲步長有正有負,所有轉換成絕對值來比較
            if(Math.abs(val)<Math.abs(speed)){
                ele.style.left = target + "px";
                clearInterval(ele.timer);
            }
        },30)
    }

2.緩動動畫封裝

function animate(ele,target) {
        //要用定時器,先清定時器
        clearInterval(ele.timer);
        //定義定時器
        ele.timer = setInterval(function () {
            //獲取步長
            //步長應該是越來越小的,緩動的算法。
            var step = (target-ele.offsetLeft)/10;
            //對步長進行二次加工(大於0向上取整,小於0向下取整)
            step = step>0?Math.ceil(step):Math.floor(step);
            //動畫原理: 目標位置 = 當前位置 + 步長
            ele.style.left = ele.offsetLeft + step + "px";
            //檢測緩動動畫有沒有停止
            //console.log(1);
            if(Math.abs(target-ele.offsetLeft)<=Math.abs(step)){
                //處理小數賦值
                ele.style.left = target + "px";
                clearInterval(ele.timer);
            }
        },30);
    }

3.緩動動畫封裝(單個屬性)(這裏有一個獲取元素樣式的封裝函數getStyle,後文將給出)

       //參數變爲3個
        function animate(ele,attr,target){
            //先清定時器
            clearInterval(ele.timer);
            ele.timer = setInterval(function () {
                //四部
                var leader = parseInt(getStyle(ele,attr)) || 0;
                //1.獲取步長
                var step = (target - leader)/10;
                //2.二次加工步長
                step = step>0?Math.ceil(step):Math.floor(step);
                leader = leader + step;
                //3.賦值
                ele.style[attr] = leader + "px";
                 //4.清除定時器
                if(Math.abs(target-leader)<=Math.abs(step)){
                    ele.style[attr] = target + "px";
                    clearInterval(ele.timer);
                }

            },25);
        }

4.緩動動畫封裝(多個屬性,多個屬性將用json來實現)(這裏有一個獲取元素樣式的封裝函數getStyle,後文將給出)

function animate(ele,json){
            //先清定時器
            clearInterval(ele.timer);
            ele.timer = setInterval(function () {
                //開閉原則
                var bool = true;


                //遍歷屬性和值,分別單獨處理json
                //attr == k(鍵)    target == json[k](值)
                for(var k in json){
                    //四部
                    var leader = parseInt(getStyle(ele,k)) || 0;
                    //1.獲取步長
                    var step = (json[k] - leader)/10;
                    //2.二次加工步長
                    step = step>0?Math.ceil(step):Math.floor(step);
                    leader = leader + step;
                    //3.賦值
                    ele.style[k] = leader + "px";
                    //4.清除定時器
                    //判斷: 目標值和當前值的差大於步長,就不能跳出循環
                    //不考慮小數的情況:目標位置和當前位置不相等,就不能清除定時器。
                    if(json[k] !== leader){
                        bool = false;
                    }
                }

                console.log(1);
                //只有所有的屬性都到了指定位置,bool值纔不會變成false;
                if(bool){
                    clearInterval(ele.timer);
                }
            },25);
        }

5.緩動動畫封裝(回調函數)(這裏有一個獲取元素樣式的封裝函數getStyle,後文將給出)

        //參數變爲3個
        function animate(ele,json,fn){
            //先清定時器
            clearInterval(ele.timer);
            ele.timer = setInterval(function () {
                //開閉原則
                var bool = true;
                //遍歷屬性和值,分別單獨處理json
                //attr == k(鍵)    target == json[k](值)
                for(var k in json){
                    //四部
                    var leader = parseInt(getStyle(ele,k)) || 0;
                    //1.獲取步長
                    var step = (json[k] - leader)/10;
                    //2.二次加工步長
                    step = step>0?Math.ceil(step):Math.floor(step);
                    leader = leader + step;
                    //3.賦值
                    ele.style[k] = leader + "px";
                    //4.清除定時器
                    //判斷: 目標值和當前值的差大於步長,就不能跳出循環
                    //不考慮小數的情況:目標位置和當前位置不相等,就不能清除清除定時器。
                    if(json[k] !== leader){
                        bool = false;
                    }
                }

                console.log(1);
                //只有所有的屬性都到了指定位置,bool值纔不會變成false;
                if(bool){
                    clearInterval(ele.timer);
                    //所有程序執行完畢了,現在可以執行回調函數了
                    //只有傳遞了回調函數,才能執行
                    if(fn){
                        fn();
                    }
                }
            },25);
        }

6.獲取元素樣式封裝

function getStyle(ele,attr){
            if(window.getComputedStyle){
                return window.getComputedStyle(ele,null)[attr];
            }
            return ele.currentStyle[attr];//兼容IE
        }

7.獲取頂部或左邊被捲去部分的高度或寬度封裝(返回值是一個json,可以用.top獲取)

function scroll(){       
            //簡單封裝(實際工作使用)
           return {
              "top": window.pageYOffset || document.body.scrollTop || document.documentElement.scrollTop,
              "left":  window.pageXOffset || document.body.scrollLeft || document.documentElement.scrollLeft
            }
        }

8.獲取屏幕可視區域的寬高的封裝(返回值是一個json,可以用.width獲取)

//獲取屏幕可視區域的寬高
    function client(){
        if(window.innerHeight !== undefined){
            return {
                "width": window.innerWidth,
                "height": window.innerHeight
            }
        }else if(document.compatMode === "CSS1Compat"){//判斷是否有dtd約束
            return {
                "width": document.documentElement.clientWidth,
                "height": document.documentElement.clientHeight
            }
        }else{
            return {
                "width": document.body.clientWidth,
                "height": document.body.clientHeight
            }
        }
    }

三、event對象的屬性

1.獲取event對象:在觸發DOM上的某個事件時,會產生一個事件對象event,這個對象中包含着所有與事件有關的信息event對象要在事件的驅動函數裏面獲取,如:

document.onclick = function (event) {
             //兼容寫法,兼容IE瀏覽器
             event = event || window.event;
}

2.event的屬性:

 特別注意pageY/X這兩個屬性,它是表示鼠標位於整個網頁頁面的頂部和左側部分的距離。

但是IE不支持這兩個屬性,於是就有了pageY和pageX的兼容寫法:

var pagey = event.pageY || scroll().top + event.clientY;
var pagex = event.pageX || scroll().left + event.clientX;

//鼠標在頁面的位置=被捲去的部分+看得見的部分

四、事件和冒泡/取消冒泡

1.事件和一些特殊屬性

1.滾動事件:window.onscroll

2.屏幕滾動到具體位置:window.scrollTo(x,y)//屏幕滾動到座標x,y

3.鼠標按下:onmousedown    鼠標彈起:onmouseup

4.鼠標移動:onmousemove //如果事件是鼠標按下並移動,那這個事件的調用者應該是document(如拖拽一個盒子、模擬滾動條)

5.瀏覽器大小改變:window.onresize

6.檢測屏幕寬度和高度:window.screen.width/window.screen.height

2.冒泡、取消冒泡、捕獲、事件委託

1.冒泡就是當子盒子和父盒子都綁定了同一個事件時,如果子盒子的事件被觸發,那麼父盒子相應的事件會在之後觸發。

2.捕獲剛好和冒泡相反,子盒子的事件被觸發時,父盒子相應的事件會先觸發,子盒子的事件再觸發。想要實現捕獲可以用addEventListenner(參數1,參數2,參數3)這個方法。參數1:事件去掉on ;參數2 :調用的函數;參數3:可有可無。(不寫或是false是冒泡,True是捕獲。)

3.取消冒泡:

元素.事件= function (event) {
        //阻止冒泡
        event = event || window.event;

        if(event && event.stopPropagation){
            event.stopPropagation();
        }else{
            event.cancelBubble = true;//兼容IE瀏覽器
        }
    }

4.事件委託:事件委託就是普通的事件綁定沒有辦法爲新創建的元素綁定事件。所以我們要使用冒泡的特性來實現事件委託。比如我們新創建了一個li標籤,我們想給這個標籤綁定一個事件,就可以給他的父類ul綁定一個事件,然後用event.target來獲取事件觸動的時候傳遞過來的對象,判斷之後再進行操作,給出一個樣例代碼:

//事件委託
    ul.onclick = function (event) {
        //獲取事件觸動的時候傳遞過來的值
        event = event || window.event;
        var a = event.target?event.target:event.srcElement;//兼容IE寫法
        //判斷標籤名,如果是li標籤就綁定驅動函數
        if(a.tagName === "LI"){
            alert("我是li");
        }
    }

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章