通過前面幾篇文章的講解,相信你們已經會操做DOM
和BOM
了。爲何前面要花那麼多精力去講DOM
呢?由於在後面的學習、工做中,會大量的使用DOM
操做,一個表格須要增、刪、改、查,一個圖片須要改變大小..等,若是你想要動態的改變這些,必需要學會使用DOM
。javascript
爲了鞏固前面的知識點,而且可以熟練地使用它們,這裏單獨寫了一篇《JavaScript 進階知識 - 特效篇》。本篇文章做爲進階篇很重要,不僅僅是對前面知識點的運用,期間也會有大量的新知識點注入,因此但願小夥伴們繼續加油,認真閱讀。css
在本篇文章中主要會講解一些案例,好比咱們平時在頁面中碰到的一些特效,一些動畫效果。html
注意: 全部的案例都在這裏連接: 提取密碼密碼: 70ny
,文章中的每一個案例後面都有對應的序號。java
offset
系列用於用於獲取元素自身的大小和位置,在網頁特效中有普遍應用。offset
系列主要有:offsetHeight
、offsetWidth
、offsetParent
、offsetLeft
、offsetTop
。
offsetWidth
和offsetHeight
獲取的是元素的真實寬高
offsetHeight
與offsetWidth
是隻讀屬性,不能設置。示例代碼:獲取一個盒子的真實寬高 [01-offset系列-offsetWidth&Height.html]面試
<!-- 樣式部分 --> <style> div { width: 200px; height: 100px; background-color: pink; padding: 10px; border: 10px solid salmon; margin: 10px; } </style> <!-- html 部分 --> <div id="box"></div> <!-- js 部分 --> <script> var box = document.getElementById('box'); // offsetWidth是一個經過計算後獲得的值, padding + border + width console.log(box.offsetWidth); // 240 console.log(box.offsetHeight); // 140 </script>
offsetWidth
是一個經過計算後獲得的值, padding
+ border
+ width
segmentfault
思考: 以前咱們不是也能夠經過style
來獲取樣式嗎?他們有什麼不一樣數組
style.height
與style.width
只能獲取到行內樣式裏的width
和height
總結:瀏覽器
style.width
與style.height
offsetWidth
與offsetHeight
offset
獲取的寬高包括padding
、border
parentNode
和offsetParent
parentNode
始終是父元素offsetParent
是離當前元素最近的定位元素(absolute
、relative
),若是沒有,那就找body
示例代碼: [02-offset系列-offsetParent.html]app
<!-- 樣式部分 --> <style> #father { width: 500px; height: 500px; background-color: #FF9F68; } #son { width: 300px; height: 300px; background-color: #FEFF89; } #grandson { width: 100px; height: 100px; background-color: #AC005D; position: absolute; left: 100px; right: 100px; } </style> <!-- html 部分 --> <div id="father"> <div id="son"> <div id="grandson"></div> </div> </div> <!-- js 部分 --> <script> var grandSon = document.getElementById("grandson"); // 找父節點 親爹 console.log(grandSon.parentNode); // 返回<div id="son"></div> // 找最近有定位的爹,若是找不到,會找body console.log(grandSon.offsetParent); // 返回<body></body> </script>
offsetLeft
: 自身左側到offsetParent
左側的距離:left + margin
offsetTop
: 自身頂部到offsetParent
頂部的距離 :top + margin
框架
offsetParent
真實的距離示例代碼:獲取一個盒子距父盒子的距離 [03-offset系列-offsetTop&Left.html]
<!-- 樣式部分 --> <style> #father { width: 400px; height: 400px; background-color: pink; position: relative; margin-left: 100px; } #son { width: 200px; height: 200px; background-color: skyblue; position: absolute; left: 100px; margin: 20px; } </style> <!-- html 部分 --> <div id="father"> <div id="son"></div> </div> <!-- js 部分 --> <script> //offsetLeft與offsetTop var son = document.getElementById("son"); console.log(son.offsetLeft); // 120 console.log(son.offsetTop); // 20 </script>
思考: 以前咱們不是也能夠經過style
來獲取樣式嗎?他們有什麼不一樣
style.top
與style.left
只能獲取到行內樣式裏的top
和left
總結:
left/top
使用style.left
與style.top
left/top
使用offsetLeft
與offsetTop
offset
獲取的位置包括margin
body
的一張圖看清offset系列
如何讓一個物體動起來?動畫函數的實現原理其實就是利用間歇定時器每隔一段時間執行一次的原理實現的。
一、讓一個物體動起來
點擊按鈕讓一個盒子勻速往右執行一段距離:[04-勻速動畫初體驗(一).html]
<!-- 樣式部分 --> <style> * { margin: 0; padding: 0; } #box { width: 100px; height: 100px; background-color: hotpink; position: absolute; } </style> <!-- html 部分 --> <button id="btn">奔跑吧</button> <div id="box"></div> <!-- js 部分 --> <script> var btn = document.getElementById('btn'); var box = document.getElementById('box'); btn.onclick = function() { setInterval(function() { // 定義一個距離 至關於每一次要跑的距離 step var step = 5; // 定義一個當前位置 leader var leader = box.offsetLeft; // 每次執行的時候 讓leader都走step距離 leader = leader + step; // 將距離賦值給box box.style.left = leader + "px"; // 每15ms 就執行一次 人眼視覺停留 就有動畫效果了 }, 15); } </script>
效果圖:
BUG: 不知道細心的小夥伴有沒有發現兩個問題
二、讓一個物體動起來,解決bug
咱們讓盒子運動到500px
的位置停下來 [05-勻速動畫初體驗(二).html]
var btn = document.getElementById('btn'); var box = document.getElementById('box'); var timer = null; /** 爲何會越點越快? 點擊一次就會調用一次定時器,點擊的次數越多,調用的就越多 距離疊加的就會愈來愈大 視覺效果上看起來就跑的愈來愈快 只要在每次點擊後,定時器執行前清除上一次定時器,就不會出現越點越快的效果了 */ btn.onclick = function() { // 一進來就清除定時器 clearInterval(timer); timer = setInterval(function() { // 定義一個距離 至關於每一次要跑的距離 step var step = 5; // 定義一個當前位置 leader var leader = box.offsetLeft; /** 當移動的位置在500px內的時候,執行動畫函數 不然就清除定時器,讓盒子停下來 */ if (leader < 500) { // 每次執行的時候 讓leader都走step距離 leader = leader + step; // 將距離賦值給box box.style.left = leader + "px"; } else { clearInterval(timer); } }, 15); }
效果圖:
總結:
setInterval
間歇定時器,若是不手動清除,它就會一直運行下去函數須要獨立,就不能使用全局變量。timer
以前是一個全局變量,若是不獨立,頁面只有一個定時器在運做。封裝的函數裏將timer
綁定給調用定時器的元素,這樣就獨立了。
一、封裝一個動畫函數 [06-封裝一個勻速動畫函數.html]
<!-- html 部分 --> <button id="btn">奔跑吧,500</button> <button id="btn2">奔跑吧,1000</button> <div id="box"></div> <!-- js 部分 --> <script> var btn = document.getElementById('btn'); var btn2 = document.getElementById('btn2'); var box = document.getElementById('box'); /** 既然是封裝的函數,有些不肯定的,常常變的元素就要提出來 好比: 1.每一次改變的距離 num 2.調用動畫的對象 box ==> element 3.運動的目標距離 500 ==> target */ // 封裝一個動畫函數 function animate(element, target,num) { // 一進來就清除定時器 // 函數須要獨立,就不能使用全局變量 因此將timer綁定在element上 clearInterval(element.timer); element.timer = setInterval(function() { // 定義一個距離 至關於每一次要跑的距離 step var step = num; // 定義一個當前位置 leader var leader = element.offsetLeft; if (leader < target) { // 每次執行的時候 讓leader都走step距離 leader = leader + step; // 將距離賦值給box element.style.left = leader + "px"; } else { clearInterval(element.timer); } }, 15); } // 點擊按鈕1 移動到500px的位置 btn.onclick = function() { animate(box, 500, 9); } // 點擊按鈕2 移動到1000px的位置 btn2.onclick = function() { animate(box, 1000, 5); } </script>
注意: 上面的案例咱們只是簡單的實現了一個動畫的封裝效果,可是做爲一個之後會常常用的函數,上面的代碼還有不少須要優化的地方
1000
,想讓它回到500
是很差實現的;5
,目標距離是500
,正好能整除。假如每次走的是9
呢?每次走9
,是不能被500
整除的,因此最後停下里的距離會偏多一點。 二、封裝一個動畫函數完整版 [07-封裝一個勻速動畫函數完整版.html]
clearInterval(element.timer); // 清除前位置在504,直接在下面設置讓它位置等於500 element.style.left = target + "px"; // 500
1000
的時候不能回到500
。假設如今盒子在1000
,咱們點擊按鈕1
的時候想要讓他回到500
,這個時候咱們能夠發現時的leader = 1000
,目標距離target爲500
,就是說當leader>target
的時候,盒子是能夠往回走的,這時候只要將步數設置爲負數
,盒子就是往回跑的。var leader = element.offsetLeft; // 當目標距離大於當前位置 說明往正方向走 step的值就是正的 var step = target > leader? 9 : -9;
if (leader < target){}, else { clearInterval(element.timer); }
去判斷,讓盒子運動了。這時的判斷條件應該是目標距離target
與盒子目前距離leader
之間差的絕對值大於等於一步距離step
絕對值的時候,讓他們執行leader = leader + step;
不然的話清除清除定時器,並將最後的距離直接設置爲target
的距離。var distance = Math.abs(target - leader); // 經過判斷此時的差若是大於或者等於一步的距離step的時候,就應該執行動畫 if (distance >= Math.abs(step)) { leader = leader + step; element.style.left = leader + "px"; }
完整代碼:
<!-- html 部分 --> <button id="btn">奔跑吧,500</button> <button id="btn2">奔跑吧,1000</button> <div id="box"></div> <!-- js 部分 --> <script> var btn = document.getElementById('btn'); var btn2 = document.getElementById('btn2'); var box = document.getElementById('box'); function animate(element, target, num) { clearInterval(element.timer); element.timer = setInterval(function() { var leader = element.offsetLeft; // 判斷此時每次走的距離,當目標距離大於當前位置 說明往正方向走 step的值就是正的 var step = target > leader ? num : -num; // 得到此時的距離 與目標距離的差的絕對值 var distance = Math.abs(target - leader); // 經過判斷此時的差若是大於或者等於一步的距離step的時候,就應該執行動畫 if (distance >= Math.abs(step)) { leader = leader + step; element.style.left = leader + "px"; } else { // 不然清除動畫,而且將最後的距離設置爲target的距離 clearInterval(element.timer); element.style.left = target + "px"; } }, 15); } btn.onclick = function() { animate(box, 500, 9); } btn2.onclick = function() { animate(box, 1000, 5); } </script>
效果圖:
如上,這就是封裝的一個完美的動畫函數了,下次有須要用到動畫的地方,直接引用便可——[ js/animate.js ]
基本上每一個網站都會用到輪播圖,輪播圖的使用能夠說是必不可少的。之後咱們用的最多的多是插件,原生的可能並不經常使用,可是輪播圖的原理咱們必須知道,而且可以寫出來。(以前一次面試就是讓我講出輪播圖的具體實現步驟)
如今咱們先來學習下簡單的輪播圖實現原理。
輪播圖樣式的特色:
ul
要足夠的寬,要求可以一行放下全部的li
overflow:hidden
,僅顯示一張圖片,很少很多要求ul
很寬很寬,由於全部的li
要左浮動,要保證全部的li
在一行上顯示,定義一個盒子,盒子的寬高要和顯示的單張圖片寬高同樣,而後設置overflow:hidden
這樣其餘的li
就會被隱藏在下面,經過改變ul的位置就能實現圖片的切換了
示例代碼: [08-實現簡單的輪播圖.html]
<!-- 樣式部分 --> <style> * { margin: 0; padding: 0; list-style: none; } #slide { width: 560px; height: 315px; margin: 100px auto; position: relative; overflow: hidden; } #slide ul { width: 600%; position: absolute; } #slide ul li { float: left; } #slide ul img { display: block; } #slide ol { width: 100px; height: 14px; background-color: rgba(255, 255, 255, .6); /* background-color: pink; */ position: absolute; bottom: 14px; left: 50%; margin-left: -50px; border-radius: 7px; } #slide ol li { width: 10px; height: 10px; float: left; background-color: #fff; border-radius: 50%; margin-top: 2px; margin-left: 8.5px; cursor: pointer; } #slide ol li.current { background-color: #DF654A; } </style> <!-- html 部分 --> <div id="slide"> <ul> <li> <a href="#"><img src="../image/1.jpg" alt=""></a> </li> <li> <a href="#"><img src="../image/2.jpg" alt=""></a> </li> <li> <a href="#"><img src="../image/3.jpg" alt=""></a> </li> <li> <a href="#"><img src="../image/4.jpg" alt=""></a> </li> <li> <a href="#"><img src="../image/5.jpg" alt=""></a> </li> </ul> <ol> <li class="current"></li> <li></li> <li></li> <li></li> <li></li> </ol> </div> <!-- js 部分 --> <script src="../js/animate.js"></script> <script> var slide = document.getElementById('slide'); var ul = slide.children[0]; var ol = slide.children[1]; // ol 下的 li 小圓點 var lis = ol.children; var imgWidth = slide.offsetWidth; // 給全部的小圓點註冊點擊事件 for (var i = 0; i < lis.length; i++) { lis[i].index = i; lis[i].onclick = function() { // 小圓點高亮排他 for (var i = 0; i < lis.length; i++) { lis[i].className = ""; } this.className = "current"; // 點擊小圓點,讓對應的圖片輪播 獲取ul要改變的距離 // 負的表示ul 向左運動 此時小圓點對應的索引乘以盒子的寬度 就是ul要移動的寬度 var target = -this.index * imgWidth; // ul.style.left = target + 'px'; // 讓圖片像動畫同樣慢慢的移過去 animate(ul, target, 50); } } </script>
效果圖:
從上面效果圖中,咱們能夠看到,一個最簡單的輪播圖已經成型了,可是須要去用手點擊,並且若是跨點數去點擊,會發現圖片要一張張滑過去,這裏後面咱們會優化。
左右焦點輪播圖,就是在顯示圖片的兩端添加兩個按鈕,一個向左,一個向右,點擊的時候圖片會根據點擊的方向滑動。而且當鼠標懸停在顯示區域的時候,兩個按鈕顯示。鼠標離開顯示區域,,兩個按鈕隱藏。
示例代碼: [09-左右焦點輪播圖.html]
<!-- 樣式部分 --> <style> * { margin: 0; padding: 0; list-style: none; } #slide { width: 560px; height: 315px; margin: 100px auto; position: relative; overflow: hidden; } #slide ul { width: 600%; position: absolute; } #slide ul li { float: left; } #slide ul img { display: block; } #slide #arrow { display: none; } #slide #arrow #leftArr, #slide #arrow #rightArr { width: 30px; height: 60px; background-color: rgba(255, 255, 2550, 0.3); position: absolute; top: 50%; margin-top: -30px; text-decoration: none; color: #fff; text-align: center; font: 700 24px/60px "宋體"; } #slide #arrow #leftArr { left: 0; } #slide #arrow #rightArr { right: 0; } </style> <!-- html 部分 --> <div id="slide"> <ul> <li> <a href="#"><img src="../image/1.jpg" alt=""></a> </li> <li> <a href="#"><img src="../image/2.jpg" alt=""></a> </li> <li> <a href="#"><img src="../image/3.jpg" alt=""></a> </li> <li> <a href="#"><img src="../image/4.jpg" alt=""></a> </li> <li> <a href="#"><img src="../image/5.jpg" alt=""></a> </li> </ul> <div id="arrow"> <a href="javascript:void(0);" id="leftArr"><</a> <a href="javascript:void(0);" id="rightArr">></a> </div> </div> <!-- js 部分 --> <script src="../js/animate.js"></script> <script> var slide = document.getElementById('slide'); var ul = slide.children[0]; var lis = ul.children; var arrow = document.getElementById('arrow'); var leftArr = document.getElementById("leftArr"); var rightArr = document.getElementById("rightArr"); var imgWidth = slide.offsetWidth; // 給slide註冊鼠標通過事件,鼠標通過時 顯示arrow slide.onmouseover = function() { arrow.style.display = "block"; }; // 給slide註冊鼠標離開事件,鼠標離開時 隱藏arrow slide.onmouseout = function() { arrow.style.display = "none"; }; // 點擊右箭頭 var count = 0; // 跑出去的張數 rightArr.onclick = function() { // 當這個張數不等於最後一張的時候 執行動畫 if (count < lis.length - 1) { count++; var target = -count * imgWidth; animate(ul, target, 40); } } leftArr.onclick = function() { // 當這個張數不等於最後一張的時候 執行動畫 if (count > 0) { count--; var target = -count * imgWidth; animate(ul, target, 40); } } </script>
效果圖:
上圖能夠看到,當滑到最左邊或者最右邊的時候,再點擊就沒有用了,正常的輪播圖確定不是這樣的,點擊到最後一張後再點擊確定是接着滑動的。下面咱們接着看,如何實現一個無縫輪播圖
示例代碼:無縫輪播(能夠一直點擊) [10-左右焦點輪播圖-無縫滾動.html]
何謂無縫滾動?
無縫滾動就是圖片可以循環切換,就算是最後一張,點擊以後也會跳到第一張
原理:
示例代碼:無縫滾動的簡單原理 [10-無縫滾動原理.html]
<!-- 樣式部分 --> <style> * { margin: 0; padding: 0; list-style: none; } #slide { position: relative; width: 560px; height: 315px; border: 6px dashed #CBF078; margin: 100px auto; overflow: hidden; } #slide ul { width: 3360px; position: absolute; left: 0; top: 0; } #slide ul li { float: left; } #slide ul li img { display: block; vertical-align: top; } </style> <!-- html 部分 --> <div id="slide"> <ul> <li> <img src="../image/1.jpg" alt=""> </li> <li> <img src="../image/2.jpg" alt=""> </li> <li> <img src="../image/3.jpg" alt=""> </li> <li> <img src="../image/4.jpg" alt=""> </li> <li> <img src="../image/5.jpg" alt=""> </li> <!-- 添加一張與第一張如出一轍的圖片 障眼法 --> <li> <img src="../image/1.jpg" alt=""> </li> </ul> </div> <!-- js 部分 --> <script> var slide = document.getElementById('slide'); var ul = slide.children[0]; setInterval(function() { // 每次向左移動的距離 var step = -3; // 獲取 ul的left的值 是個負值 var leader = ul.offsetLeft; // 定義一個目標距離,這裏的目標距離指的是最後一張圖片距離左邊的left值 // 圖片寬度560 在最後一張距離左邊left的位置:-560*5 = -2800 // 就是說當到達這張圖片的時候就應該讓 ul.style.left = "0px"; var target = -2800; // 爲何不直接判斷 leader = -2800的時候讓ul.style.left = "0px";? // 由於每次走3步 3不能被2800整除,因此leader永遠不會等於-2800的 // 這裏直接判斷leader此時距左邊的距離減去目標距離當這個絕對值大於等於 一步距離的絕對值3的時候讓它執行往左運動 if (Math.abs(leader - target) >= Math.abs(step)) { leader = leader + step; ul.style.left = leader + "px"; // 當不足一步距離的時候說明就是最後一張了,就應該跳到第一張圖片了 } else { ul.style.left = "0px"; } }, 15); </script>
效果圖:
左右焦點無縫輪播圖: [11-左右焦點無縫輪播圖.html]
<!-- 樣式部分 --> <style> * { margin: 0; padding: 0; list-style: none; } #slide { width: 560px; height: 315px; margin: 100px auto; position: relative; overflow: hidden; } #slide ul { width: 600%; position: absolute; } #slide ul li { float: left; } #slide ul img { display: block; } #slide #arrow { display: none; } #slide #arrow #leftArr, #slide #arrow #rightArr { width: 30px; height: 60px; background-color: rgba(255, 255, 2550, 0.3); position: absolute; top: 50%; margin-top: -30px; text-decoration: none; color: #fff; text-align: center; font: 700 24px/60px "宋體"; } #slide #arrow #leftArr { left: 0; } #slide #arrow #rightArr { right: 0; } </style> <!-- html 部分--> <div id="slide"> <ul> <li> <a href="#"><img src="../image/1.jpg" alt=""></a> </li> <li> <a href="#"><img src="../image/2.jpg" alt=""></a> </li> <li> <a href="#"><img src="../image/3.jpg" alt=""></a> </li> <li> <a href="#"><img src="../image/4.jpg" alt=""></a> </li> <li> <a href="#"><img src="../image/5.jpg" alt=""></a> </li> <!-- 添加一張圖片 障眼法 --> <li> <a href="#"><img src="../image/1.jpg" alt=""></a> </li> </ul> <div id="arrow"> <a href="javascript:void(0);" id="leftArr"><</a> <a href="javascript:void(0);" id="rightArr">></a> </div> </div> <!-- js 部分 --> <script src="../js/animate.js"></script> <script> var slide = document.getElementById('slide'); var ul = slide.children[0]; var lis = ul.children; var arrow = document.getElementById('arrow'); var leftArr = document.getElementById("leftArr"); var rightArr = document.getElementById("rightArr"); var imgWidth = slide.offsetWidth; // 給slide註冊鼠標通過事件,鼠標通過時 顯示arrow slide.onmouseover = function() { arrow.style.display = "block"; }; // 給slide註冊鼠標離開事件,鼠標離開時 隱藏arrow slide.onmouseout = function() { arrow.style.display = "none"; }; // 點擊右箭頭 var count = 0; // 跑出去的張數 rightArr.onclick = function() { // 當這個張數等於最後一張的時候,偷偷摸摸的把最後一張圖片換成第一張 if (count == lis.length - 1) { count = 0; ul.style.left = 0; } count++; var target = -count * imgWidth; animate(ul, target, 40); } leftArr.onclick = function() { // 判斷是第一張的時候,偷偷摸摸的把第一張換成最後一張 if (count == 0) { count = lis.length - 1; ul.style.left = -count * imgWidth + "px"; } count--; var target = -count * imgWidth; animate(ul, target, 40); } </script>
效果圖:
前面咱們已經能夠經過點擊對應的小點、左右焦點和無縫滾動來實現輪播圖了,不過都是單獨分開來的,如今咱們作個整合,實現一個完整的輪播圖。
功能概述:
簡單輪播功能
circle
下的全部的li註冊點擊事件Ul
左右焦點功能
count
來記錄移動的圖片的張數。點擊右箭頭功能
count
的小圓點。點擊左箭頭的功能和右箭頭基本一致。
自動輪播的功能
ul
,若是給ul
註冊事件,就會出現亂閃的問題 同步功能
bug
解決方法(當一圈事後回到第一個小圓點的時候,再點擊它會發現他會再跑一圈)
完整代碼: [12-完整版輪播圖.html]
<!-- 樣式部分 --> <style> * { margin: 0; padding: 0; list-style: none; } #slide { width: 560px; height: 315px; margin: 100px auto; position: relative; overflow: hidden; } #slide ul { width: 600%; position: absolute; } #slide ul li { float: left; } #slide ul img { display: block; } #slide #arrow { display: none; } #slide #arrow #leftArr, #slide #arrow #rightArr { width: 30px; height: 60px; background-color: rgba(0, 0, 0, 0.5); position: absolute; top: 50%; margin-top: -30px; text-decoration: none; color: #fff; text-align: center; font: 700 24px/60px "宋體"; } #slide #arrow #leftArr { left: 0; } #slide #arrow #rightArr { right: 0; } #slide ol { width: 100px; height: 14px; background-color: rgba(255, 255, 255, .6); /* background-color: pink; */ position: absolute; bottom: 14px; left: 50%; margin-left: -50px; border-radius: 7px; } #slide ol li { width: 10px; height: 10px; float: left; background-color: #fff; border-radius: 50%; margin-top: 2px; margin-left: 8.5px; cursor: pointer; } #slide ol li.current { background-color: #DF654A; } </style> <!--html 部分--> <div id="slide"> <ul> <li> <a href="#"><img src="../image/1.jpg" alt=""></a> </li> <li> <a href="#"><img src="../image/2.jpg" alt=""></a> </li> <li> <a href="#"><img src="../image/3.jpg" alt=""></a> </li> <li> <a href="#"><img src="../image/4.jpg" alt=""></a> </li> <li> <a href="#"><img src="../image/5.jpg" alt=""></a> </li> <li> <a href="#"><img src="../image/1.jpg" alt=""></a> </li> </ul> <!-- 左右箭頭 --> <div id="arrow"> <a href="javascript:void(0);" id="leftArr"><</a> <a href="javascript:void(0);" id="rightArr">></a> </div> <!-- 小圓點 --> <ol id="circleOl"> <li class="current"></li> <li></li> <li></li> <li></li> <li></li> </ol> </div> <script src="../js/animate.js"></script> <script> // 自執行函數,防止頁面其餘定時器會受影響 (function() { var slide = document.getElementById('slide'); var imgUl = slide.children[0]; var imgLis = imgUl.children; var arrow = document.getElementById('arrow'); var leftArr = document.getElementById("leftArr"); var rightArr = document.getElementById("rightArr"); var circleOl = document.getElementById('circleOl'); var circleLis = circleOl.children; // 獲取圖片的寬度 var imgWidth = slide.offsetWidth; var timer = null; // 點擊小圓點改變對應圖片 for (var i = 0; i < circleLis.length; i++) { circleLis[i].index = i; circleLis[i].onclick = function() { // 小圓點點擊的時候高亮排他 for (var i = 0; i < circleLis.length; i++) { circleLis[i].className = ""; } this.className = "current"; // 淘寶bug:這時還須要判斷一下 就是當圖片在最後一張假圖片的時候, // 再去點擊第一個小圓點的時候,會出現一個bug,就是圖片會輪播一圈再回到這張圖片上 if (count == imgLis.length - 1) { count = 0; imgUl.style.left = 0; } // 點擊小圓點圖片要移動 var target = -this.index * imgWidth; // 若是這裏不記錄一下,當點擊小圓點跳到某張圖片的時候,再自動播放的時候, // 不會接着當前小圓點的位置日後播放,而是接着以前count不變的狀況下 繼續播放的 count = this.index; animate(imgUl, target, 40); } } // 左右焦點輪播圖 var count = 0; // 跑出去的張數 rightArr.onclick = function() { // 當這個張數等於最後一張(假圖片)的時候,偷偷摸摸的把最後一張圖片換成第一張 if (count == imgLis.length - 1) { count = 0; imgUl.style.left = 0; } // 點擊一次圖片向右划動一次 count++; var target = -count * imgWidth; animate(imgUl, target, 40); //讓小圓點跟着動 只要將 count 與小圓點綁定便可 for (var i = 0; i < circleLis.length; i++) { circleLis[i].className = ""; } // 這裏須要判斷一下 由於此時最後一張是假圖片 小圓點是不能正常跳轉到第一個的 // 當count == 最後一張圖片的下標的時候,直接讓第一個小圓點亮 if (count == imgLis.length - 1) { circleLis[0].className = "current"; } else { // 不然其餘的下標對應的小圓點高亮 circleLis[count].className = "current"; } } leftArr.onclick = function() { // 判斷是第一張的時候,偷偷摸摸的把第一張換成最後一張 if (count == 0) { count = imgLis.length - 1; imgUl.style.left = -count * imgWidth + "px"; } count--; var target = -count * imgWidth; animate(imgUl, target, 40); // 小圓點同步 往左的時候不會出現小圓點不一樣步的問題 for (var i = 0; i < circleLis.length; i++) { circleLis[i].className = ""; } circleLis[count].className = "current"; } timer = setInterval(function() { rightArr.onclick(); }, 2000); // 給slide註冊鼠標通過事件,鼠標通過時 顯示arrow slide.onmouseover = function() { arrow.style.display = "block"; // 鼠標通過圖片的時候清除定時器,中止輪播 clearInterval(timer); }; // 給slide註冊鼠標離開事件,鼠標離開時 隱藏arrow slide.onmouseout = function() { arrow.style.display = "none"; // 鼠標離開圖片的時候開啓定時器,自動輪播 timer = setInterval(function() { rightArr.onclick(); }, 2000); }; })()
輪播圖的一些功能可能有點繞,寫的有可能不太看得懂,有疑惑的小夥伴直接私信我,我會一步步解釋給你聽的,有什麼bug
也能夠將代碼發給我。
想爲後面打下紮實的基礎的話,這裏必定要多敲幾遍,主要要搞明白的是實現的思路,以及一些小bug
的解決。這對後面的學習是很是重要的。代碼備註可能讀起來有些拗口,不懂得小夥伴直接私信給我。
緩動動畫,顧名思義,就是愈來愈慢的運動。
咱們先來回顧一下上面勻速動畫運動的原理:
/** step : 一步的距離 leader :當前的距離 咱們能夠看到 step在這裏一直等於5 未曾改變 因此就是勻速運動 */ var step = 5; leader = leader + step;
如今咱們再來看下緩動動畫的原理:
/** target: 目標距離,盒子運動到什麼地方 step : 一樣的,仍是指每次運動的距離,可是這裏的步數是一個變化的量了, 咱們能夠看到它會隨着leader的增長變得愈來愈小,這就是緩動動畫的原理 leader: 當前的距離 */ var step = (target - leader)/10; leader = leader + step;
示例代碼: [13-緩動動畫初體驗(一).html]
<!-- 樣式部分 --> <style> * { margin: 0; padding: 0; } #box { width: 100px; height: 100px; position: absolute; background: orange; } </style> <!-- html 部分--> <input type="button" value="奔跑吧" id="btn"> <div id="box"></div> <!-- js 部分 --> <script> var box = document.getElementById('box'); var btn = document.getElementById('btn'); var timer = null; btn.onclick = function() { clearInterval(timer); timer = setInterval(function() { // 定義一個目標距離 var target = 600; // 得到當前盒子的位置 var leader = box.offsetLeft; // 每次運動的距離 var step = (target - leader) / 10; // leader = leader + step 動起來 leader += step; // 將距離給盒子 box.style.left = leader + "px"; // 噹噹前距離等於目標距離的時候清除定時器 if (leader == target) { clearInterval(timer); } }, 15); } </script>
效果圖:
完美了嗎?並無,這裏有個小bug:
可能會有小夥伴不理解,有問題你上面直接講一下不就得了,還特意賣關子在下面從新寫一遍。我想跟你們說的一點就是,若是在上面我直接告訴你這裏有個問題有個bug的話,你一眼看過,可能都不當回事,我在這裏拿出來說一下,相信這個知識點你會記得更深。
小bug:明明設置的是600
,怎麼會是596.4px
呢?
緣由:
offsetLeft
獲取值的時候,只會獲取整數,會對小數部分會四捨五入處理,好比step = (target - leader)/10
當step
的值出現小數的時候,leader+= step
以後,offsetLeft
在獲取leader
位置的時候就會把小數部分四捨五入,這樣就會形成最後距離的偏差。解決方法:
step
向上取整處理(Math.ceil()
),保證每一次都至少跑1px
的距離,只要不出現小數offsetLeft
就不會出現四捨五入。完整代碼: [14-緩動動畫初體驗(二).html]
var box = document.getElementById('box'); var btn = document.getElementById('btn'); var timer = null; btn.onclick = function() { clearInterval(timer); timer = setInterval(function() { // 定義一個目標距離 var target = 600; // 得到當前盒子的位置 var leader = box.offsetLeft; // 每次運動的距離 var step = (target - leader) / 10; // 對step進行向上取整 step = Math.ceil(step); // leader = leader + step 動起來 leader += step; // 將距離給盒子 box.style.left = leader + "px"; // 噹噹前距離等於目標距離的時候清除定時器 if (leader == target) { clearInterval(timer); } }, 15); }
前面勻速動畫那裏已經講過封裝一個函數的好處與重要性,如今咱們將緩動動畫也封裝成一個函數。
示例代碼: [15-緩動動畫函數封裝.html]
<!-- 樣式部分 --> <style> * { margin: 0; padding: 0; } #box { width: 100px; height: 100px; background: orange; position: absolute; } </style> <!-- html 部分 --> <input type="button" value="奔跑吧500" id="btn1"> <input type="button" value="奔跑吧1000" id="btn2"> <div id="box"></div> <!-- js 部分 --> <script> var btn1 = document.getElementById('btn1'); var btn2 = document.getElementById('btn2'); var box = document.getElementById('box'); // 緩動動畫函數 /** element : 執行動畫元素 target : 目標距離 num : 用來控制動畫執行的速度 越大動畫執行越慢 */ function slowAnimate(element, target, num) { // 一進來就要清除定時器,防止越點越快 clearInterval(element.timer); element.timer = setInterval(function() { // 得到元素當前位置 var leader = element.offsetLeft; // 定義每次運動的距離 var step = (target - leader) / num; // step多是小數 因此要取整 step = Math.ceil(step); leader += step; // 設置元素的位置 element.style.left = leader + 'px'; // 當元素的位置 等於 目標位置的時候 清除定時器 if (leader == target) { clearInterval(element.timer); } }, 15); } // 調用緩動動畫函數 btn1.onclick = function() { slowAnimate(box, 500, 10); } // 一樣是運動500的距離,咱們能夠發現從500到1000,明顯執行的比從0-500執行的慢 btn2.onclick = function() { slowAnimate(box, 1000, 30); } </script>
效果圖:
又到了找bug的時候了:
上面的代碼從0-500
,從500-1000
都沒有問題,通過向上取整後都能到達目標距離:500
和1000
。可是小夥伴能夠看下,當從1000
回到500
的時候,是正好回到500
的嗎?答案確定不是的,爲何呢?
step
爲正數的時候,向上取整是徹底沒有問題的,可是當從1000
到500
的時候,step
就是負數了,負數向上取整後就會變得更大,好比本來是-33.3
,向上取整後就是-33
了,-0.3
就會捨去,全部就不會到500
的位置。
解決方法: 判斷step的正負,爲正的時候,向上取整。爲負的時候,向下取整。
緩動函數封裝完整版: [16-緩動動畫函數封裝完整版.html]
function slowAnimate(element, target, num) { // 一進來就要清除定時器,防止越點越快 clearInterval(element.timer); element.timer = setInterval(function() { // 得到元素當前位置 var leader = element.offsetLeft; // 定義每次運動的距離 var step = (target - leader) / num; //若是step是正數,對step向上取整, //若是step是負數,對step向下取整 // 保證每一次最少都走1px step = step > 0 ? Math.ceil(step) : Math.floor(step); leader += step; // 設置元素的位置 element.style.left = leader + 'px'; // 當元素的位置 等於 目標位置的時候 清除定時器 if (leader == target) { clearInterval(element.timer); } }, 15); };
獲取元素計算後的樣式指的是元素通過層疊後真正生效的樣式,無論樣式寫在哪,計算後的樣式指的就是最終的樣式。
經過style
只能獲取到寫在行內的樣式,那麼想要獲取其餘的樣式怎麼辦呢?
window.getComputedStyle(element, null)[attr];
,它返回的是一個對象CSSStyleDeclaration
,[attr]
就是這個對象裏面就是計算後的全部的樣式的屬性名(關聯數組取對象的值)。element
指的是當前參數,null
這裏能夠不用深究-官方解釋。這個方法須要window
調用。
/** element :獲取樣式的當前元素 null :這裏能夠傳一個僞元素,若是不是僞元素的話必須是null attr :後面能夠寫具體的屬性,好比boderRadius 就會獲取這個元素的border-radius樣式信息 */ window.getComputedStyle(element,null)[attr];
示例代碼: [17-獲取元素計算後的樣式.html]
<!-- 樣式部分 --> <style> div { width: 100px; height: 100px; background: pink; } #box { width: 200px; } </style> <!-- html 部分 --> <div id="box" style="width:300px;"></div> <!-- js 部分 --> <script> var box = document.getElementById('box'); console.log(window.getComputedStyle(box, null)); // 打印得到box的各類屬性的樣式 // 其中行內樣式權重最高,因此最後得到的寬應該是300px console.log(window.getComputedStyle(box, null).width); // 300px console.log(window.getComputedStyle(box, null).background); </script>
效果圖:
兼容性處理:
window.getComputedStyle(element, null)[attr];
只適用於現代瀏覽器中IE678
有本身的方法:element.currentStyle[attr];
// 獲取元素計算後的樣式 function getStyle(element,attr){ if(window.getComputedStyle){ return window.getComputedStyle(element, null)[attr]; }else{ return element.currentStyle[attr]; } } // 注意:調用函數的時候 獲取的屬性名是一個字符串 alert(getStyle(box, "width"));
[18-獲取元素計算後的樣式兼容性處理.html]
注意: 上面的封裝函數中,調用的時候,屬性名是一個字符串類型。
無論是上面的勻速動畫函數,仍是這裏的緩動動畫函數,都只能左右運動,可是一個真正完整的動畫函數,只改變左右位置確定是不夠的,咱們可能須要改變它的寬高等。在上面一節中,咱們知道了如何獲取到元素計算後的樣式,並且只要是元素有的樣式都能獲取到,有了這個方法咱們就可讓動畫去執行更多的事情了。
一、對獲取到的樣式返回值進行處理:
在上面的一節中,咱們能夠看到,獲取的返回值都是字符串格式,好比獲取寬度的時候,返回的是一個"300px"
的字符串,由於緩動動畫函數裏面是須要計算的,這裏是個字符串確定不行,因此咱們須要對其進行parseInt
取整處理。
[19-緩動動畫修改多個樣式-處理返回值.html]:
function getStyle(element, attr) { if (window.getComputedStyle) { return window.getComputedStyle(element, null)[attr]; } else { return element.currentStyle[attr]; } } function animate(element, attr, target) { clearInterval(element.timer); element.timer = setInterval(function() { // getStyle 返回的是樣式屬性的值 咱們用一個變量將它儲存起來 var leader = getStyle(element, attr); // 由於返回值是一個字符串,而且帶有字符px,因此咱們對返回值進行取整轉換 leader = parseInt(leader) || 0; // 這裏或 0的目的就是,當parseInt取整失敗的話,給一個默認值0 var step = (target - leader) / 10; step = step > 0 ? Math.ceil(step) : Math.floor(step); leader += step; // 設置指定樣式 element.style[attr] = leader + "px"; if (leader == target) { clearInterval(element.timer); } }, 15); } animate(box, "left", 800);
上面的代碼咱們對它的返回值進行了處理,並且還能夠對它設置其餘的樣式,只要單位是px
的屬性均可以設置。可是這裏每次仍是隻能設置一個樣式,下面咱們來實現修改多個樣式。
注意: leader = parseInt(leader) || 0;
"或"上0
的目的就是:當有些屬性設置的值不是數字的時候,好比:auto
,這時候parseInt
轉換的結果是NaN
。當"或"上0
以後,轉換失敗後,leader
,就會默認是0
。
二、遍歷一個對象:
讓咱們來複習一下,js基礎的時候,咱們接觸到了對象,而且知道了能夠用for..in
的方法來遍歷對象。咱們知道getComputedStyle
方法,獲取計算後樣式的時候,返回的是一個名叫CSSStyleDeclaration
的對象,這個對象裏面是全部的樣式屬性,咱們想要對這些屬性進行多個操做的時候,就能夠經過遍歷的方法。
for(k in obj){ // k :就是至關於對象的鍵 // obj :就是須要遍歷的對象 }
三、同時修改多個樣式:
同時修改多個樣式,就是將要修改的多個屬性以對象的形式做爲參數傳進函數中。
[20-緩動動畫修改多個樣式.html]
var box = document.getElementById('box'); var btn = document.getElementById('btn'); // 封裝一個函數,element 表示執行動畫的元素 obj傳的是一個對象,裏面能夠設置多個屬性和值 function animate(element, obj) { clearInterval(element.timer); element.timer = setInterval(function() { // 遍歷外部傳進來的對象 for (k in obj) { //attr : 要作動畫的樣式 //target : 目標值 var attr = k; var target = obj[k]; // 獲取元素開始時計算後的樣式 var leader = getStyle(element, attr); leader = parseInt(leader) || 0; // 緩動動畫函數原理 var step = (target - leader) / 10; step = step > 0 ? Math.ceil(step) : Math.floor(step); leader += step; // 給元素設置以樣式屬性名爲attr的值 // 這個封裝的動畫函數只能改值是px單位的樣式 element.style[attr] = leader + "px"; if (leader == target) { clearInterval(element.timer); } } }, 15); } // 處理兼容性 function getStyle(element, attr) { if (window.getComputedStyle) { return window.getComputedStyle(element, null)[attr]; } else { return element.currentStyle[attr]; } } // 調用函數 設置了五個樣式屬性 btn.onclick = function() { animate(box, { width: 200, height: 200, left: 300, top: 300, // bprder-radius 應該轉爲駝峯命名法 而且值只能是100px的格式 不能是百分比 borderRadius: 100 }); }
效果圖:
經過上面封裝的函數咱們能夠改變多個樣式,可是效果圖中咱們能夠看到一個問題,就是當到達設定值後,點擊按鈕還會慢慢的抖動。緣由是修改多個樣式的時候,全部的樣式並不能都到同時達終點。
出現這個bug的緣由:在for循環中判斷是否到達目標值,到達後就清除定時器,可是咱們同時修改了5個樣式,可能有的樣式到達目標值後就清楚定時器了,可是有的樣式還沒到達目標值,因此就出現了上面的
bug
。
解決方法:假設成立法
示例代碼: [21-緩動動畫修改多個樣式-修復定時器bug.html]
function animate(element, obj) { clearInterval(element.timer); element.timer = setInterval(function() { // 1-假設都到達了終點 var flag = true; for (k in obj) { var attr = k; var target = obj[k]; var leader = getStyle(element, attr); leader = parseInt(leader) || 0; var step = (target - leader) / 10; step = step > 0 ? Math.ceil(step) : Math.floor(step); leader += step; element.style[attr] = leader + "px"; // 2- 必需要等到全部的樣式都到達終點才清除定時器 // 只要有一個樣式沒有到達設定值,說明假設失敗 if (leader != target) { flag = false; } } // 全部的樣式都到達終點後 清除定時器 if (flag) { clearInterval(element.timer); } }, 15); }
通過前面幾小節的學習,咱們已經能夠實現同時修改多個樣式的緩動動畫了。可是細心的小夥伴不知道有沒有發現,目前只能設置跟px
有關係的樣式,包括設置border-radiu
也不算完善。這是由於咱們緩動動畫封裝的時後,設置的element.style[attr] = leader + "px";
,因此只能實現跟px
有關的樣式。
設置兼容其餘屬性的時候,要注意兩點,第一獲取的時候要進行判斷,設置的時候也要進行判斷
一、兼容opacity屬性: [22-緩動動畫修改多個樣式-兼容opacity.html]
function animate(element, obj) { clearInterval(element.timer); element.timer = setInterval(function() { var flag = true; for (k in obj) { var attr = k; var target = obj[k]; // 判斷得到的屬性是否是「opacity」,是的話單獨處理 var leader; // 得到當前值 if (attr === "opacity") { // 獲取的時候是個小數,將它乘以100 運算時不會出現精度丟失 leader = getStyle(element, attr) * 100 || 1; } else { leader = getStyle(element, attr); leader = parseInt(leader) || 0; } var step = (target - leader) / 10; step = step > 0 ? Math.ceil(step) : Math.floor(step); leader += step; // 賦值 // 判斷是否是opacity屬性 是的話 單獨賦值 if (attr === "opacity") { // 由於開始的時候leader擴大了100倍 設置的時候 opacity只能是0-1 element.style[attr] = leader / 100; // opacity 還須要單獨處理,由於IE678 不支持opacity element.style.filter = "alpha(opacity=" + leader + ")"; } else { element.style[attr] = leader + "px"; } if (leader != target) { flag = false; } } if (flag) { clearInterval(element.timer); } }, 15); } // 處理獲取樣式兼容性 function getStyle(element, attr) { if (window.getComputedStyle) { return window.getComputedStyle(element, null)[attr]; } else { return element.currentStyle[attr]; } } // 調用這個函數 btn.onclick = function() { animate(box, { width: 200, height: 200, left: 300, top: 300, // 這裏是按照 0-100 設置不透明度的,由於小數計算的時候會出現精度丟失 opacity: 50 }); }
二、兼容zIndex屬性: [23-緩動動畫修改多個樣式-兼容zIndex.html]
zIndex這個屬性不須要緩動的執行改變層級,直接得到傳進來的值設置便可
// 賦值 if (attr === "opacity") { element.style[attr] = leader / 100; element.style.filter = "alpha(opacity=" + leader + ")"; // 判斷設置的時候是不是zIndex屬性 } else if (attr === "zIndex") { element.style.zIndex= leader; } else { element.style[attr] = leader + "px"; }
示例代碼: [24-緩動動畫淡入淡出效果.html]
btn1.onclick = function() { animate(box, { opacity: 100 }) } btn2.onclick = function() { animate(box, { opacity: 0 }) }
效果圖:
程序執行完畢,再次執行的函數。
示例代碼: [25-緩動動畫添加回調函數.html]
var box = document.getElementById('box'); var btn = document.getElementById('btn'); function animate(element, obj, fn) { clearInterval(element.timer); element.timer = setInterval(function() { var flag = true; for (k in obj) { var attr = k; var target = obj[k]; var leader = getStyle(element, attr); leader = parseInt(leader) || 0; var step = (target - leader) / 10; step = step > 0 ? Math.ceil(step) : Math.floor(step); leader += step; element.style[attr] = leader + "px"; if (leader != target) { flag = false; } } if (flag) { clearInterval(element.timer); // 全部程序執行完畢了,如今能夠執行回調函數了 // 只有傳遞了回調函數,才能執行,因此這裏要判斷一下 if (fn) { fn(); } /* fn&&fn(); */ } }, 15); } // 處理兼容性 function getStyle(element, attr) { if (window.getComputedStyle) { return window.getComputedStyle(element, null)[attr]; } else { return element.currentStyle[attr]; } } // 調用函數 btn.onclick = function() { animate(box, { left: 600 }, function() { animate(box, { top: 500, borderRadius: 50 }, function() { animate(box, { width: 400, borderRadius: 50 }); }); }); }
效果圖:
直接看效果圖:
效果如上圖,當咱們鼠標通過某一項時,小方塊會緩動移過去,當離開列表欄時,小方塊會回到最初的位置。當點擊某一項時小方塊的初始位置就會停留在該項上。
示例代碼: [26-筋斗雲案例.html]
<!-- 樣式部分 --> <style> body { padding: 0; margin: 0; background: #333; } #box { width: 800px; height: 34px; margin: 100px auto; background: orange; position: relative; } ul { padding: 0 50px; height: 34px; position: relative; } #box ul li { float: left; width: 100px; height: 34px; line-height: 34px; text-align: center; list-style: none; font-size: 18px; font-family: '方正'; color: #fff; cursor: pointer; } #over { position: absolute; top: -3px; left: 51px; width: 100px; height: 38px; background: orangered; } </style> <!-- html 部分 --> <div id='box'> <span id='over'></span> <ul id='nav'> <li>首頁</li> <li>社區服務</li> <li>智慧超市</li> <li>便民</li> <li>圈子</li> <li>活動</li> <li>聚優惠</li> </ul> </div> <!-- js 部分 --> <script> var over = document.getElementById('over'); var nav = document.getElementById('nav'); var lis = nav.children; for (var i = 0; i < lis.length; i++) { lis[i].onmouseover = function() { // 鼠標通過時移動的距離就是它距離左邊的距離 slowAnimate(over, this.offsetLeft); } // 設定默認位置,由於第一個選項距離左邊爲51px距離因此,默認值設置爲51 var staticLeft = 51; lis[i].onmouseout = function() { // 鼠標離開的時候,要讓它回到默認位置 slowAnimate(over, staticLeft); } lis[i].onclick = function() { // 當點擊某一選項的時候,將默認位置設置爲此時的位置 staticLeft = this.offsetLeft; } } // 緩動動畫 function slowAnimate(element, target, num) { clearInterval(element.timer); element.timer = setInterval(function() { var leader = element.offsetLeft; // num 不傳的話,默認是10 var step = (target - leader) / (num || 10); step = step > 0 ? Math.ceil(step) : Math.floor(step); leader += step; element.style.left = leader + 'px'; if (leader == target) { clearInterval(element.timer); } }, 15); } </script>
在網頁中常常會出現廣告,咱們舉個例子讓關閉廣告的時候有一個動畫效果。
實現原理:
0
,因此會出現一個向下的效果0
,因此出現一個向右的效果示例代碼: [27-右下角關閉廣告案例.html]
<!-- 樣式部分 --> <style> #box { width: 213px; position: fixed; bottom: 0; right: 0; overflow: hidden; } #close { position: absolute; top: 0; right: 0; width: 30px; height: 30px; cursor: pointer; color: #FFFFFF; text-align: center; } .img { display: block; width: 212px; z-index: 99; } </style> <!-- html 部分 --> <div id="box"> <div id="hd"> <span id="close"> x </span> <img src="../image/關閉廣告/banna_up.png" class="img" alt="" /> </div> <div id="bt"> <img src="../image/關閉廣告/banner_down.png" class="img" alt="" /> </div> </div> <!-- js 部分 --> <script src="../js/slow-animate-styles.js"></script> <script> var close = document.getElementById('close'); var box = document.getElementById('box'); var bt = document.getElementById('bt'); close.onclick = function() { slowAnimateStyles(bt, { height: 0 }, function() { slowAnimateStyles(box, { width: 0 }); }); } </script>
效果圖:
手風琴效果在網頁中用的也特別的多,下面咱們會介紹兩種實現的方法,固然我的比較偏好第二種。
一、浮動版手風琴
實現原理:
ul,li
進行佈局,li
左浮動,而且設置等分的寬度;li
註冊鼠標通過事件,當鼠標通過的時候利用排他原理,將全部的li
寬度設置成最小寬度,將當前通過的li
寬度設置一個最大寬度;li
再恢復到等分的寬度。示例代碼: [28-手風琴-浮動版.html]
<!-- 樣式部分 --> <style> * { margin: 0; padding: 0; list-style: none; } #box { width: 900px; height: 441px; margin: 100px auto; overflow: hidden; border-radius: 30px; } ul { /* ul的寬要比外面的盒子大一點,不然在添加動畫效果的時候,最後一個li會出現閃動 */ width: 120%; height: 100%; overflow: hidden; } li { width: 180px; height: 100%; float: left; } </style> <!-- html 部分 --> <div id="box"> <ul> <li></li> <li></li> <li></li> <li></li> <li></li> </ul> </div> <!-- js 部分 --> <script src="../js/slow-animate-styles.js"></script> <script> var box = document.getElementById('box'); var lis = box.getElementsByTagName("li"); for (var i = 0; i < lis.length; i++) { // 動態建立img標籤 var img = document.createElement("img"); img.src = "../image/手風琴/" + (i + 1) + ".png"; lis[i].appendChild(img); // 給全部li註冊鼠標通過事件,讓當前的li寬度變成 500,其他的li寬度變成100 lis[i].onmouseover = function() { for (var i = 0; i < lis.length; i++) { // 先讓全部的li寬度變成100 slowAnimateStyles(lis[i], { width: 100 }); // 鼠標當前通過的寬度爲500 slowAnimateStyles(this, { width: 500 }) } }; // 當鼠標離開的時候,因此的li 寬度恢復到180px lis[i].onmouseout = function() { for (var i = 0; i < lis.length; i++) { slowAnimateStyles(lis[i], { width: 180 }) } } } </script>
效果圖:
二、定位版手風琴
實現原理:
ul,li
結構,li
設置寬高,與圖片大小一致,設置絕對定li
添加背景圖片,由於li
絕對定位的緣由,此時全部的li
都疊在一塊兒li
設置left
值(left*i
),這時候li
就會依次排開overflow-hidden
屬性,將多餘的隱藏掉li
註冊鼠標鼠標通過事件,而後根據下面推算出的規律(當前鼠標通過的索引index
,他以前包括他本身的left
值都是,設定的最小值乘以對應的索引。而他後面的會將設定的最小值乘以對應的索引後再加上450
,這裏的450
不是一個固定值,根據規律找出來的)進行判斷,設置各自的left
值;大盒子沒有overflow-hidden
的時候:
畫個圖,理解一下:
找規律:
結合上面的圖片,咱們能夠找到一個規律
當鼠標在第1個li上的時候,li下標index爲0:
當鼠標在第2個li上的時候,li下標index爲1:
當鼠標在第3個li上的時候,li下標index爲2:
看出規律了嗎?
<=
鼠標懸停的的下標上的時候left
值 是50*i
>
鼠標懸停的的下標上的時候left
值 是50*i + ,450
(450不是固定的值,是通過計算出來的)示例代碼: 29-手風琴-定位版.html]
<!-- 樣式部分 --> <style> * { margin: 0; padding: 0; list-style: none; } #box { width: 700px; height: 440px; margin: 100px auto; position: relative; overflow: hidden; box-sizing: border-box; border-radius: 30px; } li { width: 700px; height: 440px; position: absolute; /* background: yellow; */ } </style> <!-- html 部分 --> <div id="box"> <ul> <li></li> <li></li> <li></li> <li></li> <li></li> </ul> </div> <!-- js 部分 --> <script src="../js/slow-animate-styles.js"></script> <script> var box = document.getElementById('box'); var lis = box.getElementsByTagName('li'); for (var i = 0; i < lis.length; i++) { lis[i].index = i; // 動態添加li的背景圖片 由於i下標從0開始,可是圖片序號是從1開始 因此jia1 lis[i].style.backgroundImage = "url(../image/手風琴/" + (i + 1) + ".png)"; // 如今都疊在一塊兒,設置left 讓他們分開來 700/5 ==> 140px lis[i].style.left = 140 * i + "px"; // 註冊鼠標通過事件,讓當前的顯示寬度爲500,其他的爲50 lis[i].onmouseover = function() { for (var i = 0; i < lis.length; i++) { // 判斷當i小於等於當前鼠標停留的下標的時候,給li的left設置 50*i if (i <= this.index) { slowAnimateStyles(lis[i], { left: 50 * i }); // 當i大於當前鼠標停留的索引的時候,給後邊的li的left設置 50*i + 450 } else { slowAnimateStyles(lis[i], { left: 50 * i + 450 }); } } } // 註冊鼠標離開事件,讓全部的li都恢復到最初的樣式 lis[i].onmouseout = function() { for (var i = 0; i < lis.length; i++) { slowAnimateStyles(lis[i], { left: 140 * i }); } } } </script>
效果圖:
旋轉木馬也叫旋轉輪播圖,在效果上它就是旋轉版的輪播圖,可是在實現原理上卻一點一不同
旋轉木馬原理:
ul
、li
方式將圖片包裹在li
裏,而且對每一個li
的大小、層級、不透明度以及定位的位置設置好datas
中pop
、unshift
、shift
、push
datas
裏的最後一項利用pop
刪除掉,而且返回這個刪除的數據,再將這個數據unshift
到數組的最前面。從新遍歷數組,執行一遍動畫datas
裏的最前面一項利用shift
刪除掉,而且返回這個刪除的數據,再將這個數據push
到數組的最後面。從新遍歷數組,執行一遍動畫示例代碼: [30-旋轉木馬輪播圖案例.html]
<!-- 樣式部分 --> <style> * { margin: 0; padding: 0; list-style: none; } body { background: #666; } .wrap { width: 1200px; margin: 200px auto; } .slide { height: 340px; position: relative; } .slide li { position: absolute; left: 300px; top: 0; } img { width: 100%; } .arrow { opacity: 0; position: relative; z-index: 99; top: 50%; } .arrow #left, .arrow #right { width: 40px; height: 90px; position: absolute; top: 50%; margin-top: -45px; background: url(../image/旋轉木馬/left.png); background-size: cover; z-index: 99; } .arrow #right { right: 0; background: url(../image/旋轉木馬/right.png); background-size: cover; } </style> <!-- html 部分 --> <div class="wrap" id="wrap"> <div class="slide" id="slide"> <ul> <li><img src="../image/1.jpg" alt=""></li> <li><img src="../image/2.jpg" alt=""></li> <li><img src="../image/3.jpg" alt=""></li> <li><img src="../image/4.jpg" alt=""></li> <li><img src="../image/5.jpg" alt=""></li> </ul> <div class="arrow" id="arrow"> <a href="javascript:;"><span id="left"></span></a> <a href="javascript:;"><span id="right"></span></a> </div> </div> </div> <!-- js 部分 --> <script src="../js/slow-animate-styles.js"> </script> <script> // 將其他四張位置與透明度等信息,存放在一個數組中 var datas = [{ "width": 300, "top": -20, "left": 150, "opacity": 20, "zIndex": 2 }, //0 { "width": 500, "top": 30, "left": 50, "opacity": 80, "zIndex": 3 }, //1 { "width": 600, "top": 100, "left": 300, "opacity": 100, "zIndex": 4 }, //2 { "width": 500, "top": 30, "left": 650, "opacity": 80, "zIndex": 3 }, //3 { "width": 300, "top": -20, "left": 750, "opacity": 20, "zIndex": 2 } //4 ]; var slide = document.getElementById('slide'); var lis = slide.getElementsByTagName('li'); var arrow = document.getElementById('arrow'); var left = document.getElementById('left'); var right = document.getElementById('right'); // 定義一個節流閥 var flag = true; // 一開始頁面刷新的時候,將datas裏的數據 動態添加進去 for (var i = 0; i < lis.length; i++) { slowAnimateStyles(lis[i], datas[i]); }; // 鼠標通過的時候 箭頭顯示 slide.onmouseover = function() { slowAnimateStyles(arrow, { opacity: 100 }) }; // 鼠標離開的時候 箭頭隱藏 slide.onmouseout = function() { slowAnimateStyles(arrow, { opacity: 0 }) }; // 點擊右箭頭的時候 // 利用數組的pop 和 unshift方法對數組datas進行操做 // pop 會刪除數組的最後一項,而且返回這一項。 unshift 會在數組的最前添加 right.onclick = function() { // 只有節流閥爲true的時候 點擊纔會執行裏面的代碼 if (flag) { // 電擊後一進來就將節流閥關上,再次點擊的時候就不會進來 flag = false; datas.unshift(datas.pop()); for (var i = 0; i < lis.length; i++) { // 點擊一次就要動畫渲染一次,datas[i] 實際上是一個對象 /* { "width": 300, "top": -20, "left": 150, "opacity": 20, "zIndex": 2 } */ slowAnimateStyles(lis[i], datas[i], function() { // 當動畫執行完,也就是回調函數觸發的時候,再將節流閥打開,這樣就能夠繼續點擊了 flag = true; }); } } } // 點擊左箭頭 // 利用數組的 shift 和 push方法對數組datas進行操做 // shift 會刪除數組的第一項,而且返回這一項。 push 會在數組的最後添加 left.onclick = function() { if (flag) { flag = false; datas.push(datas.shift()); for (var i = 0; i < lis.length; i++) { slowAnimateStyles(lis[i], datas[i], function() { flag = true; }); } } } </script>
效果圖: