利用JavaScript實(shí)現(xiàn)簡(jiǎn)單3D開(kāi)關(guān)書(shū)本模型
序言
今天我們不聊干貨,來(lái)看一些用JS也能實(shí)現(xiàn)的輕松有趣的小Demo,首先我們先看實(shí)驗(yàn)效果圖。
看完這張圖后 直接把代碼附上!
HTML代碼
<!DOCTYPE html> <html lang="en"> <head> ? ? <meta charset="UTF-8"> ? ? <meta name="viewport" content="width=device-width, initial-scale=1.0"> ? ? <title>Document</title> ? ? <link rel="stylesheet" href="style.css" rel="external nofollow" rel="external nofollow" > </head> <body> ? ? <div class="book p3d"> ? ? ? ? <div class="front-cover p3d"> ? ? ? ? ? <div class="inside page p3d flip"> ? ? ? ? ? ? <p>瓦羅蘭特(VALORANT)是一款第一人稱FPS游戲。 ? ? ? ? ? ? ? ? 與傳統(tǒng)FPS游戲不同,游戲中每個(gè)角色都擁有其不一樣的技能,小隊(duì)角色之間的技能互相搭配進(jìn)攻能發(fā)揮更強(qiáng)的作用。 ? ? ? ? ? ? ? ? 背景設(shè)定:在近未來(lái)的地球世界里,全球范圍遭遇了一個(gè)重要的事件,名為First Light(原初之光),這個(gè)事件改變了地球,帶來(lái)了生命、科技和政府運(yùn)行的大轉(zhuǎn)變。 ? ? ? ? ? ? ? ? 部分地球人在這個(gè)事件中獲得了超能力,這些擁有超能力的人們被稱為“Radiants(輻射人)”,意味著他們是被原初之光輻射從而獲得了超能力。</p> ? ? ? ? ? </div> ? ? ? ? ? <div class="outside page"></div> ? ? ? ? </div> ? ? ? ? <div class="back-cover p3d"> ? ? ? ? ? ? <div class="outside page p3d"> ? ? ? ? ? ? ? ? <div class="inside page p3d"> ? ? ? ? ? ? ? ? ? ? <div class="shadow"></div> ? ? ? ? ? ? ? ? ? ? <div class="card"></div> ? ? ? ? ? ? ? ? </div> ? ? ? ? ? ? </div> ? ? ? ? </div> ? ? </div> ? ? <script src="index.js"></script> </body> </html>
CSS代碼
*{ ? ? margin: 0; ? ? padding: 0; ? ? border: 0; ? ? vertical-align: baseline; ? ? box-sizing: border-box; ?/*將容器聲明成IE模型*/ } html{ ? ? height: 100%; } body{ ? ? height: 100%; ? ? font: 100% / 1.25 Helvetica,arial,sans-serif; ? ? perspective: 1000px; ? ? background-color: #444; ? ? background-image: linear-gradient(to bottom,#444,#999); } .p3d{ ? ? transform-style: preserve-3d; } .book{ ? ? width: 300px; ? ? height: 300px; ? ? position: absolute; ? ? left: 50%; ? ? top: 50%; ? ? /* transform: translateY(-50%); */ ? ? margin-top: -150px; ? ? color: #fff; ? ? -webkit-transform: rotateX(60deg); ? ? -moz-transform: rotateX(60deg); ? ? -o-transform: rotateX(60deg); ? ? user-select: none; } .front-cover{ ? ? cursor: move; ? ? transform-origin: 0 50%; ? ? transform: rotateY(0deg); } .page{ ? ? width: 300px; ? ? height: 300px; ? ? padding: 1em;/*相對(duì)父容器大小*/ ? ? position: absolute;/*脫離文檔流*/ ? ? left: 0; ? ? top: 0; ? ? text-indent: 2em; } .inside{ ? ? background-color: #2a0303; } .outside{ ? ? background-color: #fff; } .front-cover .outside{ ? ? background-image: url(https://gimg2.baidu.com/image_search/src=http%3A%2F%2Fimg.nga.178.com%2Fattachments%2Fmon_202006%2F02%2FjoQ5-38t6XlZ5pT3cS2yo-1o0.png&refer=http%3A%2F%2Fimg.nga.178.com&app=2002&size=f9999,10000&q=a80&n=0&g=0n&fmt=auto?sec=1700461884&t=fb89517f74280d519c31d1b97adb1af3); ? ? background-repeat: no-repeat; ? ? background-size: cover; ? ? transform: translateZ(3px); ? } .flip{ ? ? transform: rotateY(180deg); } .back-cover .outside{ ? ? transform: translateZ(-3px); } .back-cover .inside{ ? ? background-color: #1e0000; } .card, .shadow{ ? ? width: 196px; ? ? height: 132px; ? ? position: absolute; ? ? left: 60px; ? ? top: 60px; ? ? transform-origin: 0 100%; } .shadow{ ? ? background-color: rgba(0,0,0,0.5); } .card{ ? ? background-image: url(https://images.9k9k.com/m/gamelib/202011/90947_zkyz.jpg); ? ? background-size: cover; ? ? transform-origin: 0 100%; }
JS代碼
var front = document.getElementsByClassName('front-cover')[0] var book = document.getElementsByClassName('book')[0] var card = document.getElementsByClassName('card')[0] var shadow = document.getElementsByClassName('shadow')[0] var hlod = false var clamp = function(val,min,max){ ? ? return Math.max(min,Math.min(val,max)) } //鼠標(biāo)是否按下 front.onmousedown = function(){ ? ? hlod = true } //在window上監(jiān)聽(tīng)鼠標(biāo)松開(kāi) window.onmouseup = function(){ ? ? hlod = false } window.onmousemove = function(e){ ? ? if(hlod){ ? ? ? ? //修改左半邊書(shū)的角度,卡片旋轉(zhuǎn),陰影傾斜 ? ? ? ? var deg = clamp((window.innerWidth / 2 - e.x + 300) / 300 * -90, -180, 0) ? ? ? ? front.style.transform = `rotateY(${deg}deg)` ? ? ? ? //整本書(shū)立起來(lái) 60 + deg / 8 ? ? ? ? book.style.transform = `rotateX(${60 + deg / 8}deg)` ? ? ? ? //卡片 deg / 2 ? ? ? ? card.style.transform = `rotateX(${deg / 3}deg)` ? ? ? ? //陰影傾斜 deg / 8 (css樣式傾斜) ? ? ? ? shadow.style.transform = `skew(${deg / 8}deg)` ? ? } } console.log(front); var front = document.getElementsByClassName('front-cover')[0] var book = document.getElementsByClassName('book')[0] var card = document.getElementsByClassName('card')[0] var shadow = document.getElementsByClassName('shadow')[0] var hlod = false var clamp = function(val,min,max){ ? ? return Math.max(min,Math.min(val,max)) } //鼠標(biāo)是否按下 front.onmousedown = function(){ ? ? hlod = true } //在window上監(jiān)聽(tīng)鼠標(biāo)松開(kāi) window.onmouseup = function(){ ? ? hlod = false } window.onmousemove = function(e){ ? ? if(hlod){ ? ? ? ? //修改左半邊書(shū)的角度,卡片旋轉(zhuǎn),陰影傾斜 ? ? ? ? var deg = clamp((window.innerWidth / 2 - e.x + 300) / 300 * -90, -180, 0) ? ? ? ? front.style.transform = `rotateY(${deg}deg)` ? ? ? ? //整本書(shū)立起來(lái) 60 + deg / 8 ? ? ? ? book.style.transform = `rotateX(${60 + deg / 8}deg)` ? ? ? ? //卡片 deg / 2 ? ? ? ? card.style.transform = `rotateX(${deg / 3}deg)` ? ? ? ? //陰影傾斜 deg / 8 (css樣式傾斜) ? ? ? ? shadow.style.transform = `skew(${deg / 8}deg)` ? ? } } console.log(front);
代碼解釋
html部分
引入文件
我們創(chuàng)建的CSS和js文件都需要引入到html文件中
在頭部標(biāo)記里用link方法引入css文件
<head> <link rel="stylesheet" href="style.css" rel="external nofollow" rel="external nofollow" > </head>
在body里用< script >標(biāo)簽引入js文件
<body> <script src="index.js"></script> </body>
HTML框架構(gòu)建(BEM命名法)
我們將整本書(shū)分成了多個(gè)部分,總體就是一個(gè)book,然后根據(jù)想要實(shí)現(xiàn)的效果或者其功能將其劃分成不同子塊
<div class="book p3d"> ? ? ? ? <div class="front-cover p3d"> ? ? ? ? ? <div class="inside page p3d flip"> ? ? ? ? ? ? <p> ? ? ? ? ? </div> ? ? ? ? ? <div class="outside page"></div> ? ? ? ? </div> ? ? ? ? <div class="back-cover p3d"> ? ? ? ? ? ? <div class="outside page p3d"> ? ? ? ? ? ? ? ? <div class="inside page p3d"> ? ? ? ? ? ? ? ? ? ? <div class="shadow"></div> ? ? ? ? ? ? ? ? ? ? <div class="card"></div> ? ? ? ? ? ? ? ? </div> ? ? ? ? ? ? </div> ? ? ? ? </div> ? ? </div>
結(jié)構(gòu)劃分完了剩下的交給CSS樣式編寫(xiě)就可以了。
CSS樣式編寫(xiě)
*{ ? ? margin: 0; ? ? padding: 0; ? ? border: 0; ? ? vertical-align: baseline; ? ? box-sizing: border-box; ?/*將容器聲明成IE模型*/ }
瀏覽器默認(rèn)會(huì)給body加一個(gè)內(nèi)外邊距,所以我們將其設(shè)置為0,之前文章我們了解知道了,CSS中有兩種盒模型,我們現(xiàn)在將其設(shè)置為box-sizing:border-box IE盒模型,為了讓頁(yè)面效果更完美的展現(xiàn)出來(lái)。
-webkit-transform: rotateX(60deg); ? ? -moz-transform: rotateX(60deg); ? ? -o-transform: rotateX(60deg);
-webkit-transform、-moz-transform、-o-transform分別是針對(duì)不同瀏覽器的前綴,以兼容不同瀏覽器。在現(xiàn)代瀏覽器中,大多數(shù)已經(jīng)支持transform屬性并可以省略前綴。
這里我們是將元素繞X軸旋轉(zhuǎn)60度,但需要注意編寫(xiě)的時(shí)候具體怎么設(shè)置角度,我們需要還要根據(jù)頁(yè)面呈現(xiàn)效果和其他樣式屬性來(lái)確定。
.page{ ? ? width: 300px; ? ? height: 300px; ? ? padding: 1em; ? ? position: absolute; ? ? left: 0; ? ? top: 0; ? ? text-indent: 2em; }
padding: 1em;
em是指相對(duì)父容器大小
position: absolute;
會(huì)導(dǎo)致其脫離文檔流
JS交互功能編寫(xiě)
在這段JS代碼中,主要是用來(lái)實(shí)現(xiàn)當(dāng)我們通過(guò)鼠標(biāo)拖拽前封面(front)時(shí),會(huì)觸發(fā)相應(yīng)的事件,從而控制頁(yè)面元素的旋轉(zhuǎn)角度,實(shí)現(xiàn)一個(gè)交互效果。
var front = document.getElementsByClassName('front-cover')[0] var book = document.getElementsByClassName('book')[0] var card = document.getElementsByClassName('card')[0] var shadow = document.getElementsByClassName('shadow')[0]
具體來(lái)說(shuō),首先通過(guò)document.getElementsByClassName()方法獲取了front、book、card、shadow四個(gè)元素。
front.onmousedown = function(){ ? ? hlod = true }
并定義了hlod變量表示鼠標(biāo)是否按下。
front.onmousedown = function(){ ? ? hlod = true } window.onmouseup = function(){ ? ? hlod = false }
接下來(lái),代碼通過(guò)給front元素綁定mousedown事件來(lái)監(jiān)聽(tīng)鼠標(biāo)按下的動(dòng)作,當(dāng)鼠標(biāo)按下時(shí),將hlod設(shè)為true。然后,通過(guò)給window綁定mousemove和mouseup事件來(lái)監(jiān)聽(tīng)鼠標(biāo)移動(dòng)和松開(kāi)的動(dòng)作。當(dāng)鼠標(biāo)移動(dòng)時(shí),如果hlod為true,就計(jì)算出deg的值,其值由用戶當(dāng)前鼠標(biāo)位置決定。clamp()函數(shù)用于限制deg變量的取值范圍在-180到0之間。隨后,代碼通過(guò)修改相應(yīng)元素的transform屬性來(lái)實(shí)現(xiàn)立體旋轉(zhuǎn)的效果:front元素繞Y軸旋轉(zhuǎn)deg度,book元素繞X軸旋轉(zhuǎn)60 + deg / 8度,card元素繞X軸旋轉(zhuǎn)deg / 3度,shadow元素skew傾斜deg / 8度。其中,模板字面量語(yǔ)法被用來(lái)構(gòu)建包含變量的字符串,方便設(shè)置transform的屬性值。
最后,console.log()函數(shù)用于輸出front元素的信息用于檢查調(diào)整。
以上就是利用JavaScript實(shí)現(xiàn)簡(jiǎn)單3D開(kāi)關(guān)書(shū)本模型的詳細(xì)內(nèi)容,更多關(guān)于JavaScript 3D開(kāi)關(guān)書(shū)本的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
JavaScript常用代碼書(shū)寫(xiě)規(guī)范的超全面總結(jié)
這篇文章給大家全面總結(jié)了JavaScript常用代碼的書(shū)寫(xiě)規(guī)范,分別利用推薦和不推薦的兩種示例代碼讓大家更能直接的了解書(shū)寫(xiě)規(guī)范,其實(shí)關(guān)于javascript代碼規(guī)范我們應(yīng)該遵循古老的原則:“能做并不意味著應(yīng)該做”,好了,下面我們就來(lái)一起看看吧。2016-09-09JS在Chrome瀏覽器中showModalDialog函數(shù)返回值為undefined的解決方法
這篇文章主要介紹了JS在Chrome瀏覽器中showModalDialog函數(shù)返回值為undefined的解決方法,涉及javascript針對(duì)谷歌瀏覽器事件判定相關(guān)操作技巧,需要的朋友可以參考下2016-08-08使用window.print()前端實(shí)現(xiàn)網(wǎng)頁(yè)打印超詳細(xì)教程(含代碼示例)
前端實(shí)現(xiàn)打印功能的方法有很多,大家在網(wǎng)上隨便一搜就是一大堆,下面這篇文章主要給大家介紹了關(guān)于使用window.print()前端實(shí)現(xiàn)網(wǎng)頁(yè)打印的相關(guān)資料,文中通過(guò)代碼介紹的非常詳細(xì),需要的朋友可以參考下2024-06-06JS代碼屏蔽F12,右鍵,粘貼,復(fù)制,剪切,選中,操作實(shí)例
在本篇文章里小編給大家分享的是關(guān)于利用JS代碼屏蔽F12,右鍵,粘貼,復(fù)制,剪切,選中,操作,需要的朋友們學(xué)習(xí)下。2019-09-09js使用removeChild方法動(dòng)態(tài)刪除div元素
本節(jié)為大家介紹了js使用removeChild方法動(dòng)態(tài)刪除div元素,需要的朋友可以參考下2014-08-08深入了解JavaScript的邏輯運(yùn)算符(與、或)
本篇文章分享的是 JS 當(dāng)中的邏輯運(yùn)算符與、或,也就是 && 、 || ,沒(méi)錯(cuò),別看這簡(jiǎn)簡(jiǎn)單單的幾個(gè)運(yùn)算符,雖然這是最基礎(chǔ)的知識(shí),但其中隱藏的奧秘卻十分耐人尋味,接下來(lái)本文就為大家一一揭開(kāi)這簡(jiǎn)單的運(yùn)算符背后的奇妙之處。2016-12-12bootstrap flask登錄頁(yè)面編寫(xiě)實(shí)例
這篇文章主要為大家詳細(xì)介紹了bootstrap flask登錄頁(yè)面編寫(xiě)實(shí)例,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2016-11-11深入學(xué)習(xí)JavaScript執(zhí)行上下文
這篇文章主要介紹了深入學(xué)習(xí)JavaScript執(zhí)行上下文,文章圍繞主題展開(kāi)詳細(xì)的內(nèi)容介紹,具有一定的參考價(jià)值,需要的朋友可以參考一下,希望對(duì)你的學(xué)習(xí)有所幫助2022-08-08