記錄--用 Vue 實現原神官網的角色切換效果

来源:https://www.cnblogs.com/smileZAZ/archive/2023/09/13/17700223.html
-Advertisement-
Play Games

這裡給大家分享我在網上總結出來的一些知識,希望對大家有所幫助 前言 為了更好的瞭解原神角色,我模仿官網做了一個角色切換效果,在做的過程當中也總結了一些技術點。 為了讓大家更好的體驗,我相容了 PC 端和移動端,建議在 PC 端查看效果更佳。接下來就為大家簡單的分享一下! 話不多說,原神啟動!! 效果 ...


這裡給大家分享我在網上總結出來的一些知識,希望對大家有所幫助

前言

為了更好的瞭解原神角色,我模仿官網做了一個角色切換效果,在做的過程當中也總結了一些技術點。

為了讓大家更好的體驗,我相容了 PC 端和移動端,建議在 PC 端查看效果更佳。接下來就為大家簡單的分享一下!

話不多說,原神啟動!!

效果

先看一下官網的效果: ys.mihoyo.com/main/charac…

我寫的真實效果:chenyajun.fun/#/ysRoleSwi…

技術點

一、底部角色橫向滾動效果

1、原理

外層容器:就是底部角色可視視窗。

內層容器: 用來存放角色頭像,點擊左右鍵或者角色需要滾動的容器。

滾動元素: 就是我們看到的一個個角色頭像。

首先我們使用外層容器來包裹所有的角色信息,同時使外層容器overflow:hidden。

其次我們通過點擊左右按鍵或者任意角色來確定當前所處的 index。

最後通過固定角色寬度 ✖ index 來控制內層容器的left值,從而移動內層容器位置,最終顯示當前激活的角色頭像。(註:移動端實現效果不同,下麵單獨講解) 

2、要求

 

要求1:如果處於最左(右)側的位置,點擊左右鍵或者前三個角色頭像不進行位移移動,只顯示角色切換激活狀態。

要求2:處於最左側並且點擊左鍵需要角色容器第一個為倒數第六個,也就是最後一欄。相反,處於最右側並且點擊右鍵需要移動到第一個,也就是第一欄。

要求3:點擊中間部分永遠保持在角色容器的第三個激活狀態。

3、代碼實現

大家可以根據HTML結構去理解代碼

      <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">
           //內部容器
          <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>

可以看到我們通過 moveDistancePC 變數來控制內層容器的移動位移,接下來主要分析一下怎麼控制 moveDistancePC !

1.點擊操作

通過點擊上一頁、下一頁以及角色信息來改變索引 $index。

// 上一頁
function lastPage() {
  if ($index.value === 0) {
    $index.value = yuRoleMes.value.length - 1
    return
  }
  $index.value--
}
// 下一頁
function nextPage() {
  // 到最後一頁
  if ($index.value === yuRoleMes.value.length - 1) {
    $index.value = 0
    return
  }
  $index.value++
}
// 點擊角色操作
function handleRoleSwitchPC(index) {
  isCloseTranstion.value = false
  $index.value = index
}

當處於第一個並且點擊左鍵時,直接將索引賦值為最後一個角色。

  if ($index.value === 0) {
    $index.value = yuRoleMes.value.length - 1
    return
  }

當處於最後一個並且點擊右鍵時,直接將索引賦值為0到第一個。

  // 到最後一頁
  if ($index.value === yuRoleMes.value.length - 1) {
    $index.value = 0
    return
  }

2.索引控制移動位移

通過索引*角色寬度來進行位置的移動,不過需要進行界限判斷,144為寬度(110px)+margin-right(34px)。

// 每次點擊移動距離
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
})

//對容器進行位移賦值
const moveDistancePC = computed(() => {
  return moveDistance.value + 'px'
})

情況一:

如果$index處於前三個,那麼位置不變永遠為0。

    const firstThree = $index.value < 3
    if (firstThree) {
      return 0
    }

情況二:

如果$index處於中間部分,永遠保持為當前的第三個激活即可。

($index.value - 2) 意思為如果直接取 $index 那麼角色位置會在第一個,保持在第三個就往後面移動兩位,故減去兩個即可。

    const lastThree = $index.value > yuRoleMes.value.length - 4
    if (!lastThree) {
      return ($index.value - 2) * -145
    }

情況三: 

如果$index處於後三個,那麼位置不變,永遠處於倒數第六個。

 return (yuRoleMes.value.length - 6) * -145

二、背景圖片放大縮小切換效果

我們可以看到每個場景下會有兩張背景圖片在不斷的切換,第一張結束之後第二張出現,兩張圖片迴圈播放,若隱若現。

代碼實現

這一部分是直接模仿的官方的樣式,直接說一下實現原理!

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>

需要使第一張背景永遠處於存在且向外擴大的狀態,通過關鍵幀動畫控制第二張的顯示隱藏,從而就達到了兩張照片的交替顯示隱藏,是不是很巧妙?

相關css代碼:

// 第一張永遠存在進行擴張
.role-bg1 {
  animation: breath 80s infinite linear;
  opacity: 1;
}
// 第二張也在擴張,只不過每次從顯示到隱藏需要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;
  }
}
// 用於向外擴張效果
@keyframes breath {
  0% {
    transform: scale(1);
  }

  50% {
    transform: scale(1.2);
  }

  100% {
    transform: scale(1);
  }
}

三、背景角色切換效果

 

到我們在切換角色的時候,第一個角色會移出,同時下一張照片會移入,並且伴有動畫,這個效果也是css實現的。

1、原理

我們將所有的圖片起初都定位到外面,預設顯示第一張,而當我們切換照片時,我們設置需要顯示的照片的 right 值,同時設置透明度,在這個過程中增加過渡動畫即可。 ​

 2、實現代碼

HTML結構

        <!-- 角色背景 -->
        <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>

我設置了兩個類show-background-pc,hide-background前者用來顯示切換的照片,index === $index時顯示點擊的照片,否則調整right值直接隱藏,兩個都加上過渡動畫,這樣顯示隱藏都會有效果了。

        .show-background-pc {
          right: 0;
          opacity: 1;
          transition: all 0.3s;
        }
        .show-background-mobile {
          right: 445px;
          opacity: 1;
          transition: all 0.3s;
        }

移動端

 1、底部角色滑動效果

2、點擊和觸摸移動事件衝突

我在做的過程中發現點擊事件和觸摸事件發生了衝突,就是我既要滑動這個容器又要進行點擊。

我採取的辦法是結束位置減去起始位置是否為0,如果為0則視為點擊事件!

  moveDistanceX.value = endX.value - startX.value
  // 如果是點擊滑動
  if (moveDistanceX.value === 0) {
    isClickMobile(e)
    return
  }

如果為true則處理點擊事件,否則處理移動事件即可,如果是點擊事件的話,邏輯和 PC 相似,這裡不再重覆講解,主要說一下滑動移動。

3、觸摸移動角色容器

我們在觸摸滑動容器時,容器需要跟著一起滑動

這裡有一些變數,大家可能需要看一下

const isCloseTranstion = ref(false) //控制是否顯示動畫效果
const startX = ref(0) //記錄開始位置
const endX = ref(0) //記錄結束位置
const moveDistanceX = ref(0) //按下抬起滑動距離
const recordLastMove = ref(0) //記錄上次滑動的距離,用於下次累加
const moveDistanceM = ref(0) //最終移動的距離

1.開始觸摸

// 觸摸開始
function handleTouchStart(e) {
  isCloseTranstion.value = true // 開始移動 關閉動畫
  startX.value = e.touches[0].pageX || e.changedTouches[0].pageX
}

2.觸摸移動

觸摸移動的話,下麵的容器需要實時跟著一起移動,也就是我們移動的位移需要實時的賦值上去,並且要累加上上次的位置,比如第一次移動到10,下次移動就是從10的基礎上進行移動。

 //最終移動的距離賦值為容器left值即可
const moveDistanceMobile = computed(() => {
  return moveDistanceM.value + 'px'
})
// 觸摸移動
function handleTouchMove(e) {
  e.preventDefault()
  isCloseTranstion.value = true // 開始移動 關閉動畫
  moveDistanceX.value = (e.changedTouches[0].pageX || e.touches[0].pageX) - startX.value // 計算移動距離
  moveDistanceM.value = recordLastMove.value + moveDistanceX.value
}

3.觸摸抬起

容器的最終位置這裡就需要分情況進行處理了,滿足相應的條件處理相應的邏輯即可。

情況一:

如果只有一欄照片或者直接往右邊移動,那就只進行實時同步移動,只不過移動結束還恢復到原來位置即可。

  // 如果照片小於五張不進行位移移動
  if (yuRoleMes.value.length < 5) {
    moveDistanceM.value = 0
    recordLastMove.value = 0
    return
  }

情況二:

已經滑到最後一欄繼續左滑,這時已經超出了最大界限,將最終位置定格在最大界限的位置

  // 最後一欄的位置
  const rightMaxValue = (yuRoleMes.value.length - 5) * -64  
//在最後一欄繼續往左邊滑動
  if (moveDistanceM.value < rightMaxValue) {
    moveDistanceM.value = rightMaxValue
    recordLastMove.value = rightMaxValue
    return
  }

情況三:

除了以上情況,也就是在中間正常滑動,我們進行賦值即可,使用 Math.round 來保證我們移動的都是每個角色的整數倍即可。

  // 其他情況
  moveDistanceM.value = recordLastMove.value + Math.round(moveDistanceX.value / 64) * 64
  recordLastMove.value = Math.round(moveDistanceM.value / 64) * 64

總結

聲明:以上所有信息材料均來之於原神官網ys.mihoyo.com/main/charac…

上面我將功能進行了分開描述,PC 端和移動端最終效果不一樣,所以代碼實現也不一樣,但其實實現邏輯相似,只不過需要對不同的情況進行處理。

另外就是每個情況需要考慮細緻,我在寫的過程中,總會有落下的問題,也就是測試用例不太全面,如果大家有發現不對的地方,可以在下方進行留言,我看到會進行及時更改的。

寫作不易,你的贊就是我最大的動力,覺得寫的不錯的,可以給點個贊呢~

源碼:

全部源碼已經同步上傳到了 GitHub

覺得寫的不錯了,可以給作者點一下star⭐

GitHub:chenyajun-create/ysRoleSwitch (github.com)

本文轉載於:

https://juejin.cn/post/7277802797474021410

