前端學(xué)習(xí)筆記十一-WebAPIs(3)特效

一、元素偏移量 offset 系列

1.1 offset 概述

offset 翻譯過(guò)來(lái)就是偏移量, 我們使用 offset系列相關(guān)屬性可以動(dòng)態(tài)地得到該元素的位置(偏移)、大小等。

  1. 獲得元素距離帶有定位父元素的位置

  2. 獲得元素自身的大小(寬度高度)

  3. 注意:返回的數(shù)值都不帶單位

1.2 offset 與 style 區(qū)別

offset
  • offset 可以得到任意樣式表中的樣式值

  • offset 系列獲得的數(shù)值是沒(méi)有單位

  • offsetWidth 包含padding+border+width

  • offsetWidth 等屬性是只讀屬性,只能獲取不能賦值

  • 所以,我們想要獲取元素大小位置,用offset更合適

style
  • style 只能得到行內(nèi)樣式表中的樣式值

  • style.width 獲得的是帶有單位的字符串

  • style.width 獲得不包含padding和border 的值

  • style.width 是可讀寫屬性,可以獲取也可以賦值

  • 所以,我們想要給元素更改值,則需要用style改變

  • 因?yàn)槠綍r(shí)我們都是給元素注冊(cè)觸摸事件,所以重點(diǎn)記住 targetTocuhes

1.3 案例:獲取鼠標(biāo)在盒子內(nèi)的坐標(biāo)

  1. 我們?cè)诤凶觾?nèi)點(diǎn)擊,想要得到鼠標(biāo)距離盒子左右的距離。
  2. 首先得到鼠標(biāo)在頁(yè)面中的坐標(biāo)(e.pageX, e.pageY)
  3. 其次得到盒子在頁(yè)面中的距離 ( box.offsetLeft, box.offsetTop)
  4. 用鼠標(biāo)距離頁(yè)面的坐標(biāo)減去盒子在頁(yè)面中的距離,得到 鼠標(biāo)在盒子內(nèi)的坐標(biāo)
  5. 如果想要移動(dòng)一下鼠標(biāo),就要獲取最新的坐標(biāo),使用鼠標(biāo)移動(dòng)
var box = document.querySelector('.box');
box.addEventListener('mousemove', function(e) {
var x = e.pageX - this.offsetLeft;
var y = e.pageY - this.offsetTop;
this.innerHTML = 'x坐標(biāo)是' + x + ' y坐標(biāo)是' + y;
})

1.4 案例:模態(tài)框拖拽

彈出框,我們也稱為模態(tài)框。

? 1.點(diǎn)擊彈出層,會(huì)彈出模態(tài)框, 并且顯示灰色半透明的遮擋層。

? 2.點(diǎn)擊關(guān)閉按鈕,可以關(guān)閉模態(tài)框,并且同時(shí)關(guān)閉灰色半透明遮擋層。

? 3.鼠標(biāo)放到模態(tài)框最上面一行,可以按住鼠標(biāo)拖拽模態(tài)框在頁(yè)面中移動(dòng)。

? 4.鼠標(biāo)松開(kāi),可以停止拖動(dòng)模態(tài)框移動(dòng)

案例分析:

  1. 點(diǎn)擊彈出層, 模態(tài)框和遮擋層就會(huì)顯示出來(lái) display:block;
  2. 點(diǎn)擊關(guān)閉按鈕,模態(tài)框和遮擋層就會(huì)隱藏起來(lái) display:none;
  3. 在頁(yè)面中拖拽的原理:鼠標(biāo)按下并且移動(dòng), 之后松開(kāi)鼠標(biāo)
  4. 觸發(fā)事件是鼠標(biāo)按下mousedown,鼠標(biāo)移動(dòng)mousemove 鼠標(biāo)松開(kāi) mouseup
  5. 拖拽過(guò)程: 鼠標(biāo)移動(dòng)過(guò)程中,獲得最新的值賦值給模態(tài)框的left和top值,這樣模態(tài)框可以跟著鼠標(biāo)走了
  6. 鼠標(biāo)按下觸發(fā)的事件源是最上面一行,就是 id 為 title
  7. 鼠標(biāo)的坐標(biāo)減去 鼠標(biāo)在盒子內(nèi)的坐標(biāo), 才是模態(tài)框真正的位置。
  8. 鼠標(biāo)按下,我們要得到鼠標(biāo)在盒子的坐標(biāo)。
  9. 鼠標(biāo)移動(dòng),就讓模態(tài)框的坐標(biāo) 設(shè)置為 :鼠標(biāo)坐標(biāo) 減去盒子坐標(biāo)即可,注意移動(dòng)事件寫到按下事件里面。
  10. 鼠標(biāo)松開(kāi),就停止拖拽,就是可以讓鼠標(biāo)移動(dòng)事件解除
 // 1. 獲取元素
        var login = document.querySelector('.login');
        var mask = document.querySelector('.login-bg');
        var link = document.querySelector('#link');
        var closeBtn = document.querySelector('#closeBtn');
        var title = document.querySelector('#title');
        // 2. 點(diǎn)擊彈出層這個(gè)鏈接 link  讓mask 和login 顯示出來(lái)
        link.addEventListener('click', function() {
                mask.style.display = 'block';
                login.style.display = 'block';
            })
            // 3. 點(diǎn)擊 closeBtn 就隱藏 mask 和 login 
        closeBtn.addEventListener('click', function() {
                mask.style.display = 'none';
                login.style.display = 'none';
            })
            // 4. 開(kāi)始拖拽
            // (1) 當(dāng)我們鼠標(biāo)按下, 就獲得鼠標(biāo)在盒子內(nèi)的坐標(biāo)
        title.addEventListener('mousedown', function(e) {
            var x = e.pageX - login.offsetLeft;
            var y = e.pageY - login.offsetTop;
            // (2) 鼠標(biāo)移動(dòng)的時(shí)候,把鼠標(biāo)在頁(yè)面中的坐標(biāo),減去 鼠標(biāo)在盒子內(nèi)的坐標(biāo)就是模態(tài)框的left和top值
            document.addEventListener('mousemove', move)

            function move(e) {
                login.style.left = e.pageX - x + 'px';
                login.style.top = e.pageY - y + 'px';
            }
            // (3) 鼠標(biāo)彈起,就讓鼠標(biāo)移動(dòng)事件移除
            document.addEventListener('mouseup', function() {
                document.removeEventListener('mousemove', move);
            })
        })

1.5 案例:仿京東放大鏡

  1. 整個(gè)案例可以分為三個(gè)功能模塊
  2. 鼠標(biāo)經(jīng)過(guò)小圖片盒子, 黃色的遮擋層 和 大圖片盒子顯示,離開(kāi)隱藏2個(gè)盒子功能
  3. 黃色的遮擋層跟隨鼠標(biāo)功能。
  4. 移動(dòng)黃色遮擋層,大圖片跟隨移動(dòng)功能。

