全国免费咨询:

13245491521

VR图标白色 VR图标黑色
X

中高端软件定制开发服务商

与我们取得联系

13245491521     13245491521

2023-08-26_原神启动!!用 Vue 实现原神官网的全屏滚动效果

您的位置:首页 >> 新闻 >> 行业资讯

原神启动!!用 Vue 实现原神官网的全屏滚动效果 点击关注公众号,技术干货及时送达先看一下官网效果:https://ys.mihoyo.com/main/map[1] 概念每次当滚动鼠标滚轮的时候,页面会进行一整页的滚动,这就是全屏滚动。 要求当窗口大小变化时,全屏滚动效果不会发生变化,即需要做到自适应,不受到高度宽度的影响。 当点击指示器也可以进行页面切换。 原理「最外层容器」:就是我们的窗口,视角能看到的。 「内层容器:」 用来存放我们需要滚动内容的容器。 「滚动元素:」 就是我们看到的一张张照片。 首先对最外侧容器的overflow:hidden;这样保证不会溢出。 其次对内层容器进行滚动,每次滚动的高度就是窗口的高度,但是需要动态计算窗口的高度。 最后只需要判断上一页还是下一页来计算index,通过index ? 页面高度,来进行滚动即可。 代码实现HTML代码大家可以结合html结构,去理解 js 代码 !--最外层容器-- divclass="outer-box"ref="fullPage" !--内层容器-- div ref="element" :class="{activeTranstion:isCloseTranstion}" class="inner-box" @mousewheel="mousewheel" @touchstart="handleTouchStart" @touchend="handleTouchEnd" @touchmove="handleTouchMove" !--滚动显示的元素-- div v-for="iteminysImage" :style="{backgroundImage:`url(${item.backgroundImage})`,height:windowHeight+'px'}" class="scroll-element" /div /div !--指示器-- ulclass="aside" liv-for="(item,index)inasideData"@click="changeBac(index)" span:class="{active:index===$index}"/span divv-show="index===$index"class="show-dec"{{item.title}}/div /li /ul /div JS代码给内层容器添加鼠标滚动事件当滚动事件触发时判断是向上还是向下滚动,以此来控制滚动方向。 另外由于鼠标滚动事件触发过于频繁,我们需要增加「节流」,即保证在单位时间内只执行一次即可。 设置canRun为节流标志,每500毫秒执行一次。 functionmousewheel(e){ isTranstion.value=false if(canRun.value){ canRun.value=false goScroll(e) setTimeout(()={ canRun.value=true },1100) } } 开始滚动元素通过上一页下一页增加减少$index,通过索引 ? 页面高度,来决定页面滚动的距离,也就是当前要显示的页面。 functiongoScroll(e){ //e.wheelDelta用来判断上一个下一个0下一个0上一个 if(e.wheelDelta0){ next() }else{ last() } } //$INDEX const$index=ref(0)//索引控制第几个显示 //下一个 functionnext(){ if($index.value4){ $index.value++ } } //上一个 functionlast(){ if($index.value1||$index.value===1){ $index.value-- } } 动态计算页面高度由于页面高度发生变化时,我们需要动态响应高度的变化。 使用 VueUse 库提供的 useWindowSize() 函数计算https://vueuse.org/core/useWindowSize/[2] 当页面高度变化时height会相应变化 const{height}=useWindowSize() 值得注意的是,当页面高度变化时,我们需要关闭动画效果。 constwindowHeight=computed(()={ isTranstion.value=true returnheight.value }) 「通过索引计算滚动高度」 consttransformScroll=computed(()={ return`translateY(-${$index.value*windowHeight.value}px)` }) 「将滚动高度应用到滚动容器上面」 「watchEffect:」 会在副作用发生期间追踪依赖。它会在同步执行过程中,自动追踪所有能访问到的响应式属性。官方:https://cn.vuejs.org/guide/essentials/watchers.html#watcheffect[3] //ELEMENT constelement=ref('element') watchEffect(()={ if(element.value.style){ element.value.style.transform=transformScroll.value } }) 点击指示器点击指示器的时候,跳转到相应页面,只需设置相应的index即可。 //点击切换 functionchangeBac(index){ //点击切换时需要开启动画 isTranstion.value=false $index.value=index } 移动端//#region移动端 conststartY=ref(0)//记录开始位置 constendY=ref(0)//记录结束位置 constmoveDistance=ref(0)//滑动距离 //触摸开始 functionhandleTouchStart(e){ startY.value=e.touches[0].pageY||e.changedTouches[0].pageY } //触摸移动 functionhandleTouchMove(e){ e.preventDefault()//wx上拉默认事件 isCloseTranstion.value=true//开始移动关闭动画 moveDistance.value=(e.changedTouches[0].pageY||e.touches[0].pageY)-startY.value//计算移动距离 //判断临界点 constisCriticalPoint= ($index.value===4moveDistance.value0)||($index.value===0moveDistance.value0) //如果是临界点就直接返回 if(isCriticalPoint){ return } //否则直接对内层容器应用随之移动 element.value.style.transform=`translateY(-${$index.value*windowHeight.value+moveDistance.value*-1}px)` //触摸抬起 functionhandleTouchEnd(e){ //抬起时开启动画 isCloseTranstion.value=false //计算结束距离 endY.value=e.changedTouches[0].pageY||e.touches[0].pageY //计算移动距离,判断应该上一页还是下一页,直接更改index即可在原先基础上整页移动 moveDistance.value=endY.value-startY.value //这里我做了一个最小值大于50才翻页 if(Math.abs(moveDistance.value)=60){ if($index.value4moveDistance.value0){ $index.value++ } if($index.value0moveDistance.value0){ $index.value-- } }else{ //当临界值小于60意味着不需要翻页就恢复原来的位置即可 element.value.style.transform=`translateY(-${$index.value*windowHeight.value}px)` } } } 效果想看效果得可以进入看一下:https://chenyajun.fun/#/fullPage[4] 总结全屏滚动的核心还是判断上一页还是下一页,动态计算页面高度,对内层容器进行滚动,从而显示我们需要展示的元素即可。不过在一些细节处理上还是需要注意,尤其是动画的开关。移动端的触摸同步也需要动画的配合,看似简单的一个应用,其实里面值得学习的内容还是比较多的。 写作不易,你的赞就是我最大的动力,觉得写的不错的,可以给点个赞呢~ 全部源码GitHub地址:https://github.com/chenyajun-create/ysFullPage 所有源码已经同步提交GitHub,觉得对你有帮助的话,记得帮作者点下star?~非常感谢呢 scriptsetup //IMAGEDATA constysImage=ref([ { backgroundImage:'https://ys.mihoyo.com/main/_nuxt/img/5c125a1.png', }, { backgroundImage:'https://uploadstatic.mihoyo.com/contentweb/20200319/2020031921550320292.jpg', }, { backgroundImage:'https://uploadstatic.mihoyo.com/contentweb/20200319/2020031921552395638.jpg', }, { backgroundImage:'https://uploadstatic.mihoyo.com/contentweb/20210719/2021071918001232800.jpg', }, { backgroundImage: 'https://webstatic.mihoyo.com/upload/contentweb/2022/08/15/8969f683b92839ac427c875d0d742be2_4825576482548821743.jpg', }, ]) constasideData=ref([ { title:'蒙德', }, { title:'璃月', }, { title:'稻妻', }, { title:'须弥', }, { title:'枫丹', }, ]) //ELEMENT constelement=ref('element') watchEffect(()={ if(element.value.style){ element.value.style.transform=transformScroll.value } }) //HEIGHT const{height}=useWindowSize() constwindowHeight=computed(()={ //高度变化时需要关闭动画 isCloseTranstion.value=true returnheight.value }) consttransformScroll=computed(()={ return`translateY(-${$index.value*windowHeight.value}px)` }) constisCloseTranstion=ref(false)//控制是否显示动画效果 constcanRun=ref(true)//节流控制器 functionmousewheel(e){ isCloseTranstion.value=false if(canRun.value){ canRun.value=false goScroll(e) setTimeout(()={ canRun.value=true },1100) } } functiongoScroll(e){ //e.wheelDelta用来判断上一个下一个0下一个0上一个 if(e.wheelDelta0){ next() }else{ last() } } //$INDEX const$index=ref(0)//索引控制第几个显示 //下一个 functionnext(){ if($index.value4){ $index.value++ } } //上一个 functionlast(){ if($index.value1||$index.value===1){ $index.value-- } } //点击切换 functionchangeBac(index){ //点击切换时需要开启动画 isCloseTranstion.value=false $index.value=index } //#region移动端 conststartY=ref(0)//记录开始位置 constendY=ref(0)//记录结束位置 constmoveDistance=ref(0)//滑动距离 //触摸开始 functionhandleTouchStart(e){ startY.value=e.touches[0].pageY||e.changedTouches[0].pageY } //触摸抬起 functionhandleTouchEnd(e){ //抬起时开启动画 isCloseTranstion.value=false //计算结束距离 endY.value=e.changedTouches[0].pageY||e.touches[0].pageY //计算移动距离,判断应该上一页还是下一页,直接更改index即可在原先基础上整页移动 moveDistance.value=endY.value-startY.value //这里我做了一个最小值大于50才翻页 if(Math.abs(moveDistance.value)=60){ if($index.value4moveDistance.value0){ $index.value++ } if($index.value0moveDistance.value0){ $index.value-- } }else{ //当临界值小于60意味着不需要翻页就恢复原来的位置即可 element.value.style.transform=`translateY(-${$index.value*windowHeight.value}px)` } } //触摸移动 functionhandleTouchMove(e){ e.preventDefault() isCloseTranstion.value=true//开始移动关闭动画 moveDistance.value=(e.changedTouches[0].pageY||e.touches[0].pageY)-startY.value//计算移动距离\ //判断临界点 constisCriticalPoint= ($index.value===4moveDistance.value0)||($index.value===0moveDistance.value0) //如果是临界点就直接返回 if(isCriticalPoint){ return } //否则直接对内层容器应用随之移动 element.value.style.transform=`translateY(-${$index.value*windowHeight.value+moveDistance.value*-1}px)` } //#endregion /script template !--最外层容器-- divclass="outer-box"ref="fullPage" !--内层容器-- div ref="element" :class="{activeTranstion:isCloseTranstion}" class="inner-box" @mousewheel="mousewheel" @touchstart="handleTouchStart" @touchend="handleTouchEnd" @touchmove="handleTouchMove" !--滚动显示的元素-- div v-for="iteminysImage" :style="{backgroundImage:`url(${item.backgroundImage})`,height:windowHeight+'px'}" class="scroll-element" /div /div !--指示器-- ulclass="aside" liv-for="(item,index)inasideData"@click="changeBac(index)" span:class="{active:index===$index}"/span divv-show="index===$index"class="show-dec"{{item.title}}/div /li /ul /div /template stylelang="scss"scoped .activeTranstion{ transition:all0msease0s!important; } .active{ display:inline-block; width:12px!important; height:12px!important; } .outer-box{ width:100%; height:100%; overflow:hidden; position:relative; .inner-box{ width:100%; transition:allease-in-out0.5s; .scroll-element{ background-size:cover!important; background-position:center; background-repeat:no-repeat; } } .aside{ list-style:none; position:fixed; right:20px; top: transform:translateY(-50%); li{ height:14px; width:14px; margin: display:flex; align-items:center; justify-content:center; position:relative; .show-dec{ text-align:right; position:absolute; width:70px; right:20px; padding: //opacity: color:#000; transition:alllinear0.1s; font-size:12px; background-color:#fff; } span { border-radius:100%; border:#fffsolid width: height: display:inline-block; background-color:#fff; transition:allease-in-out0.2s; } &:hoverspan { width:10px; height:10px; background-color:#fff; cursor:pointer; } } } } /style 如果文章对你有帮助的话欢迎 「关注+点赞+收藏」 阅读原文

