javascript
用原生JS实现3D轮播效果
用原生JS實(shí)現(xiàn)3D輪播效果
實(shí)現(xiàn)思路:
效果如下:
視圖中顯示3張圖片,并通過(guò)CSS的透視和旋轉(zhuǎn)實(shí)現(xiàn)3D效果,當(dāng)無(wú)任何操作時(shí),圖片自動(dòng)循環(huán)輪播。當(dāng)鼠標(biāo)劃到輪播圖時(shí),則停止輪播,滑出時(shí)繼續(xù)自動(dòng)輪播,此效果通過(guò)觸發(fā)mouseenter和mouseleave事件和計(jì)時(shí)器來(lái)實(shí)現(xiàn)。當(dāng)鼠標(biāo)在輪播圖上向左右滑動(dòng)時(shí),根據(jù)方向輪播下一站或上一張圖片,通過(guò)觸發(fā)mousedown和mouseup事件時(shí),的鼠標(biāo)的clientX來(lái)判斷方向。
無(wú)縫輪播思路
視圖中都會(huì)顯示3張圖片,當(dāng)我們輪播到最后一張圖片時(shí),我們?cè)撛趺崔k呢???
我的思路:
如果要達(dá)到循環(huán)輪播效果,那么最后一張圖片結(jié)束后,我們就應(yīng)該繼續(xù)輪播第一張圖片,當(dāng)最后一張圖片為視圖中的最左側(cè)的圖片時(shí)則視圖中顯示的圖片應(yīng)當(dāng)是最后一張、第一張和第二張圖片,為了能讓這三張圖片組合到一起,所以我在最后添加了第一張圖片和第二張圖片,當(dāng)繼續(xù)輪播時(shí),則從正方向的第一張和第二張圖片開(kāi)始(相當(dāng)于我們開(kāi)到的是倒數(shù)的兩張,但輪播時(shí)是正數(shù)的兩張開(kāi)始),如果是逆向輪播,則看到的是正序的前兩張,輪播時(shí)從倒序輪播。
思路圖大致如下:
用一句話(huà)就是:正序的0、1與逆序的0、1進(jìn)行偷梁換柱,達(dá)到循環(huán)輪播效果。
代碼
HTML部分:
<div class="container"><div class="wrapper"><div class="slide pre-slide"><img src="img/img1.jpg"></div><div class="slide cur-slide"><img src="img/img2.jpg"></div><div class="slide next-slide"><img src="img/img3.jpg"></div><div class="slide"><img src="img/img4.jpg"></div></div></div>CSS部分
<style>* {margin: 0;padding: 0;}body {background-color: #000;}.container {margin: 50px auto;width: 1000px;height: 500px;/*background-color: #ececec;*/overflow: hidden;position: relative;}.wrapper {height: 500px;width: 900px;/*border: 1px solid #000;*//*注意:這里解決了slide的子元素之間的間距問(wèn)題————即使設(shè)置了margin和padding時(shí),子元素之間仍有間距(子元素之間存在空格或換行字符),所以這里需要設(shè)置字體大小為0*/font-size: 0px;/**/position: absolute;left: 0;top: 0;}.wrapper:hover {cursor: pointer;}.slide {width: 300px;height: 500px;display: inline-block;border: none;font-size: 32px;font-weight: 900;text-align: center;perspective: 600px;}.slide img {width: 100%;height: 100%;transform: translateZ(-500px);}.pre-slide img {/*background-color: rgb(56, 233, 50);*/transform: translateZ(0px) rotateY(45deg);transition: all 1.5s;}/**/.cur-slide img {/*background-color: rgb(57, 180, 236);*/transform: translateZ(100px);transition: all 1.5s;}.next-slide img {/*background-color: #f4f81c;*/transform: translateZ(0px) rotateY(-45deg);transition: all 1.5s;}JS部分
<script>/** * distance用來(lái)記錄每次輪播時(shí)的偏移量* prePos用來(lái)記錄輪播圖最左邊元素的Index* downPos用來(lái)記錄mousedown時(shí)鼠標(biāo)的clientX* flag用來(lái)記錄窗口移動(dòng)的方向,true向左,false向右* * * */let wrapper, slides, container, downPos, prePos, timeID, num;init();function init() {prePos = 0;flag = true;wrapper = document.querySelector('.wrapper')slides = document.getElementsByClassName('slide')container = document.querySelector('.container')num = slides.length;let firstNode = slides[0].cloneNode(true);let secondNode = slides[1].cloneNode(true);wrapper.appendChild(firstNode);wrapper.appendChild(secondNode);distance = slides[0].clientWidth;//初始化處理//根據(jù)slide的多少動(dòng)態(tài)設(shè)置wrapper的寬度wrapper.style['width'] = slides.length * distance + 'px';container.style.width = 3 * distance + 'px';//wrapper.style.left = -distance + 'px';//console.log(wrapper.style);timeID = setInterval(move, 3000);wrapper.addEventListener('mousedown', handelMouseDown, true);wrapper.addEventListener('mouseenter', handleMouseenter);wrapper.addEventListener('mouseleave', handleMouseleave);}function move() {updateClassName(prePos, 'slide')updateClassName(prePos + 1, 'slide')updateClassName(prePos + 2, 'slide')if (flag) {if (prePos === slides.length - 3) {prePos = 0;} else {prePos++;}} else {if (prePos === 0) {prePos = slides.length - 3;} else {prePos--;}}//console.log(prePos);wrapper.style.left = -prePos * distance + 'px';console.log(prePos);updateClassName(prePos, 'slide pre-slide')updateClassName(prePos + 1, 'slide cur-slide')updateClassName(prePos + 2, 'slide next-slide')}function updateClassName(pos, name) {switch (pos) {case 0:case slides.length - 2:console.log(name);slides[0].className = slides[slides.length - 2].className = namebreak;case 1:case slides.length - 1:slides[1].className = slides[slides.length - 1].className = namebreak;default:slides[pos].className = name;break;}}function handelMouseUp(e) {//console.log(e.clientX);if (e.clientX < downPos) {//console.log('左');flag = true;} else if (e.clientX > downPos) {//console.log('右');flag = false;}move();}function handleMouseenter(e) {//console.log('enter');clearInterval(timeID);}function handleMouseleave() {//console.log('leave');flag = true;timeID = setInterval(move, 3000)}function handelMouseDown(e) {//console.log(e.target);//此處解決連續(xù)對(duì)同一個(gè)sliede的mousedown和mouseup使用一次后失效的問(wèn)題//原因://觸發(fā)了瀏覽器的 drag 操作,導(dǎo)致mouseup丟失。//由于鼠標(biāo)離開(kāi)了操作的區(qū)域,觸發(fā)了mouseleave導(dǎo)致mouseup丟失。e.preventDefault(); //我可能遇到的是第一種情況//e.stopPropagation();downPos = e.clientX;wrapper.addEventListener('mouseup', handelMouseUp);} </script>在實(shí)現(xiàn)過(guò)程中可能會(huì)遇到一些問(wèn)題,我遇到的都體現(xiàn)在代碼注釋里面啦。
總結(jié)一下:
在開(kāi)始的時(shí)候我為了簡(jiǎn)單化問(wèn)題,于是我是只用了幾個(gè)div進(jìn)行輪播,當(dāng)基本上實(shí)現(xiàn)無(wú)縫輪播的時(shí)候,我在另一個(gè)文件中進(jìn)行圖片的3D效果測(cè)試(我也剛接觸前端不久,對(duì)CSS3的動(dòng)畫(huà)掌握也不太熟練),當(dāng)覺(jué)得兩個(gè)效果都差不多時(shí)再合并代碼,將圖片的3D效果添加到輪播圖中。合并后,也出現(xiàn)了一個(gè)問(wèn)題,比如當(dāng)輪播到最后一張后繼續(xù)正向輪播和到第一張后要逆向輪播時(shí),偷梁換柱的過(guò)程中,會(huì)出現(xiàn)輪播效果和前一次相同方向輪播的效果不一致的問(wèn)題。關(guān)于這一點(diǎn),我被自己繞了很久,當(dāng)后面想通后,也就清晰明了了。出現(xiàn)這個(gè)問(wèn)題的原因是因?yàn)槲以诖a實(shí)現(xiàn)的過(guò)程中,將正序的0、1和逆序的0、1獨(dú)立化了,而它們本不應(yīng)該相互獨(dú)立,如果獨(dú)立了,它們就存在className不一致的問(wèn)題,那么它們?cè)谳啿デ暗囊淮螤顟B(tài)就不一樣,那么效果的呈現(xiàn)也就不一樣了,于是出現(xiàn)了updateClassName方法,當(dāng)修改每個(gè)slide的className時(shí),不管是正序0\1或是倒敘的,其正序的0與倒敘的0、正序的1和倒敘的1的className都要更新為最新的className,才能達(dá)到做好偷梁換柱。
除此之外,也遇到?jīng)]有記住的小問(wèn)題:
容器之間存在空格字符或換行符,都視為一個(gè)空格字符,這個(gè)字符也有大小,也就是我們所見(jiàn)的間隙,將其父容器的font-size設(shè)為0則可以解決。
當(dāng)mousedown觸發(fā)后,可能會(huì)觸發(fā)瀏覽器的默認(rèn)事件,在mousedown的回調(diào)函數(shù)中使用e.preventDefault()禁止觸發(fā)默認(rèn)事件就可以。
最后
我把代碼放到倉(cāng)庫(kù)啦,代碼還有待完善的空間,請(qǐng)各位多多指教:
鏈接: 代碼.
總結(jié)
以上是生活随笔為你收集整理的用原生JS实现3D轮播效果的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: 固态硬盘对于linux提升,固态硬盘在L
- 下一篇: 【学习】自学JavaScript