15前端學習之WebAPI(五):網頁特效的三大系列(offset、client、scroll),動畫函數封裝,輪播圖

一、網頁特效:

1. 元素偏移量 offset 系列:

1.1 offset 概述:

offset: 偏移量.使用 offset系列相關屬性可以動態的得到該元素的位置(偏移)、大小等;

  • 獲得元素距離帶有定位父元素的位置;
  • 獲得元素自身的大小;
  • 注意: 返回的數值都不帶單位;
offset系利屬性 作用
element.offsetParent 返回作爲該元素帶有定位的父級元素(如果父級元素都沒有定位, 則返回body)
element.offsetTop 返回該元素相對帶有定位的父元素上方的偏移
element.offsetLeft 返回該元素相對於帶有定位的父元素左邊框的偏移
element.offsetWidth 返回自身包括padding, 邊框,內容區的寬度(返回數值不帶單位)
element.offsetHeight 返回自身包括padding, 邊框,內容區的高度(返回數值不帶單位)

在這裏插入圖片描述

1.2 offset 與 style 區別

offset

  • offset 可以得到任意樣式表中的樣式值;
  • offset 系列獲得的數值是沒有單位的;
  • offsetWidth 包含padding+border+width;
  • offsetWidth 等屬性是隻讀屬性,只能獲取不能賦值;
  • 所以,想要獲取元素大小位置,用offset更合適;

style

  • style 只能得到行內樣式表中的樣式值;
  • style.width 獲得的是帶有單位的字符串;
  • style.width 獲得不包含padding和border 的值;
  • style.width 是可讀寫屬性,可以獲取也可以賦值;
  • 所以,想要給元素更改值,則需要用style改變;

1.3 案例:獲取鼠標在盒子內的座標:

案例分析:

  • 在盒子內點擊,想要得到鼠標距離盒子左右的距離。
  • 首先得到鼠標在頁面中的座標(e.pageX, e.pageY)
  • 其次得到盒子在頁面中的距離 ( box.offsetLeft, box.offsetTop)
  • 用鼠標距離頁面的座標減去盒子在頁面中的距離,得到 鼠標在盒子內的座標
  • 如果想要移動一下鼠標,就要獲取最新的座標,使用鼠標移動

實現:

<head>
    <title>鼠標在盒子內部的座標</title>
    <style>
        .box {
            position: relative;
            width: 280px;
            height: 280px;
            margin: 100px auto;
            background-color: pink;
            padding: 10px;
        }
    </style>
    <script>
        window.onload = function() {
            var box = document.querySelector('.box');
            box.addEventListener('mousemove', function(e) {
                var x = e.pageX - this.offsetLeft;
                var y = e.pageY - this.offsetTop;
                this.innerHTML = 'Y: ' + x + ', Y: ' + y
            })
        }
    </script>
</head>
<body>
    <div class="box">123</div>
</body>

在這裏插入圖片描述

1.4 案例:模態框拖拽:

功能需求:
彈出框,也稱爲模態框;

  • 點擊彈出層,會彈出模態框, 並且顯示灰色半透明的遮擋層;
  • 點擊關閉按鈕,可以關閉模態框,並且同時關閉灰色半透明遮擋層;
  • 鼠標放到模態框最上面一行,可以按住鼠標拖拽模態框在頁面中移動;
  • 鼠標鬆開,可以停止拖動模態框移動;

案例分析:

  • 點擊彈出層, 模態框和遮擋層就會顯示出來 display:block; 點擊關閉按鈕,模態框和遮擋層就會隱藏起來
  • display:none; 在頁面中拖拽的原理:鼠標按下並且移動, 之後鬆開鼠標
  • 觸發事件是鼠標按下mousedown,鼠標移動mousemove 鼠標鬆開 mouseup 拖拽過程:
  • 鼠標移動過程中,獲得最新的值賦值給模態框的left和top值,這樣模態框可以跟着鼠標走了 鼠標按下觸發的事件源是最上面一行,就是 id
  • 爲 title 鼠標的座標減去 鼠標在盒子內的座標, 纔是模態框真正的位置。 鼠標按下,要得到鼠標在盒子的座標。
  • 鼠標移動,就讓模態框的座標 設置爲 :鼠標座標 減去盒子座標即可,注意移動事件寫到按下事件裏面。
  • 鼠標鬆開,就停止拖拽,就是可以讓鼠標移動事件解除

實現:

<head>
    <title>拖拽的模態框</title>
    <style>
        .login-header {
            width: 100%;
            text-align: center;
            height: 30px;
            font-size: 24px;
            line-height: 30px;
        }
        div,
        p,
        span,
        a {
            padding: 0px;
            margin: 0px;
        }
        a {
            text-decoration: none;
            color: #000000;
        }
        .login {
            display: none;
            width: 512px;
            height: 280px;
            position: fixed;
            border: #ebebeb solid 1px;
            left: 50%;
            top: 50%;
            background: #fff;
            box-shadow: 0px 0px 20px #ddd;
            z-index: 9999;
            transform: translate(-50%, -50%);
        }
        .login-title {
            position: relative;
            width: 100%;
            margin: 10px 0px 0px 0px;
            text-align: center;
            line-height: 40px;
            height: 40px;
            font-size: 18px;
            cursor:move;
        }
        .login-input-content {
            margin-top: 20px;
        }
        .login-button {
            width: 50%;
            margin: 30px auto 0 auto;
            line-height: 40px;
            font-size: 14px;
            border: #ebebeb solid 1px;
            text-align: center;
        }
        .login-bg {
            display: none;
            width: 100%;
            height: 100%;
            position: fixed;
            top: 0px;
            left: 0px;
            background: rgba(0, 0, 0, .3);
        }
        .login-button a{
            display: block;
        }
        .login-input input.list-input {
            float: left;
            line-height: 35px;
            height: 35px;
            width: 350px;
            border: #ebebeb solid 1px;
            text-indent: 5px;
        }
        .login-input {
            overflow: hidden;
            margin: 0px 0px 20px 0px;
        }
        .login-input label {
            float: left;
            width: 90px;
            padding-right: 10px;
            text-align: right;
            line-height: 35px;
            height: 35px;
            font-size: 14px;
        }
        .login-title span {
            position: absolute;
            font-size: 12px;
            right: -20px;
            top: -30px;
            background: #fff;
            border: #ebebeb solid 1px;
            width: 40px;
            height: 40px;
            border-radius: 20px;
        }
    </style>
    <script>
        window.onload = function() {
            var login = document.querySelector('.login');
            var bg = document.querySelector(".login-bg");
            var link = document.querySelector('#link');
            var closeBtn = document.querySelector('.login-button');

            var title = document.querySelector('.login-title');

            // 點擊鏈接,彈出login與遮罩
            link.addEventListener('click', function() {
                login.style.display = 'block';
                bg.style.display = 'block';
            })

            // 點擊關閉,隱藏
            closeBtn.addEventListener('click', function() {
                login.style.display = 'none';
                bg.style.display = 'none';
            })

            // 拖拽效果
            title.addEventListener('mousedown', function(e) {
                // 獲取鼠標在盒子中的位置
                var X = e.pageX - login.offsetLeft;
                var Y = e.pageY - login.offsetTop;

                //鼠標移動
                document.addEventListener('mousemove', move)
                function move(e) {
                    login.style.left = e.pageX - X + "px";
                    login.style.top = e.pageY - Y + "px";
                }

                // 鼠標彈起, 移除移動事件
                document.addEventListener('mouseup', function(e) {
                    document.removeEventListener('mousemove', move);
                })
            })
        }
    </script>
</head>
<body>
    <div class="login-header">
        <a href="javascript:;" id="link">點擊, 彈出登錄框</a>
    </div>

    <div id="login" class="login">
        <div id="title" class="login-title">
            會員登錄
            <span>
                <a id="closeBtn" href="javascript:void(0);" class="close-login">關閉</a>
            </span>
        </div>
        <div class="login-input-content">
            <div class="login-input">
                <label for="username">用戶名</label>
                <input type="text" placeholder="請輸入用戶名" name="info[username]" id="username" class="list-input">
            </div>
            <div class="login-input">
                <label for="password">密碼</label>
            <input type="password" placeholder="請輸入登錄密碼" name="info[password]" id="password" class="list-input">
            </div>
        </div>
        <div id="loginBtn" class="login-button">
            <a href="javascript:void(0);" id="login-button-submit">登錄會員</a>
        </div>
    </div>
    <!-- 遮罩層 -->
    <div id="bg" class="login-bg"></div>
</body>

在這裏插入圖片描述

1.4 案例:仿京東放大鏡:

需求:

  • 整個案例可以分爲三個功能模塊
  • 鼠標經過小圖片盒子, 黃色的遮擋層 和 大圖片盒子顯示,離開隱藏2個盒子功能
  • 黃色的遮擋層跟隨鼠標功能。
  • 移動黃色遮擋層,大圖片跟隨移動功能

案例分析:

  • 黃色的遮擋層跟隨鼠標功能;
  • 把鼠標座標給遮擋層不合適。因爲遮擋層座標以父盒子爲準;
  • 首先是獲得鼠標在盒子的座標;
  • 之後把數值給遮擋層做爲left 和top值;
  • 此時用到鼠標移動事件,但是還是在小圖片盒子內移動;
    發現,遮擋層位置不對,需要再減去盒子自身高度和寬度的一半;
  • 遮擋層不能超出小圖片盒子範圍;
  • 如果小於零,就把座標設置爲0;
  • 如果大於遮擋層最大的移動距離,就把座標設置爲最大的移動距離;
  • 遮擋層的最大移動距離:小圖片盒子寬度 減去 遮擋層盒子寬度;
    實現:
window.addEventListener('load', function() {
    var preview_img = document.querySelector('.preview_img');
    var mask = document.querySelector('.mask');
    var big = document.querySelector('.big');
    // 1. 當鼠標經過 preview_img 就顯示和隱藏 mask 遮擋層 和 big 大盒子
    preview_img.addEventListener('mouseover', function() {
        mask.style.display = 'block';
        big.style.display = 'block';
    })
    preview_img.addEventListener('mouseout', function() {
            mask.style.display = 'none';
            big.style.display = 'none';
        })
        // 2. 鼠標移動的時候,讓黃色的盒子跟着鼠標來走
    preview_img.addEventListener('mousemove', function(e) {
        // (1). 先計算出鼠標在盒子內的座標
        var x = e.pageX - this.offsetLeft;
        var y = e.pageY - this.offsetTop;
        // console.log(x, y);
        // (2) 減去盒子高度 300的一半 是 150 就是mask 的最終 left 和top值了
        // (3) mask 移動的距離
        var maskX = x - mask.offsetWidth / 2;
        var maskY = y - mask.offsetHeight / 2;
        // (4) 如果x 座標小於了0 就讓他停在0 的位置
        // 遮擋層的最大移動距離
        var maskMax = preview_img.offsetWidth - mask.offsetWidth;
        if (maskX <= 0) {
            maskX = 0;
        } else if (maskX >= maskMax) {
            maskX = maskMax;
        }
        if (maskY <= 0) {
            maskY = 0;
        } else if (maskY >= maskMax) {
            maskY = maskMax;
        }
        mask.style.left = maskX + 'px';
        mask.style.top = maskY + 'px';
        // 3. 大圖片的移動距離 = 遮擋層移動距離 * 大圖片最大移動距離 / 遮擋層的最大移動距離
        // 大圖
        var bigIMg = document.querySelector('.bigImg');
        // 大圖片最大移動距離
        var bigMax = bigIMg.offsetWidth - big.offsetWidth;
        // 大圖片的移動距離 X Y
        var bigX = maskX * bigMax / maskMax;
        var bigY = maskY * bigMax / maskMax;
        bigIMg.style.left = -bigX + 'px';
        bigIMg.style.top = -bigY + 'px';
    })
})

2. 元素可視區 client 系列:

2.1 client概述

client 翻譯過來就是客戶端, 使用 client 系列的相關屬性來獲取元素可視區的相關信息. 通過 client 系列的相關屬性可以動態的得到該元素的邊框大小、元素大小等.

client系列屬性 說明
element.clientTop 返回元素上邊框的大小
element.clientLeft 返回元素左邊框的大小
element.clientWidth 返回自身包括padding, 內容區的寬度, 不含邊框,返回數值不帶單位
element.clientHeight 返回自身包括padding, 內容區的高度, 不含邊框,返回數值不帶單位

在這裏插入圖片描述

2.2. 淘寶 flexible.js 源碼分析

(function flexible(window, document) {
    // 獲取的html 的根元素
    var docEl = document.documentElement
        // dpr 物理像素比
    var dpr = window.devicePixelRatio || 1

    // adjust body font size  設置body 的字體大小
    function setBodyFontSize() {
        // 如果頁面中有body 這個元素 就設置body的字體大小
        if (document.body) {
            document.body.style.fontSize = (12 * dpr) + 'px'
        } else {
            // 如果頁面中沒有body 這個元素,則等着 頁面主要的DOM元素加載完畢再去設置body
            // 的字體大小
            document.addEventListener('DOMContentLoaded', setBodyFontSize)
        }
    }
    setBodyFontSize();

    // set 1rem = viewWidth / 10    設置html 元素的文字大小
    function setRemUnit() {
        var rem = docEl.clientWidth / 10
        docEl.style.fontSize = rem + 'px'
    }

    setRemUnit()

    // reset rem unit on page resize  當頁面尺寸大小發生變化的時候,要重新設置下rem 的大小
    window.addEventListener('resize', setRemUnit)
        // pageshow 是重新加載頁面觸發的事件
    window.addEventListener('pageshow', function(e) {
        // e.persisted 返回的是true 就是說如果這個頁面是從緩存取過來的頁面,也需要從新計算一下rem 的大小
        if (e.persisted) {
            setRemUnit()
        }
    })

    // detect 0.5px supports  有些移動端的瀏覽器不支持0.5像素的寫法
    if (dpr >= 2) {
        var fakeBody = document.createElement('body')
        var testElement = document.createElement('div')
        testElement.style.border = '.5px solid transparent'
        fakeBody.appendChild(testElement)
        docEl.appendChild(fakeBody)
        if (testElement.offsetHeight === 1) {
            docEl.classList.add('hairlines')
        }
        docEl.removeChild(fakeBody)
    }
}(window, document))
  • 立即執行函數 (function(){})() 或者 (function(){}())
    • 主要作用: 創建一個獨立的作用域。 避免了命名衝突問題
  • 下面三種情況都會刷新頁面都會觸發 load 事件。
    • a標籤的超鏈接
    • F5或者刷新按鈕(強制刷新)
    • 前進後退按鈕

但是 火狐中,有個特點,有個“往返緩存”,這個緩存中不僅保存着頁面數據,還保存了DOM和JavaScript的狀態;實際上是將整個頁面都保存在了內存裏。

所以此時後退按鈕不能刷新頁面。

此時可以使用 pageshow事件來觸發。,這個事件在頁面顯示時觸發,無論頁面是否來自緩存。在重新加載頁面中,pageshow會在load事件觸發後觸發;根據事件對象中的persisted來判斷是否是緩存中的頁面觸發的pageshow事件

注意: 這個事件給window添加

3.元素滾動 scroll 系列

3.1. scroll 概述

scroll 翻譯過來就是滾動的, 使用 scroll 系列的相關屬性可以動態的得到該元素的大小、滾動距離等

scroll系列屬性 作用
element.scrollTop 返回被捲去的上側距離
element.scrollLeft 返回被捲去的左側距離
lement.scrollWidth 返回自身實際的寬度, 不含邊框, 返回數值不帶單位
element.scrolHeight 返回自身實際的高度,不含邊框, 返回數值不帶單位

在這裏插入圖片描述

3.2. 頁面被捲去的頭部

如果瀏覽器的高(或寬)度不足以顯示整個頁面時,會自動出現滾動條. 當滾動條向下滾動時,頁面上面被隱藏掉的高度,就稱爲頁面被捲去的頭部。滾動條在滾動時會觸發 onscroll事件.

3.3.案例:仿淘寶固定右側側邊欄

  • 原先側邊欄是絕對定位
  • 當頁面滾動到一定位置,側邊欄改爲固定定位
  • 頁面繼續滾動,會讓 返回頂部顯示出來