上一篇:2024-10-24_霜降海报合集,把柿子装满整个秋天 下一篇:2024-12-19_来战!「豆包 MarsCode 算法竞技赛」第二期开赛,丰厚奖金等你来拿

TAG标签:

18
网站开发网络凭借多年的网站建设经验,坚持以“帮助中小企业实现网络营销化”为宗旨,累计为4000多家客户提供品质建站服务,得到了客户的一致好评。如果您有网站建设网站改版域名注册主机空间手机网站建设网站备案等方面的需求...
请立即点击咨询我们或拨打咨询热线:13245491521 13245491521 ,我们会详细为你一一解答你心中的疑难。
项目经理在线

相关阅读 更多>>

猜您喜欢更多>>

我们已经准备好了,你呢?
2022我们与您携手共赢,为您的企业营销保驾护航!

不达标就退款

高性价比建站

免费网站代备案

1对1原创设计服务

7×24小时售后支持

 

全国免费咨询:

13245491521

业务咨询:13245491521 / 13245491521

节假值班:13245491521()

联系地址:

Copyright © 2019-2025      ICP备案:沪ICP备19027192号-6 法律顾问:律师XXX支持

在线
客服

技术在线服务时间:9:00-20:00

在网站开发,您对接的直接是技术员,而非客服传话!

电话
咨询

13245491521
7*24小时客服热线

13245491521
项目经理手机

微信
咨询

加微信获取报价