溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊(cè)×
其他方式登錄
點(diǎn)擊 登錄注冊(cè) 即表示同意《億速云用戶服務(wù)條款》

如何使用CSS+JS幫你實(shí)現(xiàn)蘋果cover flow效果

發(fā)布時(shí)間:2021-11-12 10:48:48 來源:億速云 閱讀:157 作者:小新 欄目:web開發(fā)

小編給大家分享一下如何使用CSS+JS幫你實(shí)現(xiàn)蘋果cover flow效果,希望大家閱讀完這篇文章之后都有所收獲,下面讓我們一起去探討吧!

<!DOCTYPE html> <html lang="en"> <head>     <meta charset="UTF-8">     <title>coverflow-demo</title>     <style>         div.innerWrapper{             perspective: 300px;             width: 600px;             height: 300px;             margin: 100px auto;             display: flex;              align-items:flex-start;             background-color: #000;              overflow: hidden;              padding-top: 5%;         }         div.cover{             height: 50%;              flex-grow:1;             transition: all .5s ease;             background-size: 100% 100%;              background-repeat:no-repeat;             margin: 0;              -webkit-box-reflect:below 5% linear-gradient(transparent, white);             border: 1px solid #fff;          }         div.cover:nth-child(1){             background-image: url('covers/computergraphics-album-covers-2014-15.jpg');         }         div.cover:nth-child(2){             background-image: url('covers/Funkadelic-Maggot-Brain-album-covers-billboard-1000x1000.jpg');         }         div.cover:nth-child(3){             background-image: url('covers/Green-Day-American-Idiot-album-covers-billboard-1000x1000.jpg');         }         div.cover:nth-child(4){             background-image: url('covers/insurgency-digital-album-cover-design.jpg');         }         div.cover:nth-child(5){             background-image: url('covers/Pink-Floyd-Dark-Side-of-the-Moon-album-covers-billboard-1000x1000.jpg');         }         div.cover:nth-child(6){             background-image: url('covers/sonic-quiver-time-and-space1-1000x1000.jpg');         }         div.cover:nth-child(7){             background-image: url('covers/tumblr_inline_nydppi1Mp91t7tdyh_500.jpg');         }         button[required='required']{             background-color: #000;          }     </style> </head> <body>     <div class='container'>         <div class="innerWrapper">             <div></div>             <div></div>             <div></div>             <div></div>             <div></div>             <div></div>             <div></div>         </div>     </div>     <button required='required'>222</button>     <script>     ;(function(parent){         var cards = parent.querySelectorAll('div'), coverCount = cards.length, middleIndex = (coverCount-1)/2, middleCover = cards[middleIndex], parentWidth = middleCover.parentNode.clientWidth, currentIndex = middleIndex;          var maxRotate = 42, stepper = maxRotate/middleIndex, maxZIndex = middleIndex + 1;          var rotateReg = /rotateY\((\-?\d{1,3}\.?\d*)deg\)/, translateReg = /translateX\((\-?\d{1,3}\.?\d*)px\)/;          // debugger;          for(var i = 0; i<coverCount; i++){             var elem = cards[i];              elem.classList.add('cover');              elem.style.transform = 'translateX(0px) rotateY(' + (maxRotate-(i*stepper).toFixed(0)) + 'deg)';              elem.style.flexGrow = 1;              if(i<middleIndex){                 elem.style.zIndex = i+1;              }else if(i == middleIndex){                 elem.style.zIndex = i+1;                  elem.style.flexGrow = 2;              }else{                 elem.style.zIndex = coverCount - i;              }         }         function move(direction){             if(currentIndex==(direction=='right'?0:coverCount-1))return;              direction=='right'?currentIndex--:currentIndex++;              maxZIndex++;              [].forEach.call(cards, function(element, index) {                 var previousRotate = parseInt(element.style.transform.match(rotateReg)[1]);                  var previousTranslate = parseInt(element.style.transform.match(translateReg)[1]);                 // translateX + 80 px one right button is clicked                 var currentRotate, currentTranslate;                  if(direction=='right'){                     currentRotate = previousRotate-stepper;                      currentTranslate = previousTranslate+(parentWidth/(coverCount+1));                  }else{                     currentRotate = previousRotate+stepper;                      currentTranslate = previousTranslate-(parentWidth/(coverCount+1));                  }                 element.style.transform = 'translateX(' + currentTranslate + 'px) rotateY('+ currentRotate +'deg)'                 // element.style.zIndex =                  if(index == currentIndex){                     element.style.flexGrow = 2;                      element.style.zIndex = maxZIndex;                   }else{                     element.style.flexGrow = 1;                  }             });         }         document.addEventListener('keyup', function(e){             if(e.which == 37){                 move('right');              }else if(e.which == 39){                 move('left');              }         })     })(document.querySelector('.innerWrapper'));      </script> </body> </html>

稍微解釋下這里用到的幾個(gè)知識(shí)點(diǎn):

1. flex-box.

什么是flex-box捏, 它是為了適應(yīng)當(dāng)前設(shè)備屏幕大小不一而提出的一種display方法. 當(dāng)一個(gè)父元素的顯示被設(shè)定為display:flex時(shí),  它內(nèi)部的子元素們會(huì)被平均分配占滿父元素的空間, 并且當(dāng)父元素的尺寸變化時(shí), 子元素的尺寸也會(huì)相應(yīng)變化! 是不是很神奇呢? 不僅如此,  你還可以任意分配子元素們的排列順序, 如果覺得某個(gè)子元素需要突出顯示, 就可以給這個(gè)子元素以特殊身份, 讓它相比其他子元素大一些, 或者小一些!  由于其的自適應(yīng)特性, flex是移動(dòng)開發(fā)的一把利器, 我們先來看看一個(gè)小應(yīng)用:

設(shè)計(jì)一個(gè)對(duì)話框函數(shù), 當(dāng)傳入一個(gè)回調(diào)函數(shù)時(shí), 只顯示一個(gè)'確定'按鈕, 占100%寬度; 當(dāng)傳入兩個(gè)回調(diào)函數(shù)(確定和取消)時(shí),  分別顯示'確定'和'取消'按鈕, 各占50%寬度, 樣式分別如下:

如何使用CSS+JS幫你實(shí)現(xiàn)蘋果cover flow效果

如何使用CSS+JS幫你實(shí)現(xiàn)蘋果cover flow效果

怎么實(shí)現(xiàn)呢? 我們當(dāng)然可以用JS來做, 但是(凡事就怕一個(gè)但是哈哈)! 我們作為有追求的前端, 戰(zhàn)斗在CSS探索的***線,  現(xiàn)在有了如此好用的flex屬性, 為毛不立馬用起來呢? 說走咱就走, 按鈕容器和按鈕本身的CSS如下:

如何使用CSS+JS幫你實(shí)現(xiàn)蘋果cover flow效果

如何使用CSS+JS幫你實(shí)現(xiàn)蘋果cover flow效果


關(guān)鍵是按鈕的width:100%屬性. 有了它, 當(dāng)容器里只有一個(gè)按鈕時(shí), 它的寬度會(huì)拓展為容器的100%寬度; 而當(dāng)容器里有兩個(gè)按鈕時(shí),  按鈕的寬度都為100%, 怎么辦呢? 由于兩個(gè)按鈕勢(shì)均力敵, 它們只好平分秋色, 各占50%的空間了!

有的同學(xué)要問了: 要是我不想按鈕把空間占滿怎么辦呢? 這時(shí)候, 可以設(shè)定按鈕的寬度各為45%,  然后在父元素上設(shè)置justify-content:center, 意思是兩個(gè)子元素只占了90%的橫向空間, 那怎么分配剩下的10%空間呢?  那就兩邊各分配5%吧! 除此之外, 該屬性的其它值, 可以讓子元素左右對(duì)齊, 更多flexbox的神奇應(yīng)用, 請(qǐng)參考這篇文章~

A Complete Guide to Flexbox

回到我們的例子. 在卡片們沒有被應(yīng)用transform屬性之前, 它們看起來是這個(gè)樣子的:

如何使用CSS+JS幫你實(shí)現(xiàn)蘋果cover flow效果

七個(gè)元素平均分布, 占據(jù)了父元素的全部橫向空間. 其中中間的元素應(yīng)用了flex-grow:2的屬性, 使得它比其他元素高人一等,  面積是其他元素的兩倍~~

2. transform

其實(shí)有了上一幅圖, 初始頁面的雛形就已經(jīng)差不多了~現(xiàn)在只需要給父元素設(shè)置視角(關(guān)于視角, 3D變換等內(nèi)容, 請(qǐng)見我的這一篇文章).  為了得到比較明顯3D效果, 設(shè)置了父元素的perspective為較小的值300px, 就相當(dāng)于從距離3D變換平面300px的距離看.  perspective的值越大, 相當(dāng)于從越遠(yuǎn)的距離看, 3D效果越不明顯, 平面化效果越強(qiáng)烈~

設(shè)置好了視角, 接下來該給元素們?cè)O(shè)置3D效果了. ***步很簡(jiǎn)單: 假設(shè)有7個(gè)元素, 沿Y軸***旋轉(zhuǎn)角度為42度, 則0,1,2號(hào)元素分別旋轉(zhuǎn)42, 28,  14度, 3號(hào)元素旋轉(zhuǎn)0度同時(shí)變大2倍,4,5,6號(hào)元素分別旋轉(zhuǎn)-14, -28, -42度. 用一個(gè)簡(jiǎn)單的for循環(huán)就可以完成這項(xiàng)任務(wù), 代碼如下:

for(var i = 0; i<coverCount; i++){             var elem = cards[i];              elem.classList.add('cover');              // 設(shè)置元素的translateX為0px, 旋轉(zhuǎn)角度為***旋轉(zhuǎn)角度-目錄值*步進(jìn)值             elem.style.transform = 'translateX(0px) rotateY(' + (maxRotate-(i*stepper).toFixed(0)) + 'deg)';              elem.style.flexGrow = 1;              // 設(shè)置元素的z-index以區(qū)分前后順序, 并將中間元素設(shè)置大一些             if(i<middleIndex){                 elem.style.zIndex = i+1;              }else if(i == middleIndex){                 elem.style.zIndex = i+1;                  elem.style.flexGrow = 2;              }else{                 elem.style.zIndex = coverCount - i;              }         }

初始化完成后效果圖如下:

如何使用CSS+JS幫你實(shí)現(xiàn)蘋果cover flow效果 

此時(shí)每個(gè)卡片的translateX為0, 這個(gè)值要預(yù)先寫好, 才能通過改變?cè)撝祦韺?shí)現(xiàn)卡片的左右移動(dòng)效果; rotateY的值分別為42, 28, 14,  0, -14, -28, 42度; flex-grow(相對(duì)于其它子元素的大小)分別為1, 1, 1, 2, 1, 1, 1

3.-webkit-box-reflect

那么漂亮的倒影是怎么實(shí)現(xiàn)的呢? 哈哈其實(shí)一行CSS就能搞定, 那就是強(qiáng)大的-webkit-box-reflect, 值為below 5%  linear-gradient(transparent, white). 相信聰明的小伙伴看到這里已經(jīng)明白了大概了, 為了避免誤解,  稍稍再解釋一下~below是倒影在盒子下方, 5%表示offset, 和盒子的距離是盒子寬度的5%, linear-gradient(transparent,  white)指的是倒影的顏色, 從透明到完全不透明. 漸變語法的顏色在這里起作用的只有透明度, 白色的顏色是不會(huì)顯出來的~到這里, 我們用的大部分都是CSS,  效果圖如下:

如何使用CSS+JS幫你實(shí)現(xiàn)蘋果cover flow效果

然而靜態(tài)的展示是不夠的, 我們的目標(biāo)是! 要讓它動(dòng)起來! 來回左右動(dòng)! 到這里CSS已經(jīng)無能為力, 改JS閃亮登場(chǎng)的時(shí)候了!~

4.JS控制

控制左右移動(dòng)的函數(shù)如下, 接受一個(gè)參數(shù)left或者right表示要移動(dòng)的方向~

// 定義提取旋轉(zhuǎn)角度和translateX值的正則, 例如 -> $0.style.transform.match(/rotateY\((\-?\d{1,3}\.?\d*)deg\)/) <- ["rotateY(14deg)", "14"]        var rotateReg = /rotateY\((\-?\d{1,3}\.?\d*)deg\)/, translateReg = /translateX\((\-?\d{1,3}\.?\d*)px\)/;         function move(direction){            // 當(dāng)前值為0或者當(dāng)前值為卡片數(shù)目時(shí), 返回            if(currentIndex==(direction=='right'?0:coverCount-1))return;             // 當(dāng)前值自增或者自減            direction=='right'?currentIndex--:currentIndex++;             // ***Z-index自增            maxZIndex++;             [].forEach.call(cards, function(element, index) {                // 提取變換之前的旋轉(zhuǎn)角度                var previousRotate = parseInt(element.style.transform.match(rotateReg)[1]);                 // 提取變換之前的translateX                var previousTranslate = parseInt(element.style.transform.match(translateReg)[1]);                var currentRotate, currentTranslate;                 if(direction=='right'){                    // 計(jì)算rotatey的值                    currentRotate = previousRotate-stepper;                     // 計(jì)算平移的距離                    currentTranslate = previousTranslate+(parentWidth/(coverCount+1));                 }else{                    currentRotate = previousRotate+stepper;                     currentTranslate = previousTranslate-(parentWidth/(coverCount+1));                 }                // 寫入元素屬性                element.style.transform = 'translateX(' + currentTranslate + 'px) rotateY('+ currentRotate +'deg)'                // element.style.zIndex =                 if(index == currentIndex){                    element.style.flexGrow = 2;                     // 不斷寫入maxZIndex, 確保翻過的元素始終在最前面                    element.style.zIndex = maxZIndex;                  }else{                    element.style.flexGrow = 1;                 }            });        }

再給按鈕或者鍵盤增加事件監(jiān)聽, 這樣就完成啦!

看完了這篇文章,相信你對(duì)“如何使用CSS+JS幫你實(shí)現(xiàn)蘋果cover flow效果”有了一定的了解,如果想了解更多相關(guān)知識(shí),歡迎關(guān)注億速云行業(yè)資訊頻道,感謝各位的閱讀!

向AI問一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長(zhǎng)郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI