js实现拖动缓动效果

作者:专注前端30年 时间:2024-04-29 13:44:28 

话不多说,先上效果,一个体验非常好的拖拽缓动的效果,让页面提升一个档次。

js实现拖动缓动效果

这个效果看似很简单,到也困惑了很长时间,为什么别人写出来的拖拽体验为什么这么好?
直到我自己实现了以后,才发现,原来我想的实现方式不对。接下来,我通过简短的几句话,来提供这个功能的实现思路。

首先,我们要明白,我们鼠标拖拽是在一个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>

来源:https://blog.csdn.net/qq_30100043/article/details/103927870

标签:js,拖动,缓动
0
投稿

猜你喜欢

  • Python全栈之文件函数和函数参数

    2023-05-11 02:28:21
  • MySQL 删除大表的性能问题解决方案

    2024-01-18 22:20:31
  • 一篇文章带你了解Python之Selenium自动化爬虫

    2023-12-15 14:30:53
  • PyQtGraph在pyqt中的应用及安装过程

    2022-02-27 17:00:14
  • 使用Microsoft SQL Server 2000全文搜索功能构建Web搜索应用程序

    2008-09-29 12:32:00
  • 理解Proxy及使用Proxy实现vue数据双向绑定操作

    2024-04-26 17:41:43
  • 解决使用Pandas 读取超过65536行的Excel文件问题

    2022-03-28 09:17:29
  • Javascript: 为<input>设置readOnly属性问题,希望大家以后要小心

    2009-07-23 20:24:00
  • Perl中的正则表达式介绍

    2023-08-11 21:14:25
  • python简单实现最大似然估计&scipy库的使用详解

    2022-11-03 23:45:01
  • 浅谈Node.js之异步流控制

    2024-05-02 17:36:23
  • python中的bisect模块与二分查找详情

    2021-07-23 05:17:56
  • python中sys.argv参数用法实例分析

    2021-09-19 20:29:30
  • jupyter notebook的安装与使用详解

    2022-09-11 23:35:25
  • python 读取数据库并绘图的实例

    2024-01-27 10:43:33
  • .NET之生成数据库全流程实现

    2024-01-16 05:08:48
  • 基于go微服务效率工具goctl深度解析

    2023-07-12 03:57:13
  • Asp+ajax打造无刷新新闻评论系统

    2008-02-12 15:43:00
  • 如何go语言比较两个对象是否深度相同

    2024-02-18 21:21:58
  • php在linux环境中如何使用redis详解

    2023-06-14 23:38:30
  • asp之家 网络编程 m.aspxhome.com