案例分析:

  • 需要用到頁面滾動事件 scroll 因爲是頁面滾動,所以事件源是document;
  • 滾動到某個位置,就是判斷頁面被捲去的上部值;
  • 頁面被捲去的頭部:可以通過window.pageYOffset 獲得 如果是被捲去的左側window.pageXOffset;
  • 注意,元素被捲去的頭部是element.scrollTop , 如果是頁面被捲去的頭部 則是 window.pageYOffset;
  • 其實這個值 可以通過盒子的 offsetTop可以得到,如果大於等於這個值,就可以讓盒子固定定位了;

實現:

<head>
    <title>仿淘寶固定側邊欄</title>
    <style>
        .slider-bar {
            position: absolute;
            left: 50%;
            top: 300px;
            margin-left: 600px;
            width: 45px;
            height: 130px;
            background-color: pink;
        }
        .w {
            width: 1200px;
            margin:  10px auto;
        }
        .header {
            height: 150px;
            background-color: purple;
        }
        .banner {
            height: 250px;
            background-color: skyblue;
        }
        .main {
            height: 1000px;
            background-color: yellowgreen;
        }
        span {
            display: none;
            position: absolute;
            bottom: 0;
        }
    </style>
    <script>
        window.onload = function() {
            // 1. 獲取元素
            var sliderbar = document.querySelector('.slider-bar');
            var banner = document.querySelector('.header');
            // banner.offestTop 就是被捲去頭部的大小 一定要寫到滾動的外面
            var bannerTop = banner.offsetTop
            // 當側邊欄固定定位之後應該變化的數據
            var sliderbarTop = sliderbar.offsetTop - bannerTop;
            // 獲取mian主體元素
            var main = document.querySelector('.main');
            var goBack = document.querySelector('.goBack');
            var mainTop = main.offsetTop;
            // 2. 頁面滾動事件 scroll
            document.addEventListener('scroll', function(e) {
                // window.pageYOffset 頁面被捲去的頭部
                // console.log(window.pageYOffset);
                // 3. 當頁面被捲去的頭部大於bannerTop時, 側邊欄要改爲固定定位
                if(window.pageYOffset >= bannerTop) {
                    sliderbar.style.position = 'fixed';
                    sliderbar.style.top = sliderbarTop + 'px';
                } else {
                    sliderbar.style.position = 'absolute';
                    sliderbar.style.top = '300px';
                }
                
                // 4. 當頁面滾動到main盒子, 就顯示goback模塊
                if (window.pageYOffset >= mainTop) {
                    goBack.style.display = 'block';
                } else {
                    goBack.style.display = 'none';
                }
            })
        }
    </script>
</head>
<body>
    <div class="slider-bar">
        <span class="goBack">返回頂部</span>
    </div>
    <div class="header w">頭部</div>
    <div class="banner w">banner區域</div>
    <div class="main w">主體區域</div>
</body>

在這裏插入圖片描述

3.4頁面被捲去的頭部兼容性解決方案

需要注意的是,頁面被捲去的頭部,有兼容性問題,因此被捲去的頭部通常有如下幾種寫法:

  • 聲明瞭 DTD,使用 document.documentElement.scrollTop
  • 未聲明 DTD,使用 document.body.scrollTop
  • 新方法 window.pageYOffset和 window.pageXOffset,IE9 開始支持
function getScroll() {
    return {
      left: window.pageXOffset || document.documentElement.scrollLeft || document.body.scrollLeft||0,
      top: window.pageYOffset || document.documentElement.scrollTop || document.body.scrollTop || 0
    };
 } 
使用的時候  getScroll().left

4. 三大系列總結:

三大系列大小對比 作用
element.offsetWidth 返回自身包括padding, 邊框,內容區的寬度; 返回數值不帶單位
element.clientWidth 返回自身包括padding, 內容區的寬度; 返回數值不帶單位
element.scrollWidth 返回自身實際的寬度, 不含邊框; 返回數值不帶單位

他們主要用法:

  • 1.offset系列 經常用於獲得元素位置 offsetLeft offsetTop;
  • 2.client經常用於獲取元素大小 clientWidth clientHeight;
  • 3.scroll 經常用於獲取滾動距離 scrollTop scrollLeft;
  • 4.注意頁面滾動的距離通過 window.pageXOffset 獲得;

5. mouseenter 和mouseover的區別

  • 當鼠標移動到元素上時就會觸發mouseenter 事件;
  • 類似 mouseover,它們兩者之間的差別是;
  • mouseover 鼠標經過自身盒子會觸發,經過子盒子還會觸發。mouseenter 只會經過自身盒子觸發;
  • 之所以這樣,就是因爲mouseenter不會冒泡;
  • 跟mouseenter搭配鼠標離開 mouseleave 同樣不會冒泡;

二、 動畫函數封裝:

1. 動畫實現原理:

核心原理:通過定時器 setInterval() 不斷移動盒子位置;

實現步驟:

  • 獲得盒子當前位置;
  • 讓盒子在當前位置加上1個移動距離;
  • 利用定時器不斷重複這個操作;
  • 加一個結束定時器的條件;
  • 注意此元素需要添加定位(absolute | relative),才能使用element.style.left;

2. 動畫函數給不同元素記錄不同定時器

如果多個元素都使用這個動畫函數, 每次都要var 聲明定時器. 可以給不同的元素使用不同的定時器(自己專門用自己的定時器)

核心原理:利用 JS 是一門動態語, 可以很方便的給當前對象添加屬性;

 function animate(obj, target) {
  	// 當不斷的點擊按鈕,這個元素的速度會越來越快,因爲開啓了太多的定時器
    // 解決方案就是 讓元素只有一個定時器執行
    // 先清除以前的定時器,只保留當前的一個定時器執行
    clearInterval(obj.timer);
    obj.timer = setInterval(function() {
        if (obj.offsetLeft >= target) {
            // 停止動畫 本質是停止定時器
            clearInterval(obj.timer);
        }
        obj.style.left = obj.offsetLeft + 1 + 'px';

    }, 30);
}

3. 緩動動畫:

3.1 緩動效果原理:

緩動動畫就是讓元素運動速度有所變化,最常見的是讓速度慢慢停下來

思路:

  • 讓盒子每次移動的距離慢慢變小,速度就會慢慢落下來;
  • 核心算法:(目標值 - 現在的位置) / 10 做爲每次移動的距離步長;
  • 停止的條件是: 讓當前盒子位置等於目標位置就停止定時器;
  • 注意步長值需要取整;

3.2 動畫函數多個目標值之間移動

可以讓動畫函數從 800 移動到 500。
當點擊按鈕時候,判斷步長是正值還是負值:

  • .如果是正值,則步長往大了取整;
  • 如果是負值,則步長 向小了取整;

3.3 動函數添加回調函數

回調函數原理: 函數可以作爲一個參數. 將這個函數作爲參數傳到另一個函數裏面, 當那個函數執行完之後, 再執行傳進去的這個函數,這個過程就叫做回調;

回調函數寫的位置:定時器結束的位置;

動畫完整版代碼:

function animate(obj, target, callback) {
    // 先清除以前的定時器,只保留當前的一個定時器執行
    clearInterval(obj.timer);
    obj.timer = setInterval(function() {
        // 步長值寫到定時器的裏面
        // 把步長值改爲整數 不要出現小數的問題
        // var step = Math.ceil((target - obj.offsetLeft) / 10);
        var step = (target - obj.offsetLeft) / 10;
        step = step > 0 ? Math.ceil(step) : Math.floor(step);
        if (obj.offsetLeft == target) {
            // 停止動畫 本質是停止定時器
            clearInterval(obj.timer);
            callback && callback();
        }
        // 把每次加1 這個步長值改爲一個慢慢變小的值  步長公式:(目標值 - 現在的位置) / 10
        obj.style.left = obj.offsetLeft + step + 'px';
    }, 15);
}

3.4 動畫函數封裝到js文件中:

**案例: 滑出 **
在這裏插入圖片描述在這裏插入圖片描述

<head>
    <title>外部引用動畫函數</title>
    <style>
        .sliderbar {
            position: fixed;    /* 固定定位 */
            right: 0;
            top: 200px;
            width: 40px;
            height: 40px;
            text-align: center;
            line-height: 40px;
            cursor:pointer;
            color: #fff;
        }
        .con {
            position: absolute;
            left: 0;
            top: 0;
            width: 200px;
            height: 40px;
            background-color: purple;
            z-index: -1;
        }
    </style>
    <script src="04_animate.js"></script>
    <script>
        window.onload = function() {
            var sliderbar = document.querySelector(".sliderbar");
            var con = document.querySelector(".con");

            sliderbar.addEventListener("mouseenter", function() {
                animate(con, -160, function() {
                    sliderbar.children[0].innerHTML = "→";
                })
            });
            sliderbar.addEventListener("mouseleave", function() {
                animate(con, 0, function() {
                    sliderbar.children[0].innerHTML = "←";
                })
            })
        }
    </script>
</head>
<body>
    <div class="sliderbar">
        <span></span>
        <div class="con">問題反饋</div>
    </div>
</body>

3.5 案例: js實現動態輪播圖:

在這裏插入圖片描述
輪播圖也稱爲焦點圖,是網頁中比較常見的網頁特效;

  • 1.鼠標經過輪播圖模塊,左右按鈕顯示,離開隱藏左右按鈕;
  • 2.點擊右側按鈕一次,圖片往左播放一張,以此類推,左側按鈕同理;
  • 3.圖片播放的同時,下面小圓圈模塊跟隨一起變化;
  • 4.點擊小圓圈,可以播放相應圖片;
  • 5.鼠標不經過輪播圖,輪播圖會自動播放圖片.

js/lunbo.js

//  1. 獲取元素
var arrow_l = document.querySelector('.arrow-l');
var arrow_r = document.querySelector('.arrow-r');
var focus = document.querySelector('.focus');

var focusWidth = focus.offsetWidth;
// 2. 鼠標經過focus就顯示隱藏左右按鈕
focus.addEventListener('mouseenter', function() {
    arrow_l.style.display = 'block';
    arrow_r.style.display = 'block';
    clearInterval(timer);
    timer = null;
});
focus.addEventListener('mouseleave', function() {
    arrow_l.style.display = 'none';
    arrow_r.style.display = 'none';
    timer = setInterval(function() {
        //手動調用點擊事件
        arrow_r.click();
    }, 2000);
});

// 3. 動態生成圓圈
var ul = focus.querySelector('ul');
var ol = focus.querySelector('.circle');

for(var i = 0; i < ul.children.length; i++) {
    var li = document.createElement('li');
    // 設置索引號
    li.setAttribute('index', i);
    ol.appendChild(li);

    // 4. 給圓圈設置排他
    li.addEventListener('click', function() {
        for(var i = 0; i < ol.children.length; i++){
            ol.children[i].className = '';
        }
        this.className = 'current';
        // 5. 點擊小圓圈,移動圖片 當然移動的是 ul
        var index = this.getAttribute('index');
        // 定位index
        num = circle = index;
        animate(ul, -index * focusWidth);
    })
}
// 默認選中第一個
ol.children[0].className = 'current';
// 6. 克隆第一張圖片(li)放到ul 最後面
var first = ul.children[0].cloneNode(true);
ul.appendChild(first);

// 7. 點擊按鈕, 圖片滾動一張
var num = 0;
var circle = 0;

// 節流閥
var flag = true;
arrow_r.addEventListener('click', function() {
    if (flag) {
        flag = false;
        // // 如果走到了最後複製的一張圖片,此時的ul 要快速復原 left 改爲 0
        if(num == ul.children.length - 1) {
            ul.style.left = 0;
            num = 0;
        }
        num ++;
        animate(ul, -num * focusWidth, function() {
            flag = true;
        });
        circle ++;
        if(circle == ol.children.length){
            circle = 0;
        }
        // 調用函數
        circleChange();
    }
})
arrow_l.addEventListener('click', function() {
    if (flag) {
        flag = false;
        // // 如果走到了最後複製的一張圖片,此時的ul 要快速復原 left 改爲 0
        if(num == 0) {
            num = ul.children.length - 1;
            ul.style.left = -num * focusWidth + 'px';
        }
        num --;
        animate(ul, -num * focusWidth, function() {
            flag = true;
        });
        circle --;
        circle = circle < 0 ? ol.children.length - 1 : circle;
        // 調用函數
        circleChange();
    }
})
function circleChange() {
    // 先清除其餘小圓圈的current類名
    for(var i = 0; i < ol.children.length; i++){
        ol.children[i].className = '';
    }
    // 留下當前的小圓圈的current類名
    ol.children[circle].className = 'current';
}
// 10. 自動播放輪播圖
var timer = setInterval(function() {
    //手動調用點擊事件
    arrow_r.click();
}, 2000);

