一、元素偏移量 offset 系列
1.1 offset 概述
offset 翻譯過(guò)來(lái)就是偏移量, 我們使用 offset系列相關(guān)屬性可以動(dòng)態(tài)地得到該元素的位置(偏移)、大小等。
獲得元素距離帶有定位父元素的位置
獲得元素自身的大小(寬度高度)
注意:返回的數(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)
- 我們?cè)诤凶觾?nèi)點(diǎn)擊,想要得到鼠標(biāo)距離盒子左右的距離。
- 首先得到鼠標(biāo)在頁(yè)面中的坐標(biāo)(e.pageX, e.pageY)
- 其次得到盒子在頁(yè)面中的距離 ( box.offsetLeft, box.offsetTop)
- 用鼠標(biāo)距離頁(yè)面的坐標(biāo)減去盒子在頁(yè)面中的距離,得到 鼠標(biāo)在盒子內(nèi)的坐標(biāo)
- 如果想要移動(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)
案例分析:
- 點(diǎn)擊彈出層, 模態(tài)框和遮擋層就會(huì)顯示出來(lái) display:block;
- 點(diǎn)擊關(guān)閉按鈕,模態(tài)框和遮擋層就會(huì)隱藏起來(lái) display:none;
- 在頁(yè)面中拖拽的原理:鼠標(biāo)按下并且移動(dòng), 之后松開(kāi)鼠標(biāo)
- 觸發(fā)事件是鼠標(biāo)按下mousedown,鼠標(biāo)移動(dòng)mousemove 鼠標(biāo)松開(kāi) mouseup
- 拖拽過(guò)程: 鼠標(biāo)移動(dòng)過(guò)程中,獲得最新的值賦值給模態(tài)框的left和top值,這樣模態(tài)框可以跟著鼠標(biāo)走了
- 鼠標(biāo)按下觸發(fā)的事件源是最上面一行,就是 id 為 title
- 鼠標(biāo)的坐標(biāo)減去 鼠標(biāo)在盒子內(nèi)的坐標(biāo), 才是模態(tài)框真正的位置。
- 鼠標(biāo)按下,我們要得到鼠標(biāo)在盒子的坐標(biāo)。
- 鼠標(biāo)移動(dòng),就讓模態(tài)框的坐標(biāo) 設(shè)置為 :鼠標(biāo)坐標(biāo) 減去盒子坐標(biāo)即可,注意移動(dòng)事件寫到按下事件里面。
- 鼠標(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 案例:仿京東放大鏡
- 整個(gè)案例可以分為三個(gè)功能模塊
- 鼠標(biāo)經(jīng)過(guò)小圖片盒子, 黃色的遮擋層 和 大圖片盒子顯示,離開(kāi)隱藏2個(gè)盒子功能
- 黃色的遮擋層跟隨鼠標(biāo)功能。
- 移動(dòng)黃色遮擋層,大圖片跟隨移動(dòng)功能。
案例分析:
- 黃色的遮擋層跟隨鼠標(biāo)功能。
- 把鼠標(biāo)坐標(biāo)給遮擋層不合適。因?yàn)檎趽鯇幼鴺?biāo)以父盒子為準(zhǔn)。
- 首先是獲得鼠標(biāo)在盒子的坐標(biāo)。
- 之后把數(shù)值給遮擋層做為left 和top值。
- 此時(shí)用到鼠標(biāo)移動(dòng)事件,但是還是在小圖片盒子內(nèi)移動(dòng)。
- 發(fā)現(xiàn),遮擋層位置不對(duì),需要再減去盒子自身高度和寬度的一半。
- 遮擋層不能超出小圖片盒子范圍。
- 如果小于零,就把坐標(biāo)設(shè)置為0
- 如果大于遮擋層最大的移動(dòng)距離,就把坐標(biāo)設(shè)置為最大的移動(dòng)距離
- 遮擋層的最大移動(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 事件。
a標(biāo)簽的超鏈接
F5或者刷新按鈕(強(qiáng)制刷新)
前進(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è)邊欄
- 原先側(cè)邊欄是絕對(duì)定位
- 當(dāng)頁(yè)面滾動(dòng)到一定位置,側(cè)邊欄改為固定定位
- 頁(yè)面繼續(xù)滾動(dòng),會(huì)讓 返回頂部顯示出來(lái)
案例分析:
- 需要用到頁(yè)面滾動(dòng)事件 scroll 因?yàn)槭琼?yè)面滾動(dòng),所以事件源是document
- 滾動(dòng)到某個(gè)位置,就是判斷頁(yè)面被卷去的上部值。
- 頁(yè)面被卷去的頭部:可以通過(guò)window.pageYOffset 獲得 如果是被卷去的左側(cè)window.pageXOffset
- 注意,元素被卷去的頭部是element.scrollTop , 如果是頁(yè)面被卷去的頭部 則是 window.pageYOffset
- 其實(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)題,因此被卷去的頭部通常有如下幾種寫法:
- 聲明了 DTD,使用 document.documentElement.scrollTop
- 未聲明 DTD,使用 document.body.scrollTop
- 新方法 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é)
他們主要用法:
offset系列 經(jīng)常用于獲得元素位置 offsetLeft offsetTop
client經(jīng)常用于獲取元素大小 clientWidth clientHeight
scroll 經(jīng)常用于獲取滾動(dòng)距離 scrollTop scrollLeft
注意頁(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)步驟:
- 獲得盒子當(dāng)前位置
- 讓盒子在當(dāng)前位置加上1個(gè)移動(dòng)距離
- 利用定時(shí)器不斷重復(fù)這個(gè)操作
- 加一個(gè)結(jié)束定時(shí)器的條件
- 注意此元素需要添加定位,才能使用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)
思路:
- 讓盒子每次移動(dòng)的距離慢慢變小,速度就會(huì)慢慢落下來(lái)。
- 核心算法: (目標(biāo)值 - 現(xiàn)在的位置) / 10 做為每次移動(dòng)的距離步長(zhǎng)
- 停止的條件是: 讓當(dāng)前盒子位置等于目標(biāo)位置就停止定時(shí)器
- 注意步長(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 案例:返回頂部
- 帶有動(dòng)畫的返回頂部
- 此時(shí)可以繼續(xù)使用我們封裝的動(dòng)畫函數(shù)
- 只需要把所有的left 相關(guān)的值改為 跟 頁(yè)面垂直滾動(dòng)距離相關(guān)就可以了
- 頁(yè)面滾動(dòng)了多少,可以通過(guò) window.pageYOffset 得到
- 最后是頁(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 案例:筋頭云案例
- 利用動(dòng)畫函數(shù)做動(dòng)畫效果
- 原先筋斗云的起始位置是0
- 鼠標(biāo)經(jīng)過(guò)某個(gè)小li,把當(dāng)前小li的offsetLeft 位置做為目標(biāo)值即可
- 鼠標(biāo)離開(kāi)某個(gè)小li,就把目標(biāo)值設(shè)為 0
- 如果點(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)元素
touchstart、touchmove、touchend可以實(shí)現(xiàn)拖動(dòng)元素
但是拖動(dòng)元素需要當(dāng)前手指的坐標(biāo)值 我們可以使用 targetTouches[0] 里面的pageX 和 pageY
移動(dòng)端拖動(dòng)的原理: 手指移動(dòng)中,計(jì)算出手指移動(dòng)的距離。然后用盒子原來(lái)的位置 + 手指移動(dòng)的距離
-
手指移動(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端一致。
- 可以自動(dòng)播放圖片
- 手指可以拖動(dòng)播放輪播圖
案例分析:
- 自動(dòng)播放功能
- 開(kāi)啟定時(shí)器
- 移動(dòng)端移動(dòng),可以使用translate 移動(dòng)
- 想要圖片優(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)
自動(dòng)播放功能-無(wú)縫滾動(dòng)
注意,我們判斷條件是要等到圖片滾動(dòng)完畢再去判斷,就是過(guò)渡完成后判斷
此時(shí)需要添加檢測(cè)過(guò)渡完成事件 transitionend
判斷條件:如果索引號(hào)等于 3 說(shuō)明走到最后一張圖片,此時(shí) 索引號(hào)要復(fù)原為 0
此時(shí)圖片,去掉過(guò)渡效果,然后移動(dòng)
如果索引號(hào)小于0, 說(shuō)明是倒著走, 索引號(hào)等于2
此時(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)
案例分析
小圓點(diǎn)跟隨變化效果
把ol里面li帶有current類名的選出來(lái)去掉類名 remove
讓當(dāng)前索引號(hào)的小li 加上 current add
但是,是等著過(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');
- 手指滑動(dòng)輪播圖
- 本質(zhì)就是ul跟隨手指移動(dòng),簡(jiǎn)單說(shuō)就是移動(dòng)端拖動(dòng)元素
- 觸摸元素touchstart: 獲取手指初始坐標(biāo)
- 移動(dòng)手指touchmove: 計(jì)算手指的滑動(dòng)距離,并且移動(dòng)盒子
- 離開(kāi)手指touchend: 根據(jù)滑動(dòng)的距離分不同的情況
- 如果移動(dòng)距離小于某個(gè)像素 就回彈原來(lái)位置
- 如果移動(dòng)距離大于某個(gè)像素就上一張下一張滑動(dòng)。
- 滑動(dòng)也分為左滑動(dòng)和右滑動(dòng)判斷的標(biāo)準(zhǔn)是 移動(dòng)距離正負(fù) 如果是負(fù)值就是左滑 反之右滑
- 如果是左滑就播放下一張 (index++)
- 如果是右滑就播放上一張 (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)擊可以返回頂部
案例分析
- 滾動(dòng)某個(gè)地方顯示
- 事件:scroll頁(yè)面滾動(dòng)事件
- 如果被卷去的頭部(window.pageYOffset )大于某個(gè)數(shù)值
- 點(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 延遲。
原理就是:
- 當(dāng)我們手指觸摸屏幕,記錄當(dāng)前觸摸時(shí)間
- 當(dāng)我們手指離開(kāi)屏幕, 用離開(kāi)的時(shí)間減去觸摸的時(shí)間
- 如果時(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í)行代碼 });
- 使用插件。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 插件的使用
引入 js 插件文件。
按照規(guī)定語(yǔ)法使用。
fastclick 插件解決 300ms 延遲。 使用延時(shí)
-
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/
- 引入插件相關(guān)文件。
- 按照規(guī)定語(yǔ)法使用
11.4 其他移動(dòng)端常見(jiàn)插件
lsuperslide: http://www.superslide2.com/
l iscroll: https://github.com/cubiq/iscroll
11.5 插件的使用總結(jié)
確認(rèn)插件實(shí)現(xiàn)的功能
去官網(wǎng)查看使用說(shuō)明
下載插件
打開(kāi)demo實(shí)例文件,查看需要引入的相關(guān)文件,并且引入
復(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插件使用步驟:
引入相關(guān)js 文件
復(fù)制HTML 結(jié)構(gòu)
修改對(duì)應(yīng)樣式
修改相應(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
生命周期永久生效,除非手動(dòng)刪除 否則關(guān)閉頁(yè)面也會(huì)存在
可以多窗口(頁(yè)面)共享(同一瀏覽器可以共享)
以鍵值對(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)顯示上次登錄的用戶名
案例分析
把數(shù)據(jù)存起來(lái),用到本地存儲(chǔ)
關(guān)閉頁(yè)面,也可以顯示用戶名,所以用到localStorage
打開(kāi)頁(yè)面,先判斷是否有這個(gè)用戶名,如果有,就在表單里面顯示用戶名,并且勾選復(fù)選框
當(dāng)復(fù)選框發(fā)生改變的時(shí)候change事件
如果勾選,就存儲(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>