案例分析:

  1. 黃色的遮擋層跟隨鼠標(biāo)功能。
  2. 把鼠標(biāo)坐標(biāo)給遮擋層不合適。因?yàn)檎趽鯇幼鴺?biāo)以父盒子為準(zhǔn)。
  3. 首先是獲得鼠標(biāo)在盒子的坐標(biāo)。
  4. 之后把數(shù)值給遮擋層做為left 和top值。
  5. 此時(shí)用到鼠標(biāo)移動(dòng)事件,但是還是在小圖片盒子內(nèi)移動(dòng)。
  6. 發(fā)現(xiàn),遮擋層位置不對(duì),需要再減去盒子自身高度和寬度的一半。
  7. 遮擋層不能超出小圖片盒子范圍。
  8. 如果小于零,就把坐標(biāo)設(shè)置為0
  9. 如果大于遮擋層最大的移動(dòng)距離,就把坐標(biāo)設(shè)置為最大的移動(dòng)距離
  10. 遮擋層的最大移動(dòng)距離:小圖片盒子寬度 減去 遮擋層盒子寬度
window.addEventListener('load', function() {
    var preview_img = document.querySelector('.preview_img');
    var mask = document.querySelector('.mask');
    var big = document.querySelector('.big');
    // 1. 當(dāng)我們鼠標(biāo)經(jīng)過(guò) 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. 鼠標(biāo)移動(dòng)的時(shí)候,讓黃色的盒子跟著鼠標(biāo)來(lái)走
    preview_img.addEventListener('mousemove', function(e) {
        // (1). 先計(jì)算出鼠標(biāo)在盒子內(nèi)的坐標(biāo)
        var x = e.pageX - this.offsetLeft;
        var y = e.pageY - this.offsetTop;
        // console.log(x, y);
        // (2) 減去盒子高度 300的一半 是 150 就是我們mask 的最終 left 和top值了
        // (3) 我們mask 移動(dòng)的距離
        var maskX = x - mask.offsetWidth / 2;
        var maskY = y - mask.offsetHeight / 2;
        // (4) 如果x 坐標(biāo)小于了0 就讓他停在0 的位置
        // 遮擋層的最大移動(dòng)距離
        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. 大圖片的移動(dòng)距離 = 遮擋層移動(dòng)距離 * 大圖片最大移動(dòng)距離 / 遮擋層的最大移動(dòng)距離
        // 大圖
        var bigIMg = document.querySelector('.bigImg');
        // 大圖片最大移動(dòng)距離
        var bigMax = bigIMg.offsetWidth - big.offsetWidth;
        // 大圖片的移動(dòng)距離 X Y
        var bigX = maskX * bigMax / maskMax;
        var bigY = maskY * bigMax / maskMax;
        bigIMg.style.left = -bigX + 'px';
        bigIMg.style.top = -bigY + 'px';
    })
})

二、元素可視區(qū) client 系列

2.1 client概述

client 翻譯過(guò)來(lái)就是客戶端,我們使用 client 系列的相關(guān)屬性來(lái)獲取元素可視區(qū)的相關(guān)信息。通過(guò) client系列的相關(guān)屬性可以動(dòng)態(tài)的得到該元素的邊框大小、不包含邊框的元素大小等。

2.2 淘寶 flexible.js 源碼分析

立即執(zhí)行函數(shù) (function(){})() 或者 (function(){}())

主要作用: 創(chuàng)建一個(gè)獨(dú)立的作用域。 避免了命名沖突問(wèn)題

(function(a,b){
    console.log(a+b);
    var num = 5;//立即執(zhí)行函數(shù)里面定義的變量都是局部變量
})(1,2);
//兩個(gè)立即執(zhí)行函數(shù)之間一定要加   ;
(function(a){
    console.log(a);
    var num = 10;//局部變量
}(5));

下面三種情況都會(huì)刷新頁(yè)面都會(huì)觸發(fā) load 事件

  1. a標(biāo)簽的超鏈接

  2. F5或者刷新按鈕(強(qiáng)制刷新)

  3. 前進(jìn)后退按鈕

但是 火狐中,有個(gè)特點(diǎn),有個(gè)“往返緩存”,這個(gè)緩存中不僅保存著頁(yè)面數(shù)據(jù),還保存了DOM和JavaScript的狀態(tài);實(shí)際上是將整個(gè)頁(yè)面都保存在了內(nèi)存里。所以此時(shí)后退按鈕不能刷新頁(yè)面。

此時(shí)可以使用 pageshow事件來(lái)觸發(fā)。這個(gè)事件在頁(yè)面顯示時(shí)觸發(fā),無(wú)論頁(yè)面是否來(lái)自緩存。在重新加載頁(yè)面中,pageshow會(huì)在load事件觸發(fā)后觸發(fā);根據(jù)事件對(duì)象中的persisted來(lái)判斷是否是緩存中的頁(yè)面觸發(fā)的pageshow事件

注意這個(gè)事件給window添加。

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

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

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

    setRemUnit()

    // reset rem unit on page resize  當(dāng)我們頁(yè)面尺寸大小發(fā)生變化的時(shí)候,要重新設(shè)置下rem 的大小
    window.addEventListener('resize', setRemUnit)
        // pageshow 是我們重新加載頁(yè)面觸發(fā)的事件
    window.addEventListener('pageshow', function(e) {
        // e.persisted 返回的是true 就是說(shuō)如果這個(gè)頁(yè)面是從緩存取過(guò)來(lái)的頁(yè)面,也需要從新計(jì)算一下rem 的大小
        if (e.persisted) {
            setRemUnit()
        }
    })

    // detect 0.5px supports  有些移動(dòng)端的瀏覽器不支持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))

三、元素滾動(dòng) scroll 系列

3.1 scroll 概述

scroll 翻譯過(guò)來(lái)就是滾動(dòng)的,我們使用 scroll 系列的相關(guān)屬性可以動(dòng)態(tài)的得到該元素的大小、滾動(dòng)距離等。

3.2 頁(yè)面被卷去的頭部

如果瀏覽器的高(或?qū)挘┒炔蛔阋燥@示整個(gè)頁(yè)面時(shí),會(huì)自動(dòng)出現(xiàn)滾動(dòng)條。當(dāng)滾動(dòng)條向下滾動(dòng)時(shí),頁(yè)面上面被隱藏掉的高度,我們就稱為頁(yè)面被卷去的頭部。滾動(dòng)條在滾動(dòng)時(shí)會(huì)觸發(fā) onscroll事件。

3.3 案例:仿淘寶固定右側(cè)側(cè)邊欄

  1. 原先側(cè)邊欄是絕對(duì)定位
  2. 當(dāng)頁(yè)面滾動(dòng)到一定位置,側(cè)邊欄改為固定定位
  3. 頁(yè)面繼續(xù)滾動(dòng),會(huì)讓 返回頂部顯示出來(lái)
案例分析:
  1. 需要用到頁(yè)面滾動(dòng)事件 scroll 因?yàn)槭琼?yè)面滾動(dòng),所以事件源是document
  2. 滾動(dòng)到某個(gè)位置,就是判斷頁(yè)面被卷去的上部值。
  3. 頁(yè)面被卷去的頭部:可以通過(guò)window.pageYOffset 獲得 如果是被卷去的左側(cè)window.pageXOffset
  4. 注意,元素被卷去的頭部是element.scrollTop , 如果是頁(yè)面被卷去的頭部 則是 window.pageYOffset
  5. 其實(shí)這個(gè)值 可以通過(guò)盒子的 offsetTop可以得到,如果大于等于這個(gè)值,就可以讓盒子固定定位了
  //1. 獲取元素
        var sliderbar = document.querySelector('.slider-bar');
        var banner = document.querySelector('.banner');
        // banner.offestTop 就是被卷去頭部的大小 一定要寫到滾動(dòng)的外面
        var bannerTop = banner.offsetTop
            // 當(dāng)我們側(cè)邊欄固定定位之后應(yīng)該變化的數(shù)值
        var sliderbarTop = sliderbar.offsetTop - bannerTop;
        // 獲取main 主體元素
        var main = document.querySelector('.main');
        var goBack = document.querySelector('.goBack');
        var mainTop = main.offsetTop;
        // 2. 頁(yè)面滾動(dòng)事件 scroll
        document.addEventListener('scroll', function() {
            // console.log(11);
            // window.pageYOffset 頁(yè)面被卷去的頭部
            // console.log(window.pageYOffset);
            // 3 .當(dāng)我們頁(yè)面被卷去的頭部大于等于了 172 此時(shí) 側(cè)邊欄就要改為固定定位
            if (window.pageYOffset >= bannerTop) {
                sliderbar.style.position = 'fixed';
                sliderbar.style.top = sliderbarTop + 'px';
            } else {
                sliderbar.style.position = 'absolute';
                sliderbar.style.top = '300px';
            }
            // 4. 當(dāng)我們頁(yè)面滾動(dòng)到main盒子,就顯示 goback模塊
            if (window.pageYOffset >= mainTop) {
                goBack.style.display = 'block';
            } else {
                goBack.style.display = 'none';
            }

        })

3.4 頁(yè)面被卷去的頭部兼容性解決方案

需要注意的是,頁(yè)面被卷去的頭部,有兼容性問(wèn)題,因此被卷去的頭部通常有如下幾種寫法:

  1. 聲明了 DTD,使用 document.documentElement.scrollTop
  2. 未聲明 DTD,使用 document.body.scrollTop
  3. 新方法 window.pageYOffset和 window.pageXOffset,IE9 開(kāi)始支持
function getScroll() {
    return {
      left: window.pageXOffset || document.documentElement.scrollLeft || document.body.scrollLeft||0,
      top: window.pageYOffset || document.documentElement.scrollTop || document.body.scrollTop || 0
    };
 } 
使用的時(shí)候  getScroll().left

四、三大系列總結(jié)

他們主要用法:

  1. offset系列 經(jīng)常用于獲得元素位置 offsetLeft offsetTop

  2. client經(jīng)常用于獲取元素大小 clientWidth clientHeight

  3. scroll 經(jīng)常用于獲取滾動(dòng)距離 scrollTop scrollLeft

  4. 注意頁(yè)面滾動(dòng)的距離通過(guò) window.pageXOffset 獲得

五、mouseenter 和mouseover的區(qū)別

  • 當(dāng)鼠標(biāo)移動(dòng)到元素上時(shí)就會(huì)觸發(fā)mouseenter事件
  • 類似 mouseover,它們兩者之間的差別是
  • mouseover 鼠標(biāo)經(jīng)過(guò)自身盒子會(huì)觸發(fā),經(jīng)過(guò)子盒子還會(huì)觸發(fā)。mouseenter 只會(huì)經(jīng)過(guò)自身盒子觸發(fā)
  • 之所以這樣,就是因?yàn)?strong>mouseenter不會(huì)冒泡
  • 跟mouseenter搭配鼠標(biāo)離開(kāi) mouseleave 同樣不會(huì)冒泡

六、動(dòng)畫函數(shù)封裝

6.1 動(dòng)畫實(shí)現(xiàn)原理

核心原理:通過(guò)定時(shí)器 setInterval() 不斷移動(dòng)盒子位置。

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

  1. 獲得盒子當(dāng)前位置
  2. 讓盒子在當(dāng)前位置加上1個(gè)移動(dòng)距離
  3. 利用定時(shí)器不斷重復(fù)這個(gè)操作
  4. 加一個(gè)結(jié)束定時(shí)器的條件
  5. 注意此元素需要添加定位,才能使用element.style.left

6.2 動(dòng)畫函數(shù)給不同元素記錄不同定時(shí)器

如果多個(gè)元素都使用這個(gè)動(dòng)畫函數(shù),每次都要var 聲明定時(shí)器。我們可以給不同的元素使用不同的定時(shí)器(自己專門用自己的定時(shí)器)。

核心原理:利用 JS 是一門動(dòng)態(tài)語(yǔ)言,可以很方便的給當(dāng)前對(duì)象添加屬性。

 function animate(obj, target) {
            // 當(dāng)我們不斷的點(diǎn)擊按鈕,這個(gè)元素的速度會(huì)越來(lái)越快,因?yàn)殚_(kāi)啟了太多的定時(shí)器
            // 解決方案就是 讓我們?cè)刂挥幸粋€(gè)定時(shí)器執(zhí)行
            // 先清除以前的定時(shí)器,只保留當(dāng)前的一個(gè)定時(shí)器執(zhí)行
            clearInterval(obj.timer);
            obj.timer = setInterval(function() {
                if (obj.offsetLeft >= target) {
                    // 停止動(dòng)畫 本質(zhì)是停止定時(shí)器
                    clearInterval(obj.timer);
                }
                obj.style.left = obj.offsetLeft + 1 + 'px';

            }, 30);
        }

6.3 緩動(dòng)效果原理

緩動(dòng)動(dòng)畫就是讓元素運(yùn)動(dòng)速度有所變化,最常見(jiàn)的是讓速度慢慢停下來(lái)

思路:

  1. 讓盒子每次移動(dòng)的距離慢慢變小,速度就會(huì)慢慢落下來(lái)。
  2. 核心算法: (目標(biāo)值 - 現(xiàn)在的位置) / 10 做為每次移動(dòng)的距離步長(zhǎng)
  3. 停止的條件是: 讓當(dāng)前盒子位置等于目標(biāo)位置就停止定時(shí)器
  4. 注意步長(zhǎng)值需要取整

6.4 動(dòng)畫函數(shù)多個(gè)目標(biāo)值之間移動(dòng)

可以讓動(dòng)畫函數(shù)從 800 移動(dòng)到 500。

當(dāng)我們點(diǎn)擊按鈕時(shí)候,判斷步長(zhǎng)是正值還是負(fù)值

? 1.如果是正值,則步長(zhǎng)往大了取整

? 2.如果是負(fù)值,則步長(zhǎng) 向小了取整

6.5 動(dòng)函數(shù)添加回調(diào)函數(shù)

回調(diào)函數(shù)原理:函數(shù)可以作為一個(gè)參數(shù)。將這個(gè)函數(shù)作為參數(shù)傳到另一個(gè)函數(shù)里面,當(dāng)那個(gè)函數(shù)執(zhí)行完之后,再執(zhí)行傳進(jìn)去的這個(gè)函數(shù),這個(gè)過(guò)程就叫做回調(diào)。

回調(diào)函數(shù)寫的位置:定時(shí)器結(jié)束的位置。

6.6 動(dòng)畫完整版代碼:

function animate(obj, target, callback) {
    // console.log(callback);  callback = function() {}  調(diào)用的時(shí)候 callback()

    // 先清除以前的定時(shí)器,只保留當(dāng)前的一個(gè)定時(shí)器執(zhí)行
    clearInterval(obj.timer);
    obj.timer = setInterval(function() {
        // 步長(zhǎng)值寫到定時(shí)器的里面
        // 把我們步長(zhǎng)值改為整數(shù) 不要出現(xiàn)小數(shù)的問(wèn)題
        // 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) {
            // 停止動(dòng)畫 本質(zhì)是停止定時(shí)器
            clearInterval(obj.timer);
            // 回調(diào)函數(shù)寫到定時(shí)器結(jié)束里面
            // if (callback) {
            //     // 調(diào)用函數(shù)
            //     callback();
            // }
            callback && callback();
        }
        // 把每次加1 這個(gè)步長(zhǎng)值改為一個(gè)慢慢變小的值  步長(zhǎng)公式:(目標(biāo)值 - 現(xiàn)在的位置) / 10
        obj.style.left = obj.offsetLeft + step + 'px';

    }, 15);
}

七、常見(jiàn)網(wǎng)頁(yè)特效案例

7.1 案例:網(wǎng)頁(yè)輪播圖

輪播圖也稱為焦點(diǎn)圖,是網(wǎng)頁(yè)中比較常見(jiàn)的網(wǎng)頁(yè)特效。

功能需求:

? 1.鼠標(biāo)經(jīng)過(guò)輪播圖模塊,左右按鈕顯示,離開(kāi)隱藏左右按鈕。

? 2.點(diǎn)擊右側(cè)按鈕一次,圖片往左播放一張,以此類推,左側(cè)按鈕同理。

? 3.圖片播放的同時(shí),下面小圓圈模塊跟隨一起變化。

? 4.點(diǎn)擊小圓圈,可以播放相應(yīng)圖片。

? 5.鼠標(biāo)不經(jīng)過(guò)輪播圖,輪播圖也會(huì)自動(dòng)播放圖片。

? 6.鼠標(biāo)經(jīng)過(guò),輪播圖模塊, 自動(dòng)播放停止。

window.addEventListener('load', function() {
    // 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. 鼠標(biāo)經(jīng)過(guò)focus 就顯示隱藏左右按鈕
    focus.addEventListener('mouseenter', function() {
        arrow_l.style.display = 'block';
        arrow_r.style.display = 'block';
        clearInterval(timer);
        timer = null; // 清除定時(shí)器變量
    });
    focus.addEventListener('mouseleave', function() {
        arrow_l.style.display = 'none';
        arrow_r.style.display = 'none';
        timer = setInterval(function() {
            //手動(dòng)調(diào)用點(diǎn)擊事件
            arrow_r.click();
        }, 2000);
    });
    // 3. 動(dòng)態(tài)生成小圓圈  有幾張圖片,我就生成幾個(gè)小圓圈
    var ul = focus.querySelector('ul');
    var ol = focus.querySelector('.circle');
    // console.log(ul.children.length);
    for (var i = 0; i < ul.children.length; i++) {
        // 創(chuàng)建一個(gè)小li 
        var li = document.createElement('li');
        // 記錄當(dāng)前小圓圈的索引號(hào) 通過(guò)自定義屬性來(lái)做 
        li.setAttribute('index', i);
        // 把小li插入到ol 里面
        ol.appendChild(li);
        // 4. 小圓圈的排他思想 我們可以直接在生成小圓圈的同時(shí)直接綁定點(diǎn)擊事件
        li.addEventListener('click', function() {
            // 干掉所有人 把所有的小li 清除 current 類名
            for (var i = 0; i < ol.children.length; i++) {
                ol.children[i].className = '';
            }
            // 留下我自己  當(dāng)前的小li 設(shè)置current 類名
            this.className = 'current';
            // 5. 點(diǎn)擊小圓圈,移動(dòng)圖片 當(dāng)然移動(dòng)的是 ul 
            // ul 的移動(dòng)距離 小圓圈的索引號(hào) 乘以 圖片的寬度 注意是負(fù)值
            // 當(dāng)我們點(diǎn)擊了某個(gè)小li 就拿到當(dāng)前小li 的索引號(hào)
            var index = this.getAttribute('index');
            // 當(dāng)我們點(diǎn)擊了某個(gè)小li 就要把這個(gè)li 的索引號(hào)給 num  
            num = index;
            // 當(dāng)我們點(diǎn)擊了某個(gè)小li 就要把這個(gè)li 的索引號(hào)給 circle  
            circle = index;
            // num = circle = index;
            console.log(focusWidth);
            console.log(index);

            animate(ul, -index * focusWidth);
        })
    }
    // 把ol里面的第一個(gè)小li設(shè)置類名為 current
    ol.children[0].className = 'current';
    // 6. 克隆第一張圖片(li)放到ul 最后面
    var first = ul.children[0].cloneNode(true);
    ul.appendChild(first);
    // 7. 點(diǎn)擊右側(cè)按鈕, 圖片滾動(dòng)一張
    var num = 0;
    // circle 控制小圓圈的播放
    var circle = 0;
    // flag 節(jié)流閥
    var flag = true;
    arrow_r.addEventListener('click', function() {
        if (flag) {
            flag = false; // 關(guān)閉節(jié)流閥
            // 如果走到了最后復(fù)制的一張圖片,此時(shí) 我們的ul 要快速?gòu)?fù)原 left 改為 0
            if (num == ul.children.length - 1) {
                ul.style.left = 0;
                num = 0;
            }
            num++;
            animate(ul, -num * focusWidth, function() {
                flag = true; // 打開(kāi)節(jié)流閥
            });
            // 8. 點(diǎn)擊右側(cè)按鈕,小圓圈跟隨一起變化 可以再聲明一個(gè)變量控制小圓圈的播放
            circle++;
            // 如果circle == 4 說(shuō)明走到最后我們克隆的這張圖片了 我們就復(fù)原
            if (circle == ol.children.length) {
                circle = 0;
            }
            // 調(diào)用函數(shù)
            circleChange();
        }
    });

    // 9. 左側(cè)按鈕做法
    arrow_l.addEventListener('click', function() {
        if (flag) {
            flag = false;
            if (num == 0) {
                num = ul.children.length - 1;
                ul.style.left = -num * focusWidth + 'px';

            }
            num--;
            animate(ul, -num * focusWidth, function() {
                flag = true;
            });
            // 點(diǎn)擊左側(cè)按鈕,小圓圈跟隨一起變化 可以再聲明一個(gè)變量控制小圓圈的播放
            circle--;
            // 如果circle < 0  說(shuō)明第一張圖片,則小圓圈要改為第4個(gè)小圓圈(3)
            // if (circle < 0) {
            //     circle = ol.children.length - 1;
            // }
            circle = circle < 0 ? ol.children.length - 1 : circle;
            // 調(diào)用函數(shù)
            circleChange();
        }
    });

    function circleChange() {
        // 先清除其余小圓圈的current類名
        for (var i = 0; i < ol.children.length; i++) {
            ol.children[i].className = '';
        }
        // 留下當(dāng)前的小圓圈的current類名
        ol.children[circle].className = 'current';
    }
    // 10. 自動(dòng)播放輪播圖
    var timer = setInterval(function() {
        //手動(dòng)調(diào)用點(diǎn)擊事件
        arrow_r.click();
    }, 2000);

})

7.2 節(jié)流閥

防止輪播圖按鈕連續(xù)點(diǎn)擊造成播放過(guò)快。

節(jié)流閥目的:當(dāng)上一個(gè)函數(shù)動(dòng)畫內(nèi)容執(zhí)行完畢,再去執(zhí)行下一個(gè)函數(shù)動(dòng)畫,讓事件無(wú)法連續(xù)觸發(fā)。

核心實(shí)現(xiàn)思路:利用回調(diào)函數(shù),添加一個(gè)變量來(lái)控制,鎖住函數(shù)和解鎖函數(shù)。

開(kāi)始設(shè)置一個(gè)變量var flag= true;

If(flag){flag = false; do something} 關(guān)閉水龍頭

利用回調(diào)函數(shù)動(dòng)畫執(zhí)行完畢, flag = true 打開(kāi)水龍頭

7.3 案例:返回頂部

  1. 帶有動(dòng)畫的返回頂部
  2. 此時(shí)可以繼續(xù)使用我們封裝的動(dòng)畫函數(shù)
  3. 只需要把所有的left 相關(guān)的值改為 跟 頁(yè)面垂直滾動(dòng)距離相關(guān)就可以了
  4. 頁(yè)面滾動(dòng)了多少,可以通過(guò) window.pageYOffset 得到
  5. 最后是頁(yè)面滾動(dòng),使用 window.scroll(x,y)
  //1. 獲取元素
        var sliderbar = document.querySelector('.slider-bar');
        var banner = document.querySelector('.banner');
        // banner.offestTop 就是被卷去頭部的大小 一定要寫到滾動(dòng)的外面
        var bannerTop = banner.offsetTop
            // 當(dāng)我們側(cè)邊欄固定定位之后應(yīng)該變化的數(shù)值
        var sliderbarTop = sliderbar.offsetTop - bannerTop;
        // 獲取main 主體元素
        var main = document.querySelector('.main');
        var goBack = document.querySelector('.goBack');
        var mainTop = main.offsetTop;
        // 2. 頁(yè)面滾動(dòng)事件 scroll
        document.addEventListener('scroll', function() {
                // console.log(11);
                // window.pageYOffset 頁(yè)面被卷去的頭部
                // console.log(window.pageYOffset);
                // 3 .當(dāng)我們頁(yè)面被卷去的頭部大于等于了 172 此時(shí) 側(cè)邊欄就要改為固定定位
                if (window.pageYOffset >= bannerTop) {
                    sliderbar.style.position = 'fixed';
                    sliderbar.style.top = sliderbarTop + 'px';
                } else {
                    sliderbar.style.position = 'absolute';
                    sliderbar.style.top = '300px';
                }
                // 4. 當(dāng)我們頁(yè)面滾動(dòng)到main盒子,就顯示 goback模塊
                if (window.pageYOffset >= mainTop) {
                    goBack.style.display = 'block';
                } else {
                    goBack.style.display = 'none';
                }

            })
            // 3. 當(dāng)我們點(diǎn)擊了返回頂部模塊,就讓窗口滾動(dòng)的頁(yè)面的最上方
        goBack.addEventListener('click', function() {
            // 里面的x和y 不跟單位的 直接寫數(shù)字即可
            // window.scroll(0, 0);
            // 因?yàn)槭谴翱跐L動(dòng) 所以對(duì)象是window
            animate(window, 0);
        });

7.4 案例:筋頭云案例

  1. 利用動(dòng)畫函數(shù)做動(dòng)畫效果
  2. 原先筋斗云的起始位置是0
  3. 鼠標(biāo)經(jīng)過(guò)某個(gè)小li,把當(dāng)前小li的offsetLeft 位置做為目標(biāo)值即可
  4. 鼠標(biāo)離開(kāi)某個(gè)小li,就把目標(biāo)值設(shè)為 0
  5. 如果點(diǎn)擊了某個(gè)小li, 就把li當(dāng)前的位置存儲(chǔ)起來(lái),做為筋斗云的起始位置
 window.addEventListener('load', function() {
            // 1. 獲取元素
            var cloud = document.querySelector('.cloud');
            var c_nav = document.querySelector('.c-nav');
            var lis = c_nav.querySelectorAll('li');
            // 2. 給所有的小li綁定事件 
            // 這個(gè)current 做為筋斗云的起始位置
            var current = 0;
            for (var i = 0; i < lis.length; i++) {
                // (1) 鼠標(biāo)經(jīng)過(guò)把當(dāng)前小li 的位置做為目標(biāo)值
                lis[i].addEventListener('mouseenter', function() {
                    animate(cloud, this.offsetLeft);
                });
                // (2) 鼠標(biāo)離開(kāi)就回到起始的位置 
                lis[i].addEventListener('mouseleave', function() {
                    animate(cloud, current);
                });
                // (3) 當(dāng)我們鼠標(biāo)點(diǎn)擊,就把當(dāng)前位置做為目標(biāo)值
                lis[i].addEventListener('click', function() {
                    current = this.offsetLeft;
                });
            }
        })

八、觸屏事件

8.1 觸屏事件概述

移動(dòng)端瀏覽器兼容性較好,我們不需要考慮以前 JS 的兼容性問(wèn)題,可以放心的使用原生 JS 書(shū)寫效果,但是移動(dòng)端也有自己獨(dú)特的地方。比如觸屏事件 touch(也稱觸摸事件),Android和 IOS 都有。

touch 對(duì)象代表一個(gè)觸摸點(diǎn)。觸摸點(diǎn)可能是一根手指,也可能是一根觸摸筆。觸屏事件可響應(yīng)用戶手指(或觸控筆)對(duì)屏幕或者觸控板操作。

常見(jiàn)的觸屏事件如下:

8.2 觸摸事件對(duì)象(TouchEvent)

TouchEvent 是一類描述手指在觸摸平面(觸摸屏、觸摸板等)的狀態(tài)變化的事件。這類事件用于描述一個(gè)或多個(gè)觸點(diǎn),使開(kāi)發(fā)者可以檢測(cè)觸點(diǎn)的移動(dòng),觸點(diǎn)的增加和減少,等等

touchstart、touchmove、touchend 三個(gè)事件都會(huì)各自有事件對(duì)象。

觸摸事件對(duì)象重點(diǎn)我們看三個(gè)常見(jiàn)對(duì)象列表:

因?yàn)槠綍r(shí)我們都是給元素注冊(cè)觸摸事件,所以重點(diǎn)記住 targetTocuhes

8.3 案例:移動(dòng)端拖動(dòng)元素

  1. touchstart、touchmove、touchend可以實(shí)現(xiàn)拖動(dòng)元素

  2. 但是拖動(dòng)元素需要當(dāng)前手指的坐標(biāo)值 我們可以使用 targetTouches[0] 里面的pageX 和 pageY

  3. 移動(dòng)端拖動(dòng)的原理: 手指移動(dòng)中,計(jì)算出手指移動(dòng)的距離。然后用盒子原來(lái)的位置 + 手指移動(dòng)的距離

  4. 手指移動(dòng)的距離: 手指滑動(dòng)中的位置 減去 手指剛開(kāi)始觸摸的位置

    拖動(dòng)元素三步曲:

    (1) 觸摸元素 touchstart: 獲取手指初始坐標(biāo),同時(shí)獲得盒子原來(lái)的位置

    (2) 移動(dòng)手指 touchmove: 計(jì)算手指的滑動(dòng)距離,并且移動(dòng)盒子

    (3) 離開(kāi)手指 touchend:

    注意: 手指移動(dòng)也會(huì)觸發(fā)滾動(dòng)屏幕所以這里要阻止默認(rèn)的屏幕滾動(dòng) e.preventDefault();

九、移動(dòng)端常見(jiàn)特效

9.1 案例:移動(dòng)輪播圖

移動(dòng)端輪播圖功能和基本PC端一致。

  1. 可以自動(dòng)播放圖片
  2. 手指可以拖動(dòng)播放輪播圖
案例分析:
  1. 自動(dòng)播放功能
  2. 開(kāi)啟定時(shí)器
  3. 移動(dòng)端移動(dòng),可以使用translate 移動(dòng)
  4. 想要圖片優(yōu)雅的移動(dòng),請(qǐng)?zhí)砑舆^(guò)渡效果
//1.獲取元素
var focus = document.querySelector('.focus');
var ul = focus.children[0];
//獲得focus的寬度
var w =focus.offsetWidth;
//2.利用定時(shí)器自動(dòng)輪播圖的圖片
var index = 0;
var timer = setInterval(function() {
    index++;
    var translateX = - index * w;
    ul.style.transition = 'all .3s';
    ul.style.transform = 'translateX(' + translateX + 'px)';
},2000)
  1. 自動(dòng)播放功能-無(wú)縫滾動(dòng)

  2. 注意,我們判斷條件是要等到圖片滾動(dòng)完畢再去判斷,就是過(guò)渡完成后判斷

  3. 此時(shí)需要添加檢測(cè)過(guò)渡完成事件 transitionend

  4. 判斷條件:如果索引號(hào)等于 3 說(shuō)明走到最后一張圖片,此時(shí) 索引號(hào)要復(fù)原為 0

  5. 此時(shí)圖片,去掉過(guò)渡效果,然后移動(dòng)

  6. 如果索引號(hào)小于0, 說(shuō)明是倒著走, 索引號(hào)等于2

  7. 此時(shí)圖片,去掉過(guò)渡效果,然后移動(dòng)

 ul.addEventListener('transitionend', function() {
        // 無(wú)縫滾動(dòng)
        if (index >= 3) {
            index = 0;
            // console.log(index);
            // 去掉過(guò)渡效果 這樣讓我們的ul 快速的跳到目標(biāo)位置
            ul.style.transition = 'none';
            // 利用最新的索引號(hào)乘以寬度 去滾動(dòng)圖片
            var translatex = -index * w;
            ul.style.transform = 'translateX(' + translatex + 'px)';
        } else if (index < 0) {
            index = 2;
            ul.style.transition = 'none';
            // 利用最新的索引號(hào)乘以寬度 去滾動(dòng)圖片
            var translatex = -index * w;
            ul.style.transform = 'translateX(' + translatex + 'px)';
        }
        // 3. 小圓點(diǎn)跟隨變化
        // 把ol里面li帶有current類名的選出來(lái)去掉類名 remove
        ol.querySelector('.current').classList.remove('current');
        // 讓當(dāng)前索引號(hào) 的小li 加上 current   add
        ol.children[index].classList.add('current');
    });

9.2 classList 屬性

classList屬性是HTML5新增的一個(gè)屬性,返回元素的類名。但是ie10以上版本支持。
該屬性用于在元素中添加,移除及切換 CSS 類。有以下方法

添加類:

element.classList.add(’類名’);追加類名不會(huì)覆蓋以前的類名

focus.classList.add('current');

移除類:

element.classList.remove(’類名’);

focus.classList.remove('current');

切換類:

element.classList.toggle(’類名’);

focus.classList.toggle('current');

注意:以上方法里面,所有類名都不帶點(diǎn)

案例分析
  1. 小圓點(diǎn)跟隨變化效果

  2. 把ol里面li帶有current類名的選出來(lái)去掉類名 remove

  3. 讓當(dāng)前索引號(hào)的小li 加上 current add

  4. 但是,是等著過(guò)渡結(jié)束之后變化,所以這個(gè)寫到 transitionend 事件里面

   // 3. 小圓點(diǎn)跟隨變化
   // 把ol里面li帶有current類名的選出來(lái)去掉類名 remove
   ol.querySelector('.current').classList.remove('current');
   // 讓當(dāng)前索引號(hào) 的小li 加上 current   add
   ol.children[index].classList.add('current');
  1. 手指滑動(dòng)輪播圖
  2. 本質(zhì)就是ul跟隨手指移動(dòng),簡(jiǎn)單說(shuō)就是移動(dòng)端拖動(dòng)元素
  3. 觸摸元素touchstart: 獲取手指初始坐標(biāo)
  4. 移動(dòng)手指touchmove: 計(jì)算手指的滑動(dòng)距離,并且移動(dòng)盒子
  5. 離開(kāi)手指touchend: 根據(jù)滑動(dòng)的距離分不同的情況
  6. 如果移動(dòng)距離小于某個(gè)像素 就回彈原來(lái)位置
  7. 如果移動(dòng)距離大于某個(gè)像素就上一張下一張滑動(dòng)。
  8. 滑動(dòng)也分為左滑動(dòng)和右滑動(dòng)判斷的標(biāo)準(zhǔn)是 移動(dòng)距離正負(fù) 如果是負(fù)值就是左滑 反之右滑
  9. 如果是左滑就播放下一張 (index++)
  10. 如果是右滑就播放上一張 (index--)
    // 4. 手指滑動(dòng)輪播圖 
    // 觸摸元素 touchstart: 獲取手指初始坐標(biāo)
    var startX = 0;
    var moveX = 0; // 后面我們會(huì)使用這個(gè)移動(dòng)距離所以要定義一個(gè)全局變量
    var flag = false;
    ul.addEventListener('touchstart', function(e) {
        startX = e.targetTouches[0].pageX;
        // 手指觸摸的時(shí)候就停止定時(shí)器
        clearInterval(timer);
    });
    // 移動(dòng)手指 touchmove: 計(jì)算手指的滑動(dòng)距離, 并且移動(dòng)盒子
    ul.addEventListener('touchmove', function(e) {
        // 計(jì)算移動(dòng)距離
        moveX = e.targetTouches[0].pageX - startX;
        // 移動(dòng)盒子:  盒子原來(lái)的位置 + 手指移動(dòng)的距離 
        var translatex = -index * w + moveX;
        // 手指拖動(dòng)的時(shí)候,不需要?jiǎng)赢嬓Ч砸∠^(guò)渡效果
        ul.style.transition = 'none';
        ul.style.transform = 'translateX(' + translatex + 'px)';
        flag = true; // 如果用戶手指移動(dòng)過(guò)我們?cè)偃ヅ袛喾駝t不做判斷效果
        e.preventDefault(); // 阻止?jié)L動(dòng)屏幕的行為
    });
 // 手指離開(kāi) 根據(jù)移動(dòng)距離去判斷是回彈還是播放上一張下一張
    ul.addEventListener('touchend', function(e) {
        if (flag) {
            // (1) 如果移動(dòng)距離大于50像素我們就播放上一張或者下一張
            if (Math.abs(moveX) > 50) {
                // 如果是右滑就是 播放上一張 moveX 是正值
                if (moveX > 0) {
                    index--;
                } else {
                    // 如果是左滑就是 播放下一張 moveX 是負(fù)值
                    index++;
                }
                var translatex = -index * w;
                ul.style.transition = 'all .3s';
                ul.style.transform = 'translateX(' + translatex + 'px)';
            } else {
                // (2) 如果移動(dòng)距離小于50像素我們就回彈
                var translatex = -index * w;
                ul.style.transition = 'all .1s';
                ul.style.transform = 'translateX(' + translatex + 'px)';
            }
        }
        // 手指離開(kāi)的時(shí)候就重新開(kāi)啟定時(shí)器
        clearInterval(timer);
        timer = setInterval(function() {
            index++;
            var translatex = -index * w;
            ul.style.transition = 'all .3s';
            ul.style.transform = 'translateX(' + translatex + 'px)';
        }, 2000);
    });

