記錄--用 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
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...