這里給大家分享我在網(wǎng)上總結(jié)出來(lái)的一些知識(shí),希望對(duì)大家有所幫助
前言
為了更好的了解原神角色,我模仿官網(wǎng)做了一個(gè)角色切換效果,在做的過(guò)程當(dāng)中也總結(jié)了一些技術(shù)點(diǎn)。
為了讓大家更好的體驗(yàn),我兼容了 PC 端和移動(dòng)端,建議在 PC 端查看效果更佳。接下來(lái)就為大家簡(jiǎn)單的分享一下!
話(huà)不多說(shuō),原神啟動(dòng)?。?/p>
效果
先看一下官網(wǎng)的效果: ys.mihoyo.com/main/charac…
我寫(xiě)的真實(shí)效果:chenyajun.fun/#/ysRoleSwi…
技術(shù)點(diǎn)
一、底部角色橫向滾動(dòng)效果
1、原理
外層容器:就是底部角色可視窗口。
內(nèi)層容器:?用來(lái)存放角色頭像,點(diǎn)擊左右鍵或者角色需要滾動(dòng)的容器。
滾動(dòng)元素:?就是我們看到的一個(gè)個(gè)角色頭像。
首先我們使用外層容器
來(lái)包裹所有的角色信息,同時(shí)使外層容器overflow:hidden。
其次我們通過(guò)點(diǎn)擊左右按鍵或者任意角色來(lái)確定當(dāng)前所處的 index。
最后通過(guò)固定角色寬度?? index 來(lái)控制內(nèi)層容器
的left值,從而移動(dòng)內(nèi)層容器
位置,最終顯示當(dāng)前激活的角色頭像。(注:移動(dòng)端實(shí)現(xiàn)效果不同,下面單獨(dú)講解)?
2、要求
?
要求1:如果處于最左(右)側(cè)的位置,點(diǎn)擊左右鍵或者前三個(gè)角色頭像不進(jìn)行位移移動(dòng)
,只顯示角色切換激活狀態(tài)。
要求2:處于最左側(cè)并且點(diǎn)擊左鍵需要角色容器第一個(gè)為倒數(shù)第六個(gè),也就是最后一欄。相反,處于最右側(cè)并且點(diǎn)擊右鍵需要移動(dòng)到第一個(gè),也就是第一欄。
要求3:點(diǎn)擊中間部分永遠(yuǎn)保持在角色容器的第三個(gè)
激活狀態(tài)。
3、代碼實(shí)現(xiàn)
大家可以根據(jù)HTML結(jié)構(gòu)去理解代碼
<div class="role-outer" :style="{ width: isPC ? '830px' : '320px' }"> <template> <div class="left-arrow" :style="{ backgroundImage: `url(${leftSwitchArrow})` }" @click="lastPage"></div> <div class="right-arrow" :style="{ backgroundImage: `url(${rightSwitchArrow})` }" @click="nextPage"></div> </template> <div class="role-contener"> //內(nèi)部容器 <div class="role-inner" :class="{ activeTranstion: isCloseTranstion }" :style="{ left: isPC ? moveDistancePC : moveDistanceMobile }" ref="element" > //角色 <template> <div v-for="(item, index) in yuRoleMes" class="role-item-pc" :style="{ backgroundPosition: $index === index ? '0 -132px' : '', backgroundImage: `url(${bottomRoleBac})`, }" :key="index" @click="handleRoleSwitchPC(index)" > <img class="item-avater" :src="item.roleAvatar" /> <p class="item-name" :style="{ color: $index === index ? '#000' : '#fff' }">{{ item.roleName }}</p> </div> </template> </div> </div> </div> </div>
可以看到我們通過(guò)?moveDistancePC?
變量來(lái)控制內(nèi)層容器的移動(dòng)位移,接下來(lái)主要分析一下怎么控制 moveDistancePC !
1.點(diǎn)擊操作
通過(guò)點(diǎn)擊上一頁(yè)、下一頁(yè)以及角色信息來(lái)改變索引 $index。
// 上一頁(yè) function lastPage() { if ($index.value === 0) { $index.value = yuRoleMes.value.length - 1 return } $index.value-- } // 下一頁(yè) function nextPage() { // 到最后一頁(yè) if ($index.value === yuRoleMes.value.length - 1) { $index.value = 0 return } $index.value++ } // 點(diǎn)擊角色操作 function handleRoleSwitchPC(index) { isCloseTranstion.value = false $index.value = index }
當(dāng)處于第一個(gè)
并且點(diǎn)擊左鍵
時(shí),直接將索引賦值為最后一個(gè)角色。
if ($index.value === 0) { $index.value = yuRoleMes.value.length - 1 return }
當(dāng)處于最后一個(gè)
并且點(diǎn)擊右鍵
時(shí),直接將索引賦值為0到第一個(gè)。
// 到最后一頁(yè) if ($index.value === yuRoleMes.value.length - 1) { $index.value = 0 return }
2.索引控制移動(dòng)位移
通過(guò)索引*角色寬度
來(lái)進(jìn)行位置的移動(dòng),不過(guò)需要進(jìn)行界限判斷,144為寬度(110px)+margin-right(34px)。
// 每次點(diǎn)擊移動(dòng)距離 const moveDistance = computed(() => { const firstThree = $index.value < 3 if (firstThree) { return 0 } const lastThree = $index.value > yuRoleMes.value.length - 4 if (!lastThree) { return ($index.value - 2) * -144 } return (yuRoleMes.value.length - 6) * -144 }) //對(duì)容器進(jìn)行位移賦值 const moveDistancePC = computed(() => { return moveDistance.value + 'px' })
情況一:
如果$index處于前三個(gè),那么位置不變永遠(yuǎn)為0。
const firstThree = $index.value < 3 if (firstThree) { return 0 }
情況二:
如果$index處于中間部分,永遠(yuǎn)保持為當(dāng)前的第三個(gè)激活即可。
($index.value - 2) 意思為如果直接取 $index 那么角色位置會(huì)在第一個(gè),保持在第三個(gè)就往后面移動(dòng)兩位,故減去兩個(gè)即可。
const lastThree = $index.value > yuRoleMes.value.length - 4 if (!lastThree) { return ($index.value - 2) * -145 }
情況三:?
如果$index處于后三個(gè),那么位置不變,永遠(yuǎn)處于倒數(shù)第六個(gè)。
return (yuRoleMes.value.length - 6) * -145
二、背景圖片放大縮小切換效果
我們可以看到每個(gè)場(chǎng)景下會(huì)有兩張背景圖片在不斷的切換,第一張結(jié)束之后第二張出現(xiàn),兩張圖片循環(huán)播放,若隱若現(xiàn)。
代碼實(shí)現(xiàn)
這一部分是直接模仿的官方的樣式,直接說(shuō)一下實(shí)現(xiàn)原理!
HTML
<!-- 背景-兩張切換 --> <div class="background-wrapper"> <!-- 第一張背景 --> <div class="role-background role-bg1" :style="{ backgroundImage: outerTwoBackground[0], }" ></div> <!-- 第二張背景 --> <div class="role-background role-bg2" :style="{ backgroundImage: outerTwoBackground[1], }" ></div> </div>
需要使第一張背景永遠(yuǎn)處于存在且向外擴(kuò)大的狀態(tài),通過(guò)關(guān)鍵幀動(dòng)畫(huà)
控制第二張的顯示隱藏,從而就達(dá)到了兩張照片的交替顯示隱藏,是不是很巧妙?
相關(guān)css代碼:
// 第一張永遠(yuǎn)存在進(jìn)行擴(kuò)張 .role-bg1 { animation: breath 80s infinite linear; opacity: 1; } // 第二張也在擴(kuò)張,只不過(guò)每次從顯示到隱藏需要15秒 .role-bg2 { animation: bg-change 15s infinite linear, breath 80s infinite linear; opacity: 0; } // 用于第二張的顯示隱藏 @keyframes bg-change { 48% { opacity: 0; } 50% { opacity: 1; } 98% { opacity: 1; } 100% { opacity: 0; } } // 用于向外擴(kuò)張效果 @keyframes breath { 0% { transform: scale(1); } 50% { transform: scale(1.2); } 100% { transform: scale(1); } }
三、背景角色切換效果
到我們?cè)谇袚Q角色的時(shí)候,第一個(gè)角色會(huì)移出,同時(shí)下一張照片會(huì)移入,并且伴有動(dòng)畫(huà),這個(gè)效果也是css實(shí)現(xiàn)的。
1、原理
我們將所有的圖片起初都定位到外面,默認(rèn)顯示第一張,而當(dāng)我們切換照片時(shí),我們?cè)O(shè)置需要顯示的照片的 right
值,同時(shí)設(shè)置透明度
,在這個(gè)過(guò)程中增加過(guò)渡動(dòng)畫(huà)
即可。 ?
?2、實(shí)現(xiàn)代碼
HTML結(jié)構(gòu)
<!-- 角色背景 --> <div class="role-wrapper"> <div class="role-box"> <img v-for="(item, index) in yuRoleMes" class="role-picture" :class="[index === $index ? show-background-pc' : 'hide-background']" :key="index" :src="item.roleBackground" /> </div> </div>
我設(shè)置了兩個(gè)類(lèi)show-background-pc,hide-background前者用來(lái)顯示切換的照片,index === $index時(shí)顯示點(diǎn)擊的照片,否則調(diào)整right值直接隱藏,兩個(gè)都加上過(guò)渡動(dòng)畫(huà),這樣顯示隱藏都會(huì)有效果了。
.show-background-pc { right: 0; opacity: 1; transition: all 0.3s; } .show-background-mobile { right: 445px; opacity: 1; transition: all 0.3s; }
移動(dòng)端
?1、底部角色滑動(dòng)效果
2、點(diǎn)擊和觸摸移動(dòng)事件沖突
我在做的過(guò)程中發(fā)現(xiàn)點(diǎn)擊事件和觸摸事件
發(fā)生了沖突,就是我既要滑動(dòng)這個(gè)容器又要進(jìn)行點(diǎn)擊。
我采取的辦法是結(jié)束位置減去起始位置是否為0
,如果為0則視為點(diǎn)擊事件!
moveDistanceX.value = endX.value - startX.value // 如果是點(diǎn)擊滑動(dòng) if (moveDistanceX.value === 0) { isClickMobile(e) return }
如果為true則處理點(diǎn)擊事件,否則處理移動(dòng)事件即可,如果是點(diǎn)擊事件的話(huà),邏輯和 PC 相似,這里不再重復(fù)講解,主要說(shuō)一下滑動(dòng)移動(dòng)。
3、觸摸移動(dòng)角色容器
我們?cè)谟|摸滑動(dòng)容器時(shí),容器需要跟著一起滑動(dòng)
。
這里有一些變量,大家可能需要看一下
const isCloseTranstion = ref(false) //控制是否顯示動(dòng)畫(huà)效果 const startX = ref(0) //記錄開(kāi)始位置 const endX = ref(0) //記錄結(jié)束位置 const moveDistanceX = ref(0) //按下抬起滑動(dòng)距離 const recordLastMove = ref(0) //記錄上次滑動(dòng)的距離,用于下次累加 const moveDistanceM = ref(0) //最終移動(dòng)的距離
1.開(kāi)始觸摸
// 觸摸開(kāi)始 function handleTouchStart(e) { isCloseTranstion.value = true // 開(kāi)始移動(dòng) 關(guān)閉動(dòng)畫(huà) startX.value = e.touches[0].pageX || e.changedTouches[0].pageX }
2.觸摸移動(dòng)
觸摸移動(dòng)的話(huà),下面的容器需要實(shí)時(shí)跟著一起移動(dòng),也就是我們移動(dòng)的位移需要實(shí)時(shí)的賦值上去,并且要累加上上次
的位置,比如第一次移動(dòng)到10,下次移動(dòng)就是從10的基礎(chǔ)上進(jìn)行移動(dòng)。
//最終移動(dòng)的距離賦值為容器left值即可 const moveDistanceMobile = computed(() => { return moveDistanceM.value + 'px' }) // 觸摸移動(dòng) function handleTouchMove(e) { e.preventDefault() isCloseTranstion.value = true // 開(kāi)始移動(dòng) 關(guān)閉動(dòng)畫(huà) moveDistanceX.value = (e.changedTouches[0].pageX || e.touches[0].pageX) - startX.value // 計(jì)算移動(dòng)距離 moveDistanceM.value = recordLastMove.value + moveDistanceX.value }
3.觸摸抬起
容器的最終位置這里就需要分情況進(jìn)行處理了,滿(mǎn)足相應(yīng)的條件處理相應(yīng)的邏輯即可。
情況一:
如果只有一欄照片或者直接往右邊移動(dòng),那就只進(jìn)行實(shí)時(shí)同步移動(dòng),只不過(guò)移動(dòng)結(jié)束還恢復(fù)到原來(lái)位置即可。
// 如果照片小于五張不進(jìn)行位移移動(dòng) if (yuRoleMes.value.length < 5) { moveDistanceM.value = 0 recordLastMove.value = 0 return }
情況二:
已經(jīng)滑到最后一欄繼續(xù)左滑,這時(shí)已經(jīng)超出了最大界限,將最終位置定格在最大界限的位置
。
// 最后一欄的位置 const rightMaxValue = (yuRoleMes.value.length - 5) * -64 //在最后一欄繼續(xù)往左邊滑動(dòng) if (moveDistanceM.value < rightMaxValue) { moveDistanceM.value = rightMaxValue recordLastMove.value = rightMaxValue return }
情況三:
除了以上情況,也就是在中間正?;瑒?dòng),我們進(jìn)行賦值即可,使用 Math.round 來(lái)保證我們移動(dòng)的都是每個(gè)角色的整數(shù)倍
即可。
// 其他情況 moveDistanceM.value = recordLastMove.value + Math.round(moveDistanceX.value / 64) * 64 recordLastMove.value = Math.round(moveDistanceM.value / 64) * 64
總結(jié)
聲明:以上所有信息材料均來(lái)之于原神官網(wǎng)ys.mihoyo.com/main/charac…
上面我將功能進(jìn)行了分開(kāi)描述,PC 端和移動(dòng)端最終效果不一樣,所以代碼實(shí)現(xiàn)也不一樣,但其實(shí)實(shí)現(xiàn)邏輯相似,只不過(guò)需要對(duì)不同的情況進(jìn)行處理。
另外就是每個(gè)情況需要考慮細(xì)致,我在寫(xiě)的過(guò)程中,總會(huì)有落下的問(wèn)題,也就是測(cè)試用例不太全面,如果大家有發(fā)現(xiàn)不對(duì)的地方,可以在下方進(jìn)行留言,我看到會(huì)進(jìn)行及時(shí)更改的。
寫(xiě)作不易,你的贊就是我最大的動(dòng)力,覺(jué)得寫(xiě)的不錯(cuò)的,可以給點(diǎn)個(gè)贊呢~
源碼:
全部源碼已經(jīng)同步上傳到了 GitHub
覺(jué)得寫(xiě)的不錯(cuò)了,可以給作者點(diǎn)一下star?
GitHub:chenyajun-create/ysRoleSwitch (github.com)文章來(lái)源:http://www.zghlxwxcb.cn/news/detail-708336.html
本文轉(zhuǎn)載于:
https://juejin.cn/post/7277802797474021410
如果對(duì)您有所幫助,歡迎您點(diǎn)個(gè)關(guān)注,我會(huì)定時(shí)更新技術(shù)文檔,大家一起討論學(xué)習(xí),一起進(jìn)步。
?文章來(lái)源地址http://www.zghlxwxcb.cn/news/detail-708336.html
到了這里,關(guān)于記錄--用 Vue 實(shí)現(xiàn)原神官網(wǎng)的角色切換效果的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!