网络编程
位置:首页>> 网络编程>> JavaScript>> js实现拖动缓动效果

js实现拖动缓动效果

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

标签:js,拖动,缓动

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

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

0
投稿

猜你喜欢

  • 本篇博客会介绍如何使用python在excel和csv里实现vlookup函数的功能,首先需要简单了解一下python如何操作excel1.
  • 前言上篇文章记录了2种分割验证码的方法,此外还有一种叫做”滴水算法”(Drop Fall Algorithm)的方法,但本人智商原因看这个算
  • pandas 将字符串映射为数字在有些数据集中,有些数据变量用字符串表示,但为了方便处理,往往想转换为好处理的格式,这时候不一定要用one
  • 每次安装总是有些不同,这次用这种方式尝试一下,也记录一下。1、首先需要去下载rpm包:镜像地址:http://mysql.mirrors.p
  • 获取操作系统的当前运行状态和负载情况,是一个系统管理员的基本技能,因为这对我们日常排查故障,定位问题有着非常紧密的联系,比如查看当前系统的基
  • 如何用SQL 建表?    如下:CREATE TABLE statement 
  • 在多线程的使用时,为了线程的顺利进行,我们会使用函数来对某个线程进行暂停运行。在多线程中有两个函数可以实现sleep和wait,不过它们在使
  • 本文实例为大家分享了python绘制折线图和条形图的具体代码,供大家参考,具体内容如下最近开始写小论文啦,中间不免要作各种各样的图,学习后自
  • 大家在使用python的过程中,应该在敲代码的时候经常遇到str内置函数,为了防止大家搞混,本文整理归纳了str内置函数。1字符串查找类:f
  • 一、简介       XML(eXtensible Markup Languag
  • 本文讲述了Oracle修改表空间大小的方法。分享给大家供大家参考,具体如下:1)查看各表空间分配情况SQL> select table
  • 本文实例为大家分享了JS中FormData类实现文件上传的具体代码,供大家参考,具体内容如下上篇文章讲到了FormReader类实现文件上传
  • k-近邻算法概述简单地说,k近邻算法采用测量不同特征值之间的距离方法进行分类。k-近邻算法优点:精度高、对异常值不敏感、无数据输入假定。缺点
  • 1、流程控制流程控制在编程语言中是最伟大的发明了,因为有了它,你可以通过很简单的流程描述来表达很复杂的逻辑。流程控制包含分三大类:条件判断,
  • 标准的SQL模式匹配SQL的模式匹配允许你使用“_”匹配任何单个字符,而“%”匹配任意数目字符(包括零个字符)。在 MySQL中,SQL的模
  • 核心提示:本文针对mysql-noinstall版本,也就是解压缩版的安装配置应用做了个总结,这些操作都是平时很常用的操作。文章中不对mys
  • 在应用系统中,尤其在联机事务处理系统中,对数据查询及处理速度已成为衡量应用系统成败的标准。而采用索引来加快数据处理速度也成为广大数据库用户所
  • 什么是索引拿汉语字典的目录页(索引)打比方:正如汉语字典中的汉字按页存放一样,SQL Server中的数据记录也是按页存放的,每页容量一般为
  • Vue.js 的核心是一个允许采用简洁的模板语法来声明式的将数据渲染进 DOM,也就是将模板中的文本数据写进DOM中,使用  {{
  • 在写sql的时候,由于有部分语句别名不能调用,百度了一下原因,原来是由于别名机制不同引起的。为了避免下一次再犯同样的错误,今天把网上找到资料
手机版 网络编程 asp之家 www.aspxhome.com