记录--用 Vue 实现原神官网的角色切换效果
这里给大家分享我在网上总结出来的一些知识,希望对大家有所帮助
前言
为了更好的了解原神角色,我模仿官网做了一个角色切换效果,在做的过程当中也总结了一些技术点。
为了让大家更好的体验,我兼容了 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
本文转载于:
https://juejin.cn/post/7277802797474021410
如果对您有所帮助,欢迎您点个关注,我会定时更新技术文档,大家一起讨论学习,一起进步。
记录--用 Vue 实现原神官网的角色切换效果的更多相关文章
- js原生带缩略图的图片切换效果
js原生带缩略图的图片切换效果 本例中用到的 moveElement(elementID,final_x,final_y,interval)是来自<JavaScript DOM编程艺术(中文第二 ...
- vue 移动端,页面左右页面切换效果(切换过程中会出现白屏效果,布吉岛怎么优化,后来就发布前就弃用了)
<transition name="left"> <router-view v-if="getCms" class="Router& ...
- vue2.0实践 —— Node + vue 实现移动官网
简介 使用 Node + vue 对公司的官网进行了一个简单的移动端的实现. 源码 https://github.com/wx1993/node-vue-fabaocn 效果 组件 轮播图(使用 vu ...
- Node + vue 实现移动官网
简介 使用 Node + vue 对公司的官网进行了一个简单的移动端的实现. 源码 https://github.com/wx1993/node-vue-fabaocn 效果 组件 轮播图(使用 vu ...
- Vue 框架-06-条件语句 v-if 实现选项卡效果
Vue 框架-06-条件语句 v-if 实现选项卡效果 本片介绍的是 Vue 中条件语句 v-if 第一个小实例是,通过 v-if="布尔值",通过布尔值的真假来决定,某元素是否显 ...
- vue配合iview/element等ui实现界面效果起步
iview与element都是与vue配合使用的ui框架,用法与配置基本一致,在此,我以iview为例,教你如何起步.*首先,你需要有一定的vue基础,如果你还是个小白,可以去我之前介绍如何搭建一个v ...
- Vue实现移动端页面切换效果
找了好多博客实现效果都……emmm…… 应用Vue自带的过渡 < 进入/离开 & 列表过渡 >和 嵌套路由 和 fixed定位实现 其实还是挺简单的. 在子页面把整个页面做绝对定位 ...
- 高仿阴阳师官网轮播图效果的jQuery插件
代码地址如下:http://www.demodashi.com/demo/12302.html 插件介绍 这是一个根据阴阳师官网的轮播效果所扒下来的轮播插件,主要应用于定制个性化场景,目前源码完全公开 ...
- Vue.js实现tab切换效果
利用Vue实现简易tab切换效果 1.1 在我们平时浏览网站的时候,经常看到的特效有图片轮播.导航子菜单的隐藏.tab标签的切换等等.这段时间学习了vue后,开始要写出一些简单的特效. 1.2 实现思 ...
- vue实现选项卡切换效果
效果如下: 说明: 这里我使用的原理是利用vue中的v-show/显示隐藏指令,当为true的时候显示,为false的时候隐藏 1html代码: <head> <meta chars ...
随机推荐
- C语言,函数形参与实参个数不一致问题
最近阅读工程代码的时候,同一个函数,不同场景调用时,输入的实参个数不一样,但是编译却没有问题.查看函数的定义,相关的C文件里并没有给形参指定默认值,这就很奇怪了. 最终,发现在函数相关的头文件 ...
- apache kafka-01-kafka 入门介绍
kafka 名字背后的故事 说到卡夫卡,不知道你脑海中第一个想到的是什么? 是<变形记>的作者弗兰兹·卡夫卡(Franz Kafka)?还是村上春树的<海边的卡夫卡>? 不知 ...
- MySQL专题2: 事务和锁
合集目录 MySQL专题2: 事务和锁 说说数据库事务特性及存在的问题 这属于数据库事务的基础概念了, 就是ACID Atomicity, 原子性, 事务包含的所有操作要么全部成功, 要么全部失败回滚 ...
- 多模式匹配的Trie实现
业务场景 这种需求一般用于敏感词过滤等场景, 输入是大文本, 需要快速判断是否存在匹配的模式串(敏感词), 或者在其中找出所有匹配的模式串. 对于模式串数量不超过5000的场景, 直接用暴力查找速度也 ...
- 用于解析FBNeo游戏数据的Python3脚本
FBNeo在代码中存储了游戏的元数据, 其数据格式为 struct BurnDriver BurnDrvCpsStriderua = { "striderua", "st ...
- spring boot2.0集成mybatis-plus实战
说明: 本例演示spring boot2.0如何集成mybatis-plus 如何使用代码生成器 项目源码: https://gitee.com/indexman/mybatis-plus-demo ...
- 时序数据库timescaleDB安装
一:前言相关 环境:Red Hat 8.3.1-5安装程序:PostgreSQL 14.1,TimescaleDB 2.5.1,cmake3.22.1PostgreSQL编译安装需要cmake3.4以 ...
- Java是解释型语言么
基础概念 JVM虚拟机会将.java类文件编译成.class文件--字节码文件,这大家都知道. 代码运行时还需要将.class字节码文件翻译成机器码才能执行. 解释执行:将编译好的字节码一行一行地翻译 ...
- 【Azure 应用服务】App Service的运行状况检查功能失效,一直提示"实例运行不正常"
问题描述 为App Service配置了健康检查,单独访问Health Check Path的路径,返回代码为200.但为什么在App Service的页面上,一直提示"实例运行不正常&qu ...
- 【Azure Developer】Java代码访问Key Vault Secret时候的认证问题,使用 DefaultAzureCredentialBuilder 或者 ClientSecretCredentialBuilder
问题描述 使用Java SDK获取Key Vault Secret机密信息时,需要获取授权.通常是使用AAD的注册应用(Client ID, Tenant ID, Client Secret)来获取 ...