css/base.css

/*清除元素默認的內外邊距  */
* {
    margin: 0;
    padding: 0
}
/*讓所有斜體 不傾斜*/
em,
i {
    font-style: normal;
}
/*去掉列表前面的小點*/
li {
    list-style: none;
}
/*圖片沒有邊框   去掉圖片底側的空白縫隙*/
img {
    border: 0;  /*ie6*/
    vertical-align: middle;
}
/*讓button 按鈕 變成小手*/
button {
    cursor: pointer;
}
/*取消鏈接的下劃線*/
a {
    color: #666;
    text-decoration: none;
}

a:hover {
    color: #e33333;
}

button,
input {
    font-family: 'Microsoft YaHei', 'Heiti SC', tahoma, arial, 'Hiragino Sans GB', \\5B8B\4F53, sans-serif;
    /*取消輪廓線 藍色的*/
    outline: none;
}

body {
    background-color: #fff;
    font: 12px/1.5 'Microsoft YaHei', 'Heiti SC', tahoma, arial, 'Hiragino Sans GB', \\5B8B\4F53, sans-serif;
    color: #666
}

.hide,
.none {
    display: none;
}
/*清除浮動*/
.clearfix:after {
    visibility: hidden;
    clear: both;
    display: block;
    content: ".";
    height: 0
}
.clearfix {
    *zoom: 1
}

css/lunbo.css

.focus {
    position: relative;
    width: 721px;
    height: 455px;
    background-color: purple;
    overflow: hidden;

    margin: 100px auto;
}
.focus ul {
    position: absolute;
    top: 0;
    left: 0;
    width: 600%;
}
.focus ul li {
    float: left;
}
.arrow-l,
.arrow-r{
    display: none;
    position: absolute;
    top:50%;
    width: 24px;
    height: 40px;
    margin-top: -20px;
    line-height: 40px;
    text-align: center;
    font-size: 28px;
    color: #ffffff;
    background-color: rgba(0, 0, 0, .3);
    z-index: 2;
}
.arrow-l {
    left: 5px;
}
.arrow-r {
    right: 5px;
}
.circle {
    position: absolute;
    bottom: 10px;
    left: 50%;
}
.circle li {
    float: left;
    width: 8px;
    height: 8px;
    border: 2px solid rgba(255, 255, 255, .5);
    margin: 0 3px;
    border-radius: 50%; 
    cursor: pointer;
}
.current {
    background-color: #fff;
}

index.html

<head>
    <title>05_輪播圖</title>
    <link rel="stylesheet" href="./css/base.css">
    <link rel="stylesheet" href="./css/lunbo.css">
    <script src="./js/animate.js"></script>
    <script src="./js/lunbo.js"></script>
</head>
<body>
    <div class="focus">
        <a href="javascript:;"  class="arrow-l">&lt;</a>
        <a href="javascript:;"  class="arrow-r">&gt;</a>
        <ul>
            <li>
                <a href="#">
                    <img src="image/focus.jpg" alt="">
                </a>
            </li>
            <li>
                <a href="#">
                    <img src="image/focus1.jpg" alt="">
                </a>
            </li>
            <li>
                <a href="#">
                    <img src="image/focus2.jpg" alt="">
                </a>
            </li>
            <li>
                <a href="#">
                    <img src="image/focus3.jpg" alt="">
                </a>
            </li>
        </ul>
        <!-- 小圓圈 -->
        <ol class="circle">

        </ol>
    </div>
</body>

3.6 節流閥

防止輪播圖按鈕連續點擊造成播放過快;
節流閥目的:當上一個函數動畫內容執行完畢,再去執行下一個函數動畫,讓事件無法連續觸發;
核心實現思路:利用回調函數,添加一個變量來控制,鎖住函數和解鎖函數;

開始設置一個變量var flag= true;
If(flag){flag = false; do something}       關閉水龍頭
利用回調函數動畫執行完畢, flag = true     打開水龍頭
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章