文章目錄
一、網頁特效:
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"><</a>
<a href="javascript:;" class="arrow-r">></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 打開水龍頭