如果對您有所幫助,歡迎您點個關註,我會定時更新技術文檔,大家一起討論學習,一起進步。

 


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 1、背景描述 出於安全考慮,需要禁止使用root用戶通過ssh遠程登錄Linux 禁用root用戶遠程登錄後,需要提供一個許可權用戶用於ssh遠程登錄 2、創建擁有sudo許可權的用戶 2.1、創建一個普通用戶rain useradd命令用於創建一個用戶, 選項 -m 表示創建用戶的主目錄, -c 表示 ...
  • 1. 索引 1.1. 鍵(key) 1.2. 存儲引擎用於快速找到記錄的一種數據結構 1.3. 當表中的數據量越來越大時,索引對性能的影響愈發重要 1.4. 在數據量較小且負載較低時,缺少合適的索引對性能的影響可能還不明顯 1.5. 索引優化是對查詢性能優化最有效的手段 1.6. 索引能夠輕易將查詢 ...
  • 本文分享自華為雲社區《GaussDB(DWS)鎖問題全解》,作者: yd_211043076。 一、gaussdb有哪些鎖 1、常規鎖:常規鎖主要用於業務訪問資料庫對象的加鎖,保護併發操作的對象,保持數據一致性;常見的常規鎖有表鎖(relation)和行鎖(tuple)。 表鎖:當對錶進行DDL、D ...
  • Apache SeaTunnel是一個非常易於使用的、超高性能的分散式數據集成平臺,支持海量數據的實時同步。每天可穩定高效同步數百億數據,已被近百家企業投入生產使用。 現在的版本不支持通過jtds的方式鏈接sqlserver,我們來自己寫代碼來實現它,並把代碼提交給apache seatunnel。 ...
  • 通過 API 對外提供數據服務是大部分企業中比較常見的數據應用方式,對於 API 平臺管理者、開發者和調用者來說,API 的調用性能、安全性和穩定性是在平臺選型時最需要考慮的三個因素。 袋鼠雲API開發及管理平臺【數棧-數據服務 DataAPI】通過多種手段標準化管控服務,可完成從 API 創建、發 ...
  • 業務挑戰與痛點 隨著互聯網技術的發展、雲計算技術的成熟、人工智慧技術的興起和數字化經濟的崛起,數據已成為企業的核心資產。在金融行業中,數字化已成為了支撐各類業務場景的核心力量,包括個人理財、企業融資、股票交易、保險理賠、貸款服務、支付結算、投資咨詢、資產管理等等。然而,在基於大數據分析與處理技術的業 ...
  • 起因 在GreatSQL社區上有一位用戶提出了“手工構建MGR碰到的次節點一直處於recovering狀態”,經過排查後,發現了是因為新密碼驗證插件caching_sha2_password導致的從節點一直無法連接主節點,帖子地址:(https://greatsql.cn/thread-420-2- ...
  • Android的源碼非常的龐大,編譯Android系統往往會占用我們很長的時間,我們需要瞭解下Android的編譯規則,以期能提高我們的開發效率。。。 ...
一周排行
    -Advertisement-
    Play Games
  • 示例項目結構 在 Visual Studio 中創建一個 WinForms 應用程式後,項目結構如下所示: MyWinFormsApp/ │ ├───Properties/ │ └───Settings.settings │ ├───bin/ │ ├───Debug/ │ └───Release/ ...
  • [STAThread] 特性用於需要與 COM 組件交互的應用程式,尤其是依賴單線程模型(如 Windows Forms 應用程式)的組件。在 STA 模式下,線程擁有自己的消息迴圈,這對於處理用戶界面和某些 COM 組件是必要的。 [STAThread] static void Main(stri ...
  • 在WinForm中使用全局異常捕獲處理 在WinForm應用程式中,全局異常捕獲是確保程式穩定性的關鍵。通過在Program類的Main方法中設置全局異常處理,可以有效地捕獲並處理未預見的異常,從而避免程式崩潰。 註冊全局異常事件 [STAThread] static void Main() { / ...
  • 前言 給大家推薦一款開源的 Winform 控制項庫,可以幫助我們開發更加美觀、漂亮的 WinForm 界面。 項目介紹 SunnyUI.NET 是一個基於 .NET Framework 4.0+、.NET 6、.NET 7 和 .NET 8 的 WinForm 開源控制項庫,同時也提供了工具類庫、擴展 ...
  • 說明 該文章是屬於OverallAuth2.0系列文章,每周更新一篇該系列文章(從0到1完成系統開發)。 該系統文章,我會儘量說的非常詳細,做到不管新手、老手都能看懂。 說明:OverallAuth2.0 是一個簡單、易懂、功能強大的許可權+可視化流程管理系統。 有興趣的朋友,請關註我吧(*^▽^*) ...
  • 一、下載安裝 1.下載git 必須先下載並安裝git,再TortoiseGit下載安裝 git安裝參考教程:https://blog.csdn.net/mukes/article/details/115693833 2.TortoiseGit下載與安裝 TortoiseGit,Git客戶端,32/6 ...
  • 前言 在項目開發過程中,理解數據結構和演算法如同掌握蓋房子的秘訣。演算法不僅能幫助我們編寫高效、優質的代碼,還能解決項目中遇到的各種難題。 給大家推薦一個支持C#的開源免費、新手友好的數據結構與演算法入門教程:Hello演算法。 項目介紹 《Hello Algo》是一本開源免費、新手友好的數據結構與演算法入門 ...
  • 1.生成單個Proto.bat內容 @rem Copyright 2016, Google Inc. @rem All rights reserved. @rem @rem Redistribution and use in source and binary forms, with or with ...
  • 一:背景 1. 講故事 前段時間有位朋友找到我,說他的窗體程式在客戶這邊出現了卡死,讓我幫忙看下怎麼回事?dump也生成了,既然有dump了那就上 windbg 分析吧。 二:WinDbg 分析 1. 為什麼會卡死 窗體程式的卡死,入口門檻很低,後續往下分析就不一定了,不管怎麼說先用 !clrsta ...
  • 前言 人工智慧時代,人臉識別技術已成為安全驗證、身份識別和用戶交互的關鍵工具。 給大家推薦一款.NET 開源提供了強大的人臉識別 API,工具不僅易於集成,還具備高效處理能力。 本文將介紹一款如何利用這些API,為我們的項目添加智能識別的亮點。 項目介紹 GitHub 上擁有 1.2k 星標的 C# ...