记录--怎么写一个可以鼠标控制旋转的div?
这里给大家分享我在网上总结出来的一些知识,希望对大家有所帮助
说在前面
鼠标控制元素旋转在现在也是一个很常见的功能,让我们从实现div元素的旋转控制开始来了解元素旋转的具体原理和实现方法吧。
效果展示
体验地址
实现步骤
画一个div
首先我们需要先画一个div,并在它上方加上旋转图标,我们可以通过这个图标来对div进行旋转,具体代码如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | <!DOCTYPE html> <html lang= "en" > <head> <meta charset= "UTF-8" /> <meta http-equiv= "X-UA-Compatible" content= "IE=edge" /> <meta name= "viewport" content= "width=device-width, initial-scale=1.0" /> <title>Document</title> <link rel= "stylesheet" href= "./index.css" /> </head> <body> <div class = "container" > <div class = "rotate-div" > <div class = "rotate-icon" >↻</div> </div> </div> </body> <script src= "./index.js" ></script> </html> |
加点css
将div设置为红色背景的方块,调整旋转图标的位置,具体代码如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 | .container { display: flex; justify-content: center; align-items: center; height: 100vh; } .rotate-div { position: relative; width: 200px; height: 200px; background-color: red; transform-origin: center center; } .rotate-icon { position: absolute; top: -50px; /* 调整图标的位置 */ left: 50%; transform: translateX(-50%); font-size: 20px; cursor: pointer; } |
效果如下:
完成鼠标拖拽旋转功能
鼠标在旋转图标按下的时候,我们需要监听鼠标移动事件,根据鼠标移动位置和初始点击位置的相对角度来计算方块旋转的角度。
1、获取方块和旋转图标元素对象
首先我们要先获取方块和旋转图标元素对象,便于后续事件监听和元素操作。
1 2 | const rotateDiv = document.querySelector( ".rotate-div" ); const rotateIcon = document.querySelector( ".rotate-icon" ); |
返回值类型:TextRectangle对象,每个矩形具有四个整数性质( 上, 右 , 下,和左 )表示的坐标的矩形,以像素为单位。
rectObject.top:元素上边到视窗上边的距离;
rectObject.right:元素右边到视窗左边的距离;
rectObject.bottom:元素下边到视窗上边的距离;
rectObject.left:元素左边到视窗左边的距离;
我们记录下方块的初始中心点:
1 2 | const centerX = rect.left + rect.width / 2; const centerY = rect.top + rect.height / 2; |
(2)计算旋转角度
Math.atan2()
Math.atan2()
返回从原点 (0,0) 到 (x,y) 点的线段与 x 轴正方向之间的平面角度 (弧度值),也就是 Math.atan2(y,x)
1 | Math.atan2(y, x) |
atan2
方法返回一个 -pi 到 pi 之间的数值,表示点 (x, y) 对应的偏移角度。这是一个逆时针角度,以弧度为单位,正 X 轴和点 (x, y) 与原点连线 之间。注意此函数接受的参数:先传递 y 坐标,然后是 x 坐标。
atan2
接受单独的 x 和 y 参数,而 atan
接受两个参数的比值。
由于 atan2
是 Math
的静态方法,所以应该像这样使用:Math.atan2()
,而不是作为你创建的 Math
实例的方法。
1 2 3 | function getAngle(centerX, centerY, mouseX, mouseY) { return Math.atan2(mouseY - centerY, mouseX - centerX) * (180 / Math.PI); } |
使用当前鼠标位置相对角度减去鼠标初始点击点的相对角度即可得到鼠标旋转的角度。
1 2 | startingMouseAngle = getAngle(centerX, centerY, event .clientX, event .clientY); const deltaMouseAngle = currentMouseAngle - startingMouseAngle; |
(3)旋转角度简化
方块的最大旋转角度为360度,所以我们对角度进行取模,保持旋转角度在360度以内即可。
1 2 3 4 5 6 7 | function normalizeRotation(rotation) { if (rotation >= 0) { return rotation % 360; } else { return (rotation % 360) + 360; } } |
(4)给方块设置旋转角度
1 | rotateDiv.style.transform = `rotate(${newRotation}deg)`; |
3、移除旋转逻辑
鼠标抬起的时候我们应该将旋转逻辑给移除,及将鼠标移动和抬起事件移除。
1 2 3 4 | function stopSpin() { window.removeEventListener( "mousemove" , spin); window.removeEventListener( "mouseup" , stopSpin); } |
4、完整代码
完整的JavaScrip代码如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 | const rotateDiv = document.querySelector( ".rotate-div" ); const rotateIcon = document.querySelector( ".rotate-icon" ); let startingMouseAngle = 0; let startingRotation = 0; rotateIcon.addEventListener( "selectstart" , function ( event ) { event .preventDefault(); }); rotateIcon.addEventListener( "mousedown" , function ( event ) { const rect = rotateDiv.getBoundingClientRect(); const centerX = rect.left + rect.width / 2; const centerY = rect.top + rect.height / 2; startingMouseAngle = getAngle(centerX, centerY, event .clientX, event .clientY); startingRotation = getCurrentRotation(); window.addEventListener( "mousemove" , spin); window.addEventListener( "mouseup" , stopSpin); }); function stopSpin() { window.removeEventListener( "mousemove" , spin); window.removeEventListener( "mouseup" , stopSpin); } function spin( event ) { const rect = rotateDiv.getBoundingClientRect(); const centerX = rect.left + rect.width / 2; const centerY = rect.top + rect.height / 2; const currentMouseAngle = getAngle( centerX, centerY, event .clientX, event .clientY ); const deltaMouseAngle = currentMouseAngle - startingMouseAngle; let newRotation = startingRotation + deltaMouseAngle; newRotation = normalizeRotation(newRotation); rotateDiv.style.transform = `rotate(${newRotation}deg)`; } function normalizeRotation(rotation) { if (rotation >= 0) { return rotation % 360; } else { return (rotation % 360) + 360; } } function getAngle(centerX, centerY, mouseX, mouseY) { return Math.atan2(mouseY - centerY, mouseX - centerX) * (180 / Math.PI); } function getCurrentRotation() { const transformStyle = window .getComputedStyle(rotateDiv) .getPropertyValue( "transform" ); const matrix = new DOMMatrixReadOnly(transformStyle); const angle = Math.acos(matrix.a) * (180 / Math.PI); return matrix.b < 0 ? -angle : angle; } |
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 全程不用写代码,我用AI程序员写了一个飞机大战
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· 记一次.NET内存居高不下排查解决与启示
· DeepSeek 开源周回顾「GitHub 热点速览」
· 白话解读 Dapr 1.15:你的「微服务管家」又秀新绝活了
2022-10-17 记录--图解 Vue 响应式原理