话不多说,先上效果,一个体验非常好的拖拽缓动的效果,让页面提升一个档次。
这个效果看似很简单,到也困惑了很长时间,为什么别人写出来的拖拽体验为什么这么好?
直到我自己实现了以后,才发现,原来我想的实现方式不对。接下来,我通过简短的几句话,来提供这个功能的实现思路。
首先,我们要明白,我们鼠标拖拽是在一个2d平面上拖拽
2d平面只有x轴和y轴,而且获取的拖拽值也是基于平面的像素获取的。所以,我们第一步,先通过鼠标事件来获取到当前的拖拽的长度像素。
首先,绑定鼠标按下事件,来获取到鼠标基于浏览器窗口左上角的xy平面二维坐标。
然后,绑定move事件,在move事件回调内获取到鼠标拖拽的坐标,和按下坐标相减,求出拖拽的距离。
然后,我们需要通过一定比例,将拖拽的像素转换为旋转角度
我这里设置的比例是,
鼠标横向拖拽10像素,那模型沿3d的Y轴坐标就旋转5度,
鼠标纵向拖拽10像素,模型沿3d世界的X轴坐标旋转1度,并且还设置了范围,即沿x轴旋转再-45度到45度之间
function onDocumentMouseMove(event) { mouseX = event.clientX; mouseY = event.clientY; targetRotationX = targetRotationOnMouseDownX + (mouseX - mouseXOnMouseDownX) * 0.5; targetRotationY = Math.min(Math.max((targetRotationOnMouseDownY - (mouseY - mouseXOnMouseDownY) * 0.1), -45), 45); //拖拽后的目标位置 }
上面获取到目标角度,重点来了,如何实现惰性旋转呢?
通过上面思路,我们知道了目标角度,那么直接设置目标角度,肯定就没有这种想要的效果了,那么如何实现这种惰性效果呢?
接下来,我们需要一个专门实现动画的requestAnimationFrame方法,这个方法是闲时运行,最大根据性能能够达到60帧每秒,有好多小伙伴感觉一直递归运行会不会卡顿,或者影响性能。那是你多虑了,这个方法会根据当前页面性能进行减帧,保证页面流畅运行。
我们有了这个以后,然后做什么呢,就是用来实现缓动,在每一帧里面,获取到目标角度和当前角度的角度差,然后每一次只选择总进度的百分之10 ,然后你会发现选择离目标角度越近,越慢,体验效果也是非常的棒。
而且在运行中,角度也会无限制的接近目标角度,当前demo是通过css3d来实现的:
function animate() { requestAnimationFrame(animate); rotateY += (targetRotationX - rotateY) * 0.1; rotateX += (targetRotationY - rotateX) * 0.1; box.style.transform = 'rotateY(' + rotateY + 'deg)'; item.style.transform = 'rotateX(' + rotateX + 'deg)'; }
案例全部代码
<!DOCTYPE html> <html lang="zh"> <head> <meta charset="UTF-8"> <title>css3d翻转</title> <style> * { padding: 0; margin: 0; } body { display: flex; justify-content: center; align-items: center; height: 100vh; overflow: hidden; perspective: 1000px; } .item { width: 50vw; height: 50vh; transform: rotateX(-50deg); perspective: 5000px; transform-style: preserve-3d; } .box { background: #abb9c5; width: 100%; height: 100%; transform-style: preserve-3d; position: relative; } .font, .back { position: absolute; top: 0; left: 0; width: 100%; height: 100%; text-align: center; line-height: 50vh; background: #4cae4c; backface-visibility: hidden; } .back { background: #62ebff; transform: rotateY(180deg); } </style> </head> <body> <!--item 可以触发翻转的区域--> <div class="item"> <!--box 可以翻转的容器--> <div class="box"> <!--font 默认显示的正面--> <div class="font">正面</div> <!--back 背面--> <div class="back">背面</div> </div> </div> </body> <script> var targetRotationX = 0; var targetRotationY = 0; var targetRotationOnMouseDownX = 0; var targetRotationOnMouseDownY = 0; var mouseX = 0; var mouseY = 0; var mouseXOnMouseDownX = 0; var mouseXOnMouseDownY = 0; var box = document.querySelector('.box'); var item = document.querySelector('.item'); var rotateY = 0; var rotateX = 0; init(); animate(); function init() { // EVENTS document.addEventListener('mousedown', onDocumentMouseDown, false); document.addEventListener('touchstart', onDocumentTouchStart, false); document.addEventListener('touchmove', onDocumentTouchMove, false); } function onDocumentMouseDown(event) { event.preventDefault(); document.addEventListener('mousemove', onDocumentMouseMove, false); document.addEventListener('mouseup', onDocumentMouseUp, false); mouseXOnMouseDownX = event.clientX; mouseXOnMouseDownY = event.clientY; targetRotationOnMouseDownX = targetRotationX; targetRotationOnMouseDownY = targetRotationY; } function onDocumentMouseMove(event) { mouseX = event.clientX; mouseY = event.clientY; targetRotationX = targetRotationOnMouseDownX + (mouseX - mouseXOnMouseDownX) * 0.5; targetRotationY = Math.min(Math.max((targetRotationOnMouseDownY - (mouseY - mouseXOnMouseDownY) * 0.1), -45), 45); //拖拽后的目标位置 } function onDocumentMouseUp() { document.removeEventListener('mousemove', onDocumentMouseMove, false); document.removeEventListener('mouseup', onDocumentMouseUp, false); } function onDocumentTouchStart(event) { event.preventDefault(); if (event.touches.length === 1) { mouseXOnMouseDownX = event.touches[0].pageX; mouseXOnMouseDownY = event.touches[0].pageY; targetRotationOnMouseDownX = targetRotationX; targetRotationOnMouseDownY = targetRotationY; } } function onDocumentTouchMove(event) { event.preventDefault(); if (event.touches.length === 1) { mouseX = event.touches[0].pageX; mouseY = event.touches[0].pageY; targetRotationX = targetRotationOnMouseDownX + (mouseX - mouseXOnMouseDownX) * 0.5; targetRotationY = Math.min(Math.max((targetRotationOnMouseDownY - (mouseY - mouseXOnMouseDownY) * 0.1), -45), 45); //拖拽后的目标位置 } } function animate() { requestAnimationFrame(animate); rotateY += (targetRotationX - rotateY) * 0.1; rotateX += (targetRotationY - rotateX) * 0.1; box.style.transform = 'rotateY(' + rotateY + 'deg)'; item.style.transform = 'rotateX(' + rotateX + 'deg)'; } </script> </html>
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持。
免责声明:本站资源来自互联网收集,仅供用于学习和交流,请遵循相关法律法规,本站一切资源不代表本站立场,如有侵权、后门、不妥请联系本站删除!
《魔兽世界》大逃杀!60人新游玩模式《强袭风暴》3月21日上线
暴雪近日发布了《魔兽世界》10.2.6 更新内容,新游玩模式《强袭风暴》即将于3月21 日在亚服上线,届时玩家将前往阿拉希高地展开一场 60 人大逃杀对战。
艾泽拉斯的冒险者已经征服了艾泽拉斯的大地及遥远的彼岸。他们在对抗世界上最致命的敌人时展现出过人的手腕,并且成功阻止终结宇宙等级的威胁。当他们在为即将于《魔兽世界》资料片《地心之战》中来袭的萨拉塔斯势力做战斗准备时,他们还需要在熟悉的阿拉希高地面对一个全新的敌人──那就是彼此。在《巨龙崛起》10.2.6 更新的《强袭风暴》中,玩家将会进入一个全新的海盗主题大逃杀式限时活动,其中包含极高的风险和史诗级的奖励。
《强袭风暴》不是普通的战场,作为一个独立于主游戏之外的活动,玩家可以用大逃杀的风格来体验《魔兽世界》,不分职业、不分装备(除了你在赛局中捡到的),光是技巧和战略的强弱之分就能决定出谁才是能坚持到最后的赢家。本次活动将会开放单人和双人模式,玩家在加入海盗主题的预赛大厅区域前,可以从强袭风暴角色画面新增好友。游玩游戏将可以累计名望轨迹,《巨龙崛起》和《魔兽世界:巫妖王之怒 经典版》的玩家都可以获得奖励。
更新日志
- 小骆驼-《草原狼2(蓝光CD)》[原抓WAV+CUE]
- 群星《欢迎来到我身边 电影原声专辑》[320K/MP3][105.02MB]
- 群星《欢迎来到我身边 电影原声专辑》[FLAC/分轨][480.9MB]
- 雷婷《梦里蓝天HQⅡ》 2023头版限量编号低速原抓[WAV+CUE][463M]
- 群星《2024好听新歌42》AI调整音效【WAV分轨】
- 王思雨-《思念陪着鸿雁飞》WAV
- 王思雨《喜马拉雅HQ》头版限量编号[WAV+CUE]
- 李健《无时无刻》[WAV+CUE][590M]
- 陈奕迅《酝酿》[WAV分轨][502M]
- 卓依婷《化蝶》2CD[WAV+CUE][1.1G]
- 群星《吉他王(黑胶CD)》[WAV+CUE]
- 齐秦《穿乐(穿越)》[WAV+CUE]
- 发烧珍品《数位CD音响测试-动向效果(九)》【WAV+CUE】
- 邝美云《邝美云精装歌集》[DSF][1.6G]
- 吕方《爱一回伤一回》[WAV+CUE][454M]