9.3 案例:返回頂部

當(dāng)頁(yè)面滾動(dòng)某個(gè)地方,就顯示,否則隱藏

點(diǎn)擊可以返回頂部

案例分析
  1. 滾動(dòng)某個(gè)地方顯示
  2. 事件:scroll頁(yè)面滾動(dòng)事件
  3. 如果被卷去的頭部(window.pageYOffset )大于某個(gè)數(shù)值
  4. 點(diǎn)擊,window.scroll(0,0) 返回頂部
//返回頂部模塊制作
var goBack = document.querySelector('.goBack');
var nav  = document.querySelector('nav');
window.addEventListener('scroll',function() {
    if (window.pageYOffset >= nav.offsetTop) {
        goBack.style.display = 'block';
    } else{
        goBack.style.display = 'none';
    }
})
goBack.addEventListener('click',function() {
    window.scroll(0, 0);
})

十、click 延時(shí)解決方案

移動(dòng)端 click 事件會(huì)有 300ms 的延時(shí),原因是移動(dòng)端屏幕雙擊會(huì)縮放(double tap to zoom) 頁(yè)面。

解決方案:

?1. 禁用縮放。 瀏覽器禁用默認(rèn)的雙擊縮放行為并且去掉300ms 的點(diǎn)擊延遲。

  <meta name="viewport" content="user-scalable=no">

2.利用touch事件自己封裝這個(gè)事件解決300ms 延遲。

原理就是:

  1. 當(dāng)我們手指觸摸屏幕,記錄當(dāng)前觸摸時(shí)間
  2. 當(dāng)我們手指離開(kāi)屏幕, 用離開(kāi)的時(shí)間減去觸摸的時(shí)間
  3. 如果時(shí)間小于150ms,并且沒(méi)有滑動(dòng)過(guò)屏幕, 那么我們就定義為點(diǎn)擊

代碼如下:

//封裝tap,解決click 300ms 延時(shí)
function tap (obj, callback) {
        var isMove = false;
        var startTime = 0; // 記錄觸摸時(shí)候的時(shí)間變量
        obj.addEventListener('touchstart', function (e) {
            startTime = Date.now(); // 記錄觸摸時(shí)間
        });
        obj.addEventListener('touchmove', function (e) {
            isMove = true;  // 看看是否有滑動(dòng),有滑動(dòng)算拖拽,不算點(diǎn)擊
        });
        obj.addEventListener('touchend', function (e) {
            if (!isMove && (Date.now() - startTime) < 150) {  // 如果手指觸摸和離開(kāi)時(shí)間小于150ms 算點(diǎn)擊
                callback && callback(); // 執(zhí)行回調(diào)函數(shù)
            }
            isMove = false;  //  取反 重置
            startTime = 0;
        });
}
//調(diào)用  
  tap(div, function(){   // 執(zhí)行代碼  });

  1. 使用插件。fastclick 插件解決300ms 延遲。
<script src="fastclick.js"></script>
<script>
        if ('addEventListener' in document) {
            document.addEventListener('DOMContentLoaded', function() {
                FastClick.attach(document.body);
            }, false);
        }
        var div = document.querySelector('div');
        div.addEventListener('click', function() {
            alert(11);
        })
</script>

十一、移動(dòng)端常用開(kāi)發(fā)插件

11.1 什么是插件

移動(dòng)端要求的是快速開(kāi)發(fā),所以我們經(jīng)常會(huì)借助于一些插件來(lái)幫我完成操作,那么什么是插件呢?

JS 插件是 js 文件,它遵循一定規(guī)范編寫,方便程序展示效果,擁有特定功能且方便調(diào)用。如輪播圖和瀑布流插件。

特點(diǎn):它一般是為了解決某個(gè)問(wèn)題而專門存在,其功能單一,并且比較小。

我們以前寫的animate.js 也算一個(gè)最簡(jiǎn)單的插件

fastclick 插件解決 300ms 延遲。 使用延時(shí)

GitHub官網(wǎng)地址: https://github.com/ftlabs/fastclick

11.2 插件的使用

  1. 引入 js 插件文件。

  2. 按照規(guī)定語(yǔ)法使用。

  3. fastclick 插件解決 300ms 延遲。 使用延時(shí)

  4. GitHub官網(wǎng)地址: https://github.com/ftlabs/fastclick

    if ('addEventListener' in document) {
                document.addEventListener('DOMContentLoaded', function() {
                           FastClick.attach(document.body);
                }, false);
    }
    

11.3 Swiper 插件的使用

中文官網(wǎng)地址: https://www.swiper.com.cn/

  1. 引入插件相關(guān)文件。
  2. 按照規(guī)定語(yǔ)法使用

11.4 其他移動(dòng)端常見(jiàn)插件

lsuperslide: http://www.superslide2.com/

l iscroll: https://github.com/cubiq/iscroll

11.5 插件的使用總結(jié)

  1. 確認(rèn)插件實(shí)現(xiàn)的功能

  2. 去官網(wǎng)查看使用說(shuō)明

  3. 下載插件

  4. 打開(kāi)demo實(shí)例文件,查看需要引入的相關(guān)文件,并且引入

  5. 復(fù)制demo實(shí)例文件中的結(jié)構(gòu)html,樣式css以及js代碼

11.6 移動(dòng)端視頻插件 zy.media.js

H5 給我們提供了 video 標(biāo)簽,但是瀏覽器的支持情況不同。

不同的視頻格式文件,我們可以通過(guò)source解決。

但是外觀樣式,還有暫停,播放,全屏等功能我們只能自己寫代碼解決。

這個(gè)時(shí)候我們可以使用插件方式來(lái)制作。

我們可以通過(guò) JS 修改元素的大小、顏色、位置等樣式。

十二、移動(dòng)端常用開(kāi)發(fā)框架

12.1 移動(dòng)端視頻插件 zy.media.js

框架,顧名思義就是一套架構(gòu),它會(huì)基于自身的特點(diǎn)向用戶提供一套較為完整的解決方案。框架的控制權(quán)在框架本身,使用者要按照框架所規(guī)定的某種規(guī)范進(jìn)行開(kāi)發(fā)。

插件一般是為了解決某個(gè)問(wèn)題而專門存在,其功能單一,并且比較小。

前端常用的框架有 Bootstrap、Vue、Angular、React 等。既能開(kāi)發(fā)PC端,也能開(kāi)發(fā)移動(dòng)端

前端常用的移動(dòng)端插件有 swiper、superslide、iscroll等。

框架: 大而全,一整套解決方案

插件: 小而專一,某個(gè)功能的解決方案

12.2 Bootstrap

Bootstrap 是一個(gè)簡(jiǎn)潔、直觀、強(qiáng)悍的前端開(kāi)發(fā)框架,它讓 web 開(kāi)發(fā)更迅速、簡(jiǎn)單。

它能開(kāi)發(fā)PC端,也能開(kāi)發(fā)移動(dòng)端

Bootstrap JS插件使用步驟:

  1. 引入相關(guān)js 文件

  2. 復(fù)制HTML 結(jié)構(gòu)

  3. 修改對(duì)應(yīng)樣式

  4. 修改相應(yīng)JS 參數(shù)

?十三、本地存儲(chǔ)

隨著互聯(lián)網(wǎng)的快速發(fā)展,基于網(wǎng)頁(yè)的應(yīng)用越來(lái)越普遍,同時(shí)也變的越來(lái)越復(fù)雜,為了滿足各種各樣的需求,會(huì)經(jīng)常性在本地存儲(chǔ)大量的數(shù)據(jù),HTML5規(guī)范提出了相關(guān)解決方案。

13.1 本地存儲(chǔ)特性

1、數(shù)據(jù)存儲(chǔ)在用戶瀏覽器中

2、設(shè)置、讀取方便、甚至頁(yè)面刷新不丟失數(shù)據(jù)

3、容量較大,sessionStorage約5M、localStorage約20M

4、只能存儲(chǔ)字符串,可以將對(duì)象JSON.stringify() 編碼后存儲(chǔ)

13.2 window.sessionStorage

1、生命周期為關(guān)閉瀏覽器窗口

2、在同一個(gè)窗口(頁(yè)面)下數(shù)據(jù)可以共享

當(dāng)用戶打開(kāi)一個(gè)標(biāo)簽頁(yè)(tab頁(yè)),實(shí)際上就是建立了一個(gè)session會(huì)話,在這個(gè)標(biāo)簽頁(yè)里,url發(fā)生跳轉(zhuǎn),sessionStorage實(shí)際上還是保存著,并不會(huì)消失,當(dāng)標(biāo)簽頁(yè)關(guān)閉的時(shí)候,數(shù)據(jù)才會(huì)消失。

3、以鍵值對(duì)的形式存儲(chǔ)使用

存儲(chǔ)數(shù)據(jù):

sessionStorage.setItem(key, value)

獲取數(shù)據(jù):

sessionStorage.getItem(key)

刪除數(shù)據(jù):

sessionStorage.removeItem(key)

清空數(shù)據(jù):(所有都清除掉)

sessionStorage.clear()

經(jīng)過(guò)測(cè)試發(fā)現(xiàn):

通過(guò)帶target="_blank"的A標(biāo)簽、window.open等方式打開(kāi)新窗口時(shí),會(huì)把舊窗口(或標(biāo)簽)的sessionStorage數(shù)據(jù)帶過(guò)去,但從此之后,新窗口(或標(biāo)簽)的sessionStorage的增刪改和舊窗口已經(jīng)沒(méi)有關(guān)系了,如果只是通過(guò)location.href或target='self'的A鏈接在當(dāng)前標(biāo)簽內(nèi)跳轉(zhuǎn)新頁(yè)面(或者刷新),數(shù)據(jù)還會(huì)保留(前提當(dāng)然是同域)。

總之,在處理sessionStorage時(shí),只要打開(kāi)新窗口就要特別注意了,新舊窗口數(shù)據(jù)不會(huì)互相同步。也就是如果跳轉(zhuǎn)新的標(biāo)簽頁(yè),最好應(yīng)使用localStorage

13.3 window.localStorage

  1. 生命周期永久生效,除非手動(dòng)刪除 否則關(guān)閉頁(yè)面也會(huì)存在

  2. 可以多窗口(頁(yè)面)共享(同一瀏覽器可以共享)

  3. 以鍵值對(duì)的形式存儲(chǔ)使用

存儲(chǔ)數(shù)據(jù):

localStorage.setItem(key, value)

獲取數(shù)據(jù):

localStorage.getItem(key)

刪除數(shù)據(jù):

localStorage.removeItem(key)

清空數(shù)據(jù):(所有都清除掉)

localStorage.clear()

13.4 案例:記住用戶名

如果勾選記住用戶名, 下次用戶打開(kāi)瀏覽器,就在文本框里面自動(dòng)顯示上次登錄的用戶名

案例分析
  1. 把數(shù)據(jù)存起來(lái),用到本地存儲(chǔ)

  2. 關(guān)閉頁(yè)面,也可以顯示用戶名,所以用到localStorage

  3. 打開(kāi)頁(yè)面,先判斷是否有這個(gè)用戶名,如果有,就在表單里面顯示用戶名,并且勾選復(fù)選框

  4. 當(dāng)復(fù)選框發(fā)生改變的時(shí)候change事件

  5. 如果勾選,就存儲(chǔ),否則就移除

<input type="text" id="username">
<input type="checkbox" name="" id="remember">
 記住用戶名
<script>
        var username = document.querySelector('#username');
        var remember = document.querySelector('#remember');
        if (localStorage.getItem('username')) {
            username.value = localStorage.getItem('username');
            remember.checked = true;
        }
        remember.addEventListener('change', function() {
            if (this.checked) {
                localStorage.setItem('username', username.value)
            } else {
                localStorage.removeItem('username');
            }
        })
</script>
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 230,431評(píng)論 6 544
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 99,637評(píng)論 3 429
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人,你說(shuō)我怎么就攤上這事。” “怎么了?”我有些...
    開(kāi)封第一講書(shū)人閱讀 178,555評(píng)論 0 383
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我,道長(zhǎng),這世上最難降的妖魔是什么? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 63,900評(píng)論 1 318
  • 正文 為了忘掉前任,我火速辦了婚禮,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 72,629評(píng)論 6 412
  • 文/花漫 我一把揭開(kāi)白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上,一...
    開(kāi)封第一講書(shū)人閱讀 55,976評(píng)論 1 328
  • 那天,我揣著相機(jī)與錄音,去河邊找鬼。 笑死,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,976評(píng)論 3 448
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起,我...
    開(kāi)封第一講書(shū)人閱讀 43,139評(píng)論 0 290
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 49,686評(píng)論 1 336
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 41,411評(píng)論 3 358
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 43,641評(píng)論 1 374
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 39,129評(píng)論 5 364
  • 正文 年R本政府宣布,位于F島的核電站,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 44,820評(píng)論 3 350
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 35,233評(píng)論 0 28
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 36,567評(píng)論 1 295
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 52,362評(píng)論 3 400
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 48,604評(píng)論 2 380

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

  • ??JavaScript 與 HTML 之間的交互是通過(guò)事件實(shí)現(xiàn)的。 ??事件,就是文檔或?yàn)g覽器窗口中發(fā)生的一些特...
    霜天曉閱讀 3,526評(píng)論 1 11
  • 事件對(duì)象 在我們注冊(cè)事件后,并不會(huì)直接調(diào)用這個(gè)匿名函數(shù),而是觸發(fā)這個(gè)事件時(shí)才執(zhí)行內(nèi)部代碼。 所以真正調(diào)用匿名函數(shù)的...
    印象rcj閱讀 296評(píng)論 0 1
  • 第3章 基本概念 3.1 語(yǔ)法 3.2 關(guān)鍵字和保留字 3.3 變量 3.4 數(shù)據(jù)類型 5種簡(jiǎn)單數(shù)據(jù)類型:Unde...
    RickCole閱讀 5,149評(píng)論 0 21
  • offset家族三大家族和一個(gè)事件對(duì)象三大家族(offset/scroll/client)事件對(duì)象/event ...
    Yuann閱讀 980評(píng)論 0 5
  • JavaScript 與 HTML 之間的交互是通過(guò)事件實(shí)現(xiàn)的。事件,就是文檔或?yàn)g覽器窗口中發(fā)生的一些特定的交互瞬...
    LemonnYan閱讀 697評(píng)